Projection of 2D histogram to one axis with matplotlib - python

I have the following code where I produced a 2d histogram with matplotlib of a function f of two variables, namely x and y. x goes from 0 to 7 and y from 0 to np.pi/2. Below you can find related code. I would like to project onto the x-axis so that I have the function f only as function of x: f(x). How can I do that? I would like to plot it as a 1d histogram and possibly save the values in a list.
from matplotlib import cm
plt.figure(figsize=(20,16))
h = plt.hist2d(x, y, bins=[110,110],cmin=0.000001,cmap='jet')
plt.colorbar(h[3])
plt.title("SW Distribution for Pion Zero",fontsize=22)
plt.xlabel("Momentum (GeV/c)",fontsize=22)
plt.ylabel("Angle (rad)",fontsize=22)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.show()

Related

How to plot 2d array in a colored 2d-colored-histogram in Python?

I have a list of shape 31x4240 which looks like
this
Each row contains 4240 random values. My objective is to create a colored 2d-histogram, where the distribution of the 4240 random values is represented in a colored bar parallel to the y-axis, similar to this:
2d-histogram for 2d-array
I have already seen mentions of using hist2d like this:
x = np.random.normal(size=50000)
y = x * 3 + np.random.normal(size=50000)
plt.hist2d(x, y, bins=(50, 50), cmap=plt.cm.jet)
plt.show()
But i dont really see how i can use this in my scenario, since x and y are both 1D and my array is 2D
Does anyone have a clue?
You can try imshow:
im = plt.imshow(masked_array, cmap='jet', aspect='auto')

Python - 3D Plotting, horizontal lines missing and incorrect gradients showing

I am new to 3D surface plots and I am trying to make a 3D plot of temperature as a function of distance and time using the following:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
t = np.arange(0,60,1)
z = np.arange(5,85,5)
fig=plt.figure(1)
ax = fig.gca(projection='3d')
X, Y = np.meshgrid(z, t)
surface=ax.plot_surface(X,Y,T1, linewidth=1,cmap=cm.coolwarm, antialiased=False)
fig.colorbar(surface, shrink=0.5, aspect=5)
ax.view_init(ax.elev, ax.azim+90)
ax.set_title("Temperature Distribution 1")
ax.set_xlabel('z (cm)')
ax.set_ylabel('Time (min)')
ax.set_zlabel('Temperature ($^\circ$C)')
ax.set_xticks(np.arange(0,80, 15))
plt.savefig("3D_1.png",format='png',dpi=1000,bbox_inches='tight')
plt.show()
T1 is 2D data. This produces the following:
There is only 1 horizontal line showing at around 60cm, however I would like a horiztonal line every 5cm (data was taken along every 5cm). It seems there is only 2 sections to the plot along the distance axis. The colour gradients are showing in large blocks instead of showing as a function of temperature all along the length.
e.g. for time between 50-60mins from distance 0~40cm, the temperature goes from ~180 to ~20 degrees, but the colour of that block is dark red all the way along it, instead it should start as dark red and reduce down to blue. How do I get the temperature to show the correct gradient along the whole length axis.
Also the temperature legend is in %, instead of the temperature values in degrees, how do I fix this?
Looking at the documentation of surface we find
The rstride and cstride kwargs set the stride used to sample the input data to generate the graph. If 1k by 1k arrays are passed in, the default values for the strides will result in a 100x100 grid being plotted. Defaults to 10.
Thus, using
surface=ax.plot_surface(X,Y,T1, rstride=8, cstride=8)
you get
While using
surface=ax.plot_surface(X,Y,T1, rstride=5, cstride=1)
you get
This is an example how to create reproducible data for this case:
t = np.arange(0,60,1)
z = z=np.arange(5,85,5)
f = lambda z, t, z0, t0, sz, st: 180.*np.exp(-(z-z0)**2/sz**2 -(t-t0)**2/st**2)
X, Y = np.meshgrid(z, t)
T1 =f(X,Y,-20.,56, 40.,30.)

Adding a 4th variable to a 3D plot in Python

I have 3 different parameters X,Y and Z over a range of values, and for each combination of these a certain value of V. To make it clearer, the data would look something like this.
X Y Z V
1 1 2 10
1 2 3 15
etc...
I'd like to visualize the data with a surface/contour plot, using V as a colour to see its value at that point, but I do not see how to add my custom colouring scheme into the mix using Python. Any idea on how to do this (or is this visualization outright silly)?
Thanks a lot!
Matplotlib allows one to pass the facecolors as an argument to e.g.
ax.plot_surface.
That would imply then that you would have to perform 2D interpolation on your
current array of colors, because you currently only have the colors in the
corners of the rectangular faces (you did mention that you have a rectilinear
grid).
You could use
scipy.interpolate.interp2d
for that, but as you see from the documentation, it is suggested to use
scipy.interpolate.RectBivariateSpline.
To give you a simple example:
import numpy as np
y,x = np.mgrid[1:10:10j, 1:10:10j] # returns 2D arrays
# You have 1D arrays that would make a rectangular grid if properly reshaped.
y,x = y.ravel(), x.ravel() # so let's convert to 1D arrays
z = x*(x-y)
colors = np.cos(x**2) - np.sin(y)**2
Now I have a similar dataset as you (one-dimensional arrays for x, y, z and
colors). Remark that the colors are defined for
each point (x,y). But when you want to plot with plot_surface, you'll
generate rectangular patches, of which the corners are given by those points.
So, on to interpolation then:
from scipy.interpolate import RectBivariateSpline
# from scipy.interpolate import interp2d # could 've used this too, but docs suggest the faster RectBivariateSpline
# Define the points at the centers of the faces:
y_coords, x_coords = np.unique(y), np.unique(x)
y_centers, x_centers = [ arr[:-1] + np.diff(arr)/2 for arr in (y_coords, x_coords)]
# Convert back to a 2D grid, required for plot_surface:
Y = y.reshape(y_coords.size, -1)
X = x.reshape(-1, x_coords.size)
Z = z.reshape(X.shape)
C = colors.reshape(X.shape)
#Normalize the colors to fit in the range 0-1, ready for using in the colormap:
C -= C.min()
C /= C.max()
interp_func = RectBivariateSpline(x_coords, y_coords, C.T, kx=1, ky=1) # the kx, ky define the order of interpolation. Keep it simple, use linear interpolation.
In this last step, you could also have used interp2d (with kind='linear'
replacing the kx=1, ky=1). But since the docs suggest to use the faster
RectBivariateSpline...
Now you're ready to plot it:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r = ax.plot_surface(X,Y,Z,
facecolors=cm.hot(interp_func(x_centers, y_centers).T),
rstride=1, cstride=1) # only added because of this very limited dataset
As you can see, the colors on the faces have nothing to do anymore with the height of the dataset.
Note that you could have thought simply passing the 2D array C to facecolors would work, and matplotlib would not have complained. However, the result isn't accurate then, because matplotlib will use only a subset of C for the facecolors (it seems to ignore the last column and last row of C). It is equivalent to using only the color defined by one coordinate (e.g. the top-left) over the entire patch.
An easier method would have been to let matplotlib do the interpolation and obtain the facecolors and then pass those in to the real plot:
r = ax.plot_surface(X,Y,C, cmap='hot') # first plot the 2nd dataset, i.e. the colors
fc = r.get_facecolors()
ax.clear()
ax.plot_surface(X, Y, Z, facecolors=fc)
However, that won't work in releases <= 1.4.1 due to this recently submitted bug.
It really depends on how you plan on plotting this data. I like to plot graphs with gnuplot: it's easy, free and intuitive. To plot your example with gnuplot you'd have to print those line into a file (with only those four columns) and plot using a code like the following
reset
set terminal png
set output "out.png"
splot "file.txt" using 1:2:3:4 with lines palette
Assuming that you save your data into the file file.txt. splot stands for surface plot. Of course, this is a minimum example.
Alternatively you can use matplotlib, but that is not, in my opinion, as intuitive. Although it has the advantage of centering all the processing in python.

Python - Line colour of 3D parametric curve

I have 2 lists tab_x (containe the values of x) and tab_z (containe the values of z) which have the same length and a value of y.
I want to plot a 3D curve which is colored by the value of z. I know it's can be plotted as a 2D plot but I want to plot a few of these plot with different values of y to compare so I need it to be 3D.
My tab_z also containe negatives values
I've found the code to color the curve by time (index) in this question but I don't know how to transforme this code to get it work in my case.
Thanks for the help.
I add my code to be more specific:
fig8 = plt.figure()
ax8 = fig8.gca(projection = '3d')
tab_y=[]
for i in range (0,len(tab_x)):
tab_y.append(y)
ax8.plot(tab_x, tab_y, tab_z)
I have this for now
I've tried this code
for i in range (0,len(tab_t)):
ax8.plot(tab_x[i:i+2], tab_y[i:i+2], tab_z[i:i+2],color=plt.cm.rainbow(255*tab_z[i]/max(tab_z)))
A total failure:
Your second attempt almost has it. The only change is that the input to the colormap cm.jet() needs to be on the range of 0 to 1. You can scale your z values to fit this range with Normalize.
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import colors
fig = plt.figure()
ax = fig.gca(projection='3d')
N = 100
y = np.ones((N,1))
x = np.arange(1,N + 1)
z = 5*np.sin(x/5.)
cn = colors.Normalize(min(z), max(z)) # creates a Normalize object for these z values
for i in xrange(N-1):
ax.plot(x[i:i+2], y[i:i+2], z[i:i+2], color=plt.cm.jet(cn(z[i])))
plt.show()

plotting 3d histogram/barplot in python matplotlib

I have an Nx3 matrix in scipy/numpy and I'd like to make a 3 dimensional bar graph out of it, where the X and Y axes are determined by the values of first and second columns of the matrix, the height of each bar is the third column in the matrix, and the number of bars is determined by N.
In other words, if "data" is the matrix then:
data[:, 0] # values of X-axis
data[:, 1] # values of Y-axis
data[:, 2] # values of each Z-axis bar
and there should be one bar for each len(data)
How can I do this in Matplotlib?
Secondly, as a variant of this, how can I do the same thing, but this time histogram the bars into N bins in each X, Y, Z dimension? I.e. instead of a bar for each point, just histogram the data into those bins in every dimension, and plot a bar for each bin.
thanks very much for your help.
Here is one example of a 3D bar plot.
Here is another.
Numpy has a function called histogram2d to do the rectangular binning you want.
I had a little of a hard time shaping the 'heights' of my data properly from the examples, but finally got it to work with the following code. Here, Z is a 3 dimensional array with all of my data, and x and rval are basically the 2-d indices corresponding to the datapoints.
xs = np.arange(biopsy_num)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for y in (np.arange(r_sweep)):
z = Z[:,y]
ax.bar(xs, z, zs=y, zdir='y', alpha=0.8)
ax.set_xlabel('biopsies')
ax.set_ylabel('radius of biopsy')
ax.set_zlabel('Shannon Index')
plt.show()

Categories

Resources