I have a 3 data sets, X,Y,Z which are my axes and my data respectively. They are well defined, i.e.
len(X) = len(Y) = len(Z) = len(Z[i]) = N for i in range(0,N).
I would like to make a similar to a contourf plot (I already made it), but using discrete axes, like a "contour squares", where each square (x,y) has a color given by the Z value (which is a float value).
So far I'm using the contourf(X,Y,Z), but it makes some interpolations that I don't want, I need a better visualization with squares.
Does anyone knows how to do it?
Thanks
You should use matshow or imshow plotting functions.
An important argument here is the interpolation one.
Check this example from the matplotlib gallery to see some examples.
By using matshow(), keyword arguments are passed to imshow().
matshow() sets defaults for origin, interpolation (='nearest'), and aspect.
here is an example from my own work...
# level, time and conc are previously read from a file
X,Y=[level,time]
Z=conc.transpose() # Create the data to be plotted
cax = matshow(Z, origin='lower', vmin=0, vmax=500)
# I am telling all the Z values above 500 will have the same color
# in the plot (if vmin or vmax are not given, they are taken from
# the input’s minimum and maximum value respectively)
grid(True)
cbar = colorbar(cax)
...which returns this plot:
Related
So I am trying to create a 3D scatter plot of radar data, where each point is assigned an alpha value based on the amplitude of the corresponding pixel.
I have done this looping through all x,y,z points and building the scatter plot point by point assigning the alpha values on each iteration. But once the scatter plot is created it is very slow and unable to manipulate the graph without considerable time spent waiting for the plot to update.
Points is a normalised (0 to 1) array.
Here is a link to my data
Data
File preparation:
def normalise0to1(data):
normalised = (data - np.min(data)) / (np.max(data) - np.min(data))
return normalised
Data = np.loadtxt('filepath.txt')
points2D = normalise0to1(Data) #Is (101,400) size
points3D = np.reshape(points2D,(101,20,20)) #Is (101,20,20) size
And the first attempt at creating the 3D scatter plot:
def Scatter_Plot1(points3D):
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
for x in range(0,points3D[1]):
for y in range(0,points3D[2]):
for z in range(0,points3D[0]):
val = points3D[z,x,y]
ax.scatter(x, y, z, alpha=val,c='black',s=1)
plt.show()
This takes a long time to run and is very slow once created.
In 2D, I can do something like this. Bear in mind this is the same array as the 3D 'points' array, but the (20x20) has been flattened to 400. I have provided an image of the flattened array, you can see how it creates an image where intensity is scaled to the alpha value.
def Scatter_Plot2(points2D):
fig = plt.figure()
ax = fig.add_subplot()
x_=np.linspace(0,points2D.shape[1]-1,points2D.shape[1])
y_=np.linspace(0,points2D.shape[0]-1,points2D.shape[0])
x,y = np.meshgrid(x_,y_)
ax.scatter(x,y,alpha=points2D.flatten(),s=1,c='black')
plt.show()
This image is the flattened version of the 3D plot I want to create, where instead of 400 length, it would be (20x20) and overall the 3D shape is (101,20,20).
The problem comes when trying to assign the alpha to a 3D plot, in 2D it seems happy enough when I provide a flattened array to the alpha parameter.
I would like something like this, but whether that's possible is another question..
def Scatter_Plot3(points3D):
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
x_=np.linspace(0,points3D.shape[2]-1,points3D.shape[2])
y_=np.linspace(0,points3D.shape[1]-1,points3D.shape[1])
z_=np.linspace(0,points3D.shape[0]-1,points3D.shape[0])
x,y,z = np.meshgrid(x_,y_,z_)
ax.scatter(x,y,z,alpha=points3D,s=1,c='black')
plt.show()
Results in this image, which seems a bit random in terms of how the alpha is assigned. You would expect to see the dark horizontal lines as in the first picture. What I want may not be possible, I'm open to using another package, perhaps pyqtgraph or mayavi etc. But matplotlib would be preferable.
Thank you!
Edit:
I have achieved something similar to what I would like, though not exactly. I have used the c and cmap inputs. This isn't ideal as I am dealing with a 3D cube and viewing the centre is still difficult but it has correctly mapped a variation to the data. But it doesn't work when I use the alpha parameter.
Notice the 2 main horizontal bands and the dark bit in the centre which is hard to see.
What I need is the same mapping but rather opacity than colour.
c = (points2D.T.flatten())
ax.scatter(x,y,z,s=1,c=c,cmap='viridis_r')
I want to plot some impedance values and task and code are both simple. xhertz_df is a pandas dataframe and after conversion to a numpy array xhertz[0]is the real part, xhertz[1]the imaginary part and xhertz[3]represents the time between measurements.
def xhertz_plot(xhertz_df):
ax = plt.gca()
xhertz = xhertz_df.T.to_numpy()
ax.plot(xhertz[3], xhertz[0], 'green')
ax.plot(xhertz[3], xhertz[1], 'blue')
ax.scatter(xhertz[3], xhertz[0], cmap ='green')
ax.scatter(xhertz[3], xhertz[1], cmap ='blue')
ax.set_xlabel('Time Passed (in Minutes)')
plt.show()
I'm confused as to what can go wrong with this code as it seems so simple. Yet I get this result:
The upper line and points is a mix of blue and green even though it should be just green. The lower line that should be only blue has orange (?!) points. What is going on here?
Edit:
I found the problem: I used cmap instead of just c for the scatter plot. But to someone with expertise in both concepts: Why did I get the result shown above? E.g. where did the orange come from?
As stated in the docs for Axes.scatter:
A Colormap instance or registered colormap name. cmap is only used if c is an array of floats.
Since you did not provide a list of floats for the arg c, matplotlib ignored your cmap and instead used the first and second default colors (blue, then orange).
If you just want a single color, note the docs for the c argument:
If you wish to specify a single color for all points prefer the color keyword argument.
Alternatively, you can just use Axes.plot with o for the marker style, instead of scatter, e.g. ax.plot(x, y, 'o', color='green') or equivalently ax.plot(x, y, 'og'). This is more typical for simple plots; you can use - or o to explicitly set a line plot or marker plot.
Note that cmap is generally intended to be used if you want a different color for each point, like if you wanted to color the points to represent another dimension of data. In that case c would represent that third dimension of data, norm would scale the data, and cmap would be what colors are mapped to that data. See the scatter demo 2 from matplotlib for an example of how that argument is usually used.
I would like to plot contourf with (lat,depth,temp) and then have similar spacing as in the figure below (the temperature vary more near the surface then at depth, so I want to emphasized this region).
My depth array is not uniform (i.e. depth = [5,15,...,4975,5185,...]. I want to have such non-uniform vertical spacing.
I would like to show yticks = [10,100,500,1000,1500,2000,3000,4000,5000], and depth array does not have those exact values.
z = np.arange(0,50) # I want uniform spacing
pos = ([0,2,5,10,15,20,30,40,48]) # I want some yticks (not all of them)
ax=plt.contourf(lat,z,temp) # temp is a variable with dimensions (lat,depth)
plt.colorbar()
plt.gca().yaxis.set_ticks(pos) # Set some yticks, not all of them
plt.yticks(z[pos],depth[pos].astype(int)) # Replace the dummy values of z-array by something meaningful
plt.gca().invert_yaxis()
plt.grid(linestyle=':')
plt.gca().set(ylabel='depth (m)',xlabel='Latitude')'''
Potential Temperature of the Atlantic Ocean:
Per the matplotlib docs on yticks, you can specify the labels you want to use. In your case, if you want to show the labels [10,100,500,1000,1500,2000,3000,4000,5000] you can simply pass that list as the second argument in plt.yticks(), like so
plt.yticks(z[pos], [10,100,500,1000,1500,2000,3000,4000,5000])
and it will display the yticks accordingly. The issue arises in the specification of the positions - since the depth array does not have points corresponding exactly to the desired ytick values you will need to interpolate in order to find the exact position at which to place the labels. Unless the approximate positions specified in pos are already sufficient, in which case the above suffices.
If the depth data are not uniformly spaced then you can use numpy.interp to perform the interpolation, as shown below
import matplotlib.pyplot as plt
import numpy as np
# Create some depth data that is not uniformly spaced over [0, 5500]
depth = [(np.random.random() - 0.5)*25 + ii for ii in np.linspace(0, 5500, 50)]
lat = np.linspace(-75, 75, 50)
z = np.linspace(0,50, 50)
yticks = [10,100,500,1000,1500,2000,3000,4000,5000]
# Interpolate depths to get z-positions
pos = np.interp(yticks, depth, z)
temp = np.outer(lat, z) # Arbitrarily populate temp for demonstration
ax = plt.contourf(lat,z,temp)
plt.colorbar()
plt.gca().yaxis.set_ticks(pos)
plt.yticks(pos,yticks) # Place yticks at interpolated z-positions
plt.gca().invert_yaxis()
plt.grid(linestyle=':')
plt.gca().set(ylabel='Depth (m)',xlabel='Latitude')
plt.show()
This will find the exact positions where the yticks would fall if the depth array had data at those positions and place them accordingly as shown below.
I have some data of the following type:
grid = np.array([posx, posy]) where posx and posy are the X/Y position some, stored in another array.
The (transposed) grid may look like:
grid = np.array([posx, posy])
print grid.T
[[ 2.47685286 2.51629155]
[ 2.47685286 8.51629155]
[ 2.47685286 14.51629155]
[ 8.47685286 5.51629155]
[ 8.47685286 11.51629155]
[ 14.47685286 2.51629155]
[ 14.47685286 8.51629155]
[ 14.47685286 14.51629155]]
Especially the y-Position is not identical in each "row" and the number of points differs, which I assume to be one of my problems.
Additionally, the corresponding data is stored in another (1D-)array like data = [2.3 4.7 -0.3 .....] having the same amount of entrys as I have points.
My aim is to plot this data in kind of a smooth heatmap displaying by colours indicating position of high / low values. So far I used:
import numpy as np
import matplotlib.pyplot as p
p.imshow(data, interpolation=None)
p.colorbar()
p.show()
Obviously my problem is that I need to adjust the positon of my points.
I searched some other posts but with this shape of data it never worked out.
Also I tried to adjust this by simply reshaping the data but this didn't work due to the irregular number of points
As I am new here I am also happy for comments on how to improve my post (more input needed etc.)
Thanks in advance!
There are several solutions to this problem.
If what you want is simply to have the points shown as markers of some size, with colors depending on the values in the z array, then a scatterplot will do nicely. If the space between the points should also be colored however, you should use interpolation and contouring. Fortunately those things have also been implemented in matplotlib for irregularly spaced data (data on an "unstructured grid"), which is what you have as the points cannot be easily mapped to a regular grid (although in the small example you've given, there does seem to be a tendency for equal-sized triangles).
Here are 3 examples that illustrate the functions you might want to look further into: plt.scatter, plt.tripcolor and plt.tricontourf. I've made the dataset to play with a bit larger, so that you can get a feeling of the function that is represented by z.
x,y = (2*np.random.rand(50)-1 for _ in range(2))
z = np.exp(-x*x - y*y) - np.cos(x) # turtle-surface around origin
f, ax = plt.subplots(1,3, sharex=True, sharey=True, num=2, subplot_kw={'xlim': (-1,1), 'ylim': (-1, 1)})
ax[0].scatter(x,y, s=500*(z-z.min()), c=z, cmap='hot') # scatterplot with variable-sized markers and colors
ax[1].tripcolor(x, y, z, cmap='hot') # creates a tesselation and colors the formed triangles based on the values in the 3 nodes
ax[2].tricontourf(x, y, z, cmap='hot') # estimates the underlying surface
for indx in (1,2):
ax[indx].triplot(x,y, 'ko ') # add the locations of the points
for axes in ax: # turn off the needless clutter
axes.tick_params(axis='both', which='both', bottom='off', left='off', labelbottom='off', labelleft='off')
ax[0].set_title('scatter')
ax[1].set_title('tripcolor')
ax[2].set_title('tricontourf')
I think your problem could be solved by creating a regular 2d-matrix and then using scipy.interpolate to interpolate the data between your data points. Example can be found at: http://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html#id1
I would like to plot a 2D discretization rectangular mesh with non-regular
x y axes values, e.g. the typical discretization meshes used in CFD.
An example of the code may be:
fig = plt.figure(1,figsize=(12,8))
axes = fig.add_subplot(111)
matplotlib.rcParams.update({'font.size':17})
axes.set_xticks(self.xPoints)
axes.set_yticks(self.yPoints)
plt.grid(color='black', linestyle='-', linewidth=1)
myName = "2D.jpg"
fig.savefig(myName)
where self.xPoints and self.yPoints are 1D non-regular vectors.
This piece of code produce a good discretization mesh, the problem are the
xtics and ytics labels because they appear for all values of xPoints and yPoints (they overlap).
How can I easily redefine the printed values in the axes?
Let's say I only want to show the minimum and maximum value for x and y and not all values from the discretization mesh.
I cann't post a example-figure because it is the first time I ask something here (I can send it by mail if requested)
the problem is that you explicitly told matplotlib to label each point when you wrote:
axes.set_xticks(self.xPoints)
axes.set_yticks(self.yPoints)
comment out those lines and see what the result looks like.
Of course, if you only want the first and last point labelled, it becomes:
axes.set_xticks([self.xPoints[0], self.xPoints[-1]])
...
If the gridline was specified by axes.set_xticks(), I don't think it would be possible to show ticks without overlap in your case.
I may have a solution for you:
...
ax = plt.gca()
#Arr_y: y-direction data, 1D numpy array or list.
for j in range(len(Arr_y)):
plt.hline(y = Arr_y[j], xmin = Arr_x.min(), xmax = Arr_x.max(), color = 'black')
#Arr_x: x-direction data, 1D numpy array or list.
for i in range(len(Arr_x)):
plt.vline(x = Arr_x[i], ymin = Arr_y.min(), ymax = Arr_y.max(), color = 'black')
#Custom your ticks here, 1D numpy array or list.
ax.set_xticks(Arr_xticks)
ax.set_yticks(Arr_yticks)
plt.xlim(Arr_x.min(), Arr_x.max())
plt.ylim(Arr_y.min(), Arr_y.max())
plt.show()
...
hlines and vlines are horizontal and vertical lines, you can specify those lines with boundary data in both x and y directions.
I tried it with 60×182 non uniform mesh grid which cost me 1.2s, hope I can post a picture here.