3D Density visualisation with matplotlib - matplotlib

I am trying to plot a 3D column with associated density.
Specifically, I have a .txt file with 4 separate columns x, y, z, density. The first 3 columns are the cartesian coordinates of the column, density a list of density values associated with each cross-section, at height z, of the column.
I can plot the column with a colormap as follows
x=np.linspace(-1, 1, 100)
z=np.linspace(-20, 5, 50)
Xc, Zc=np.meshgrid(x, z)
Yc = np.sqrt(1-Xc**2)
# Draw parameters
rstride = 1
cstride = 1
surf1 = ax.plot_surface(Xc, Yc, Zc, alpha=1., rstride=rstride, cstride=cstride,antialiased=False, cmap=cm.coolwarm,linewidth=0)
surf2 = ax.plot_surface(Xc, -Yc, Zc, alpha=1., rstride=rstride, cstride=cstride, antialiased=False, cmap=cm.coolwarm,linewidth=0)
and I can associate a colormap to z
fig.colorbar(surf1, shrink=0.5, aspect=5)
I would like to associate the colormap to the values in the fourth column, while maintaining the plotted dimensions of the cylinder constant.
I would appreciate any help on the matter.
Thanks.

Related

Matplotlib - Correlation plots with different range of numbers but on same scale

I would like to have a 2 by 3 figure with 6 correlation plots, sharing the same scale, even when the values in the plots have different ranges. Below you can see what I have so far.
In the first column, the values range from 0 to 1, with 1 on the diagonal, and close to 0 elsewhere. For the other two columns it holds for the top row that the values range from 0 to 1, whereas the values in the bottom row range from -1 and 1. The difference between the second and third column is that the values in the second column are around 0.3 (and -0.3) and the values in the third column are around 0.7 (and -0.7).
As you can see, several things seem to be going incorrect. First of all, although I want them all to be plotted according to the same color scale, with dark blue being -1 and yellow being 1, this is clearly not the case. If this would hold, we would have bright blue/greenish in the first column. What could I do to indicate the range for the colors? Next, how do I change the labels of the color scale on the right? I would like it to range from -1 to 1.
Below, you find my implementation.
fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(15,8))
idx_mixed = {False: 0, True: 1}
idx_rho = {0: 0, 0.3: 1, 0.7: 2}
for mixed in [False, True]:
for rho in [0, 0.3, 0.7]:
ax[idx_mixed[mixed]][idx_rho[rho]].matshow(results[mixed][rho])
ax[0][0].set_title("No correlation", pad=20, fontsize=14)
ax[0][1].set_title("Weakly correlated", pad=20, fontsize=14)
ax[0][2].set_title("Strongly correlated", pad=20, fontsize=14)
ax[0][0].set_ylabel("Positive correlations", fontsize = 14)
ax[1][0].set_ylabel("Mixed correlations", fontsize = 14)
fig.colorbar(mpl.cm.ScalarMappable(), ax=fig.get_axes())
You need to provide a norm= argument to matshow() so that the data is scaled to the range [-1, 1] rather than a range defined by the min and max value present in the data. See Colormap Normalization for more details.
cmap = 'viridis'
norm = matplotlib.colors.Normalize(vmin=-1, vmax=1)
fig, axs = plt.subplots(2,3)
for ax, d in zip(axs.flat, data):
m = ax.matshow(d, cmap=cmap, norm=norm)
fig.colorbar(m, ax=axs)

Multiple different kinds of plots on a single figure and save it to a video

I am trying to plot multiple different plots on a single matplotlib figure with in a for loop. At the moment it is all good in matlab as shown in the picture below and then am able to save the figure as a video frame. Here is a link of a sample video generated in matlab for 10 frames
In python, tried it as below
import matplotlib.pyplot as plt
for frame in range(FrameStart,FrameEnd):#loop1
# data generation code within a for loop for n frames from source video
array1 = np.zeros((200, 3800))
array2 = np.zeros((19,2))
array3 = np.zeros((60,60))
for i in range(len(array2)):#loop2
#generate data for arrays 1 to 3 from the frame data
#end loop2
plt.subplot(6,1,1)
plt.imshow(DataArray,cmap='gray')
plt.subplot(6, 1, 2)
plt.bar(data2D[:,0], data2D[:,1])
plt.subplot(2, 2, 3)
plt.contourf(mapData)
# for fourth plot, use array2[3] and array2[5], plot it as shown and keep the\is #plot without erasing for next frame
not sure how to do the 4th axes with line plots. This needs to be there (done using hold on for this axis in matlab) for the entire sequence of frames processing in the for loop while the other 3 axes needs to be erased and updated with new data for each frame in the movie. The contour plot needs to be square all the time with color bar on the side. At the end of each frame processing, once all the axes are updated, it needs to be saved as a frame of a movie. Again this is easily done in matlab, but not sure in python.
Any suggestions
thanks
I guess you need something like this format.
I have used comments # in code to answer your queries. Please check the snippet
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(6,6))
ax1=fig.add_subplot(311) #3rows 1 column 1st plot
ax2=fig.add_subplot(312) #3rows 1 column 2nd plot
ax3=fig.add_subplot(325) #3rows 2 column 5th plot
ax4=fig.add_subplot(326) #3rows 2 column 6th plot
plt.show()
To turn off ticks you can use plt.axis('off'). I dont know how to interpolate your format so left it blank . You can adjust your figsize based on your requirements.
import numpy as np
from numpy import random
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(6,6)) #First is width Second is height
ax1=fig.add_subplot(311)
ax2=fig.add_subplot(312)
ax3=fig.add_subplot(325)
ax4=fig.add_subplot(326)
#Bar Plot
langs = ['C', 'C++', 'Java', 'Python', 'PHP']
students = [23,17,35,29,12]
ax2.bar(langs,students)
#Contour Plot
xlist = np.linspace(-3.0, 3.0, 100)
ylist = np.linspace(-3.0, 3.0, 100)
X, Y = np.meshgrid(xlist, ylist)
Z = np.sqrt(X**2 + Y**2)
cp = ax3.contourf(X, Y, Z)
fig.colorbar(cp,ax=ax3) #Add a colorbar to a plot
#Multiple line plot
x = np.linspace(-1, 1, 50)
y1 = 2*x + 1
y2 = 2**x + 1
ax4.plot(x, y2)
ax4.plot(x, y1, color='red',linewidth=1.0)
plt.tight_layout() #Make sures plots dont overlap
plt.show()

Plot Frequency of Values of Multiple Columns

I want to create a pandas plot of the frequency of occurrences of values in two columns. The scatter plot is to contain a regression line. The result is a heat map-like plot with a regression line.
First, combine columns 'A' and 'B' into a unique value. In this case both columns are numeric so I'm using addition. Next use value_counts to create a frequency. Use pandas scatter plot to create the scatter/bubble/heatmap. Finally use numpy.polyfit to drop a regression line.
combined = (plotdf['A']*plotdf['B'].nunique()+plotdf['B']) # combine numeric values of columns A and B
vcounts = combined.value_counts() # get value counts of combined values
frequency = combined.map(vcounts) # lookup count for each row
plt = plotdf.plot(x='A',y='B',c=frequency,s=frequency,colormap='viridis',kind='scatter',figsize=(16,8),title='Frequency of A and B')
plt.set(xlabel='A',ylabel='B')
x = plotdf['A'].values
y = plotdf['B'].values
m, b = np.polyfit(x, y, 1) # requires numpy
plt.plot(x, m*x + b, 'r') # r is color red

Creating a grid of polar histograms (python)

I wish to create a sub plot that looks like the following picture,
it is supposed to contain 25 polar histograms, and I wish to add them to the plot one by one.
needs to be in python.
I already figured I need to use matplotlib but can't seem to figure it out completely.
thanks a lot!
You can create a grid of polar axes via projection='polar'.
hist creates a histogram, also when working with polar axes. Note that the x is in radians with a range of 2π. It works best when you give the bins explicitly as a linspace from 0 to 2π (or from -π to π, depending on the data). The third parameter of linspace should be one more than the number of bars that you'd want for the full circle.
About the exact parameters of axs[i][j].hist(x, bins=np.linspace(0, 2 * np.pi, np.random.randint(7, 30), endpoint=True), color='dodgerblue', ec='black'):
axs[i][j] draw on the jth subplot of the ith line
.hist create a histogram
x: the values that are put into bins
bins=: to enter the bins (either a fixed number between lowest and highest x or some explicit boundaries; default is 10 fixed boundaries)
np.random.randint(7, 30) a random whole number between 7 and 29
np.linspace(0, 2 * np.pi, n, endpoint=True) divide the range between 0 and 2π into n equal parts; endpoint=True makes boundaries at 0, at 2π and at n-2 positions in between; when endpoint=False there will be a boundary at 0, at n-1 positions in between but none at the end
color='dodgerblue': the color of the histogram bars will be blueish
ec='black': the edge color of the bars will be black
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots(5, 5, figsize=(8, 8),
subplot_kw=dict(projection='polar'))
for i in range(5):
for j in range(5):
x = np.random.uniform(0, 2 * np.pi, 50)
axs[i][j].hist(x, bins=np.linspace(0, 2 * np.pi, np.random.randint(7, 30)), color='dodgerblue', ec='black')
plt.tight_layout()
plt.show()

Matplotlib how to divide an histogram by a constant number

I would like to perform a personalized normalization on histograms on matplotlib. In particular I have two histograms and I would like to divide each of them by a given number (number of generated events).
I don't want to "normally" normalize it, because the "normal normalization" makes the area equal to 1. What I wish for is basically to divide the value of each bin by a given number N, so that if my histogram has 2 bins, one with 5 entries and one with 3, the resulting "normalized" (or "divided") histogram would have the first bin with 5/N entries and the second one with 3/N.
I searched far&wide and found nothing really helpful. Do you have any handy solution? This is my code, working with pandas:
num_bins = 128
list_1 = dataframe_1['E']
list_2 = dataframe_2['E']
fig, ax = plt.subplots()
ax.set_xlabel('Proton energy [MeV]')
ax.set_ylabel('Normalized frequency')
ax.set_title('Proton energy distribution')
n, bins, patches = ax.hist(list_1, num_bins, density=1, alpha=0.5, color='red', ec='red', label='label_1')
n, bins, patches = ax.hist(list_2, num_bins, density=1, alpha=0.5, color='blue', ec='blue', label='label_2')
plt.legend(loc='upper center', fontsize='x-large')
fig.savefig('NiceTitle.pdf')
plt.close('all')