I'd like to create a continuous colormap with matplotlib on a 3D Surface Plot, where the color depends on the z-value of the surface. But with the "normal" plt functions the colormap fills the space between the gridpoints with the same color like shown in the picture. So there is no continuous change in color, rather there are just some colored surfaces stitched together:
x = range(0,126)
y = range(0,3)
#z is my data from the experiment
# make a grid of the x/y plane
X,Y= np.meshgrid(x,y)
# get the colormap for the graph
cmap=plt.get_cmap("RdBu")
# cmap = clr.LinearColormap.from_list('custom blue', ['#244162','#DCE6F1'], N=256)
#plot the corresponding z-value at every knot of the grid
surface = ax.plot_surface(X,Y,z, cmap = cmap, antialiased=True, edgecolor='gray' , linewidth=0.2)
m = cm.ScalarMappable(cmap=surface.cmap,norm=surface.norm)
m.set_array(z)
plt.colorbar(m)
ax.set_yticks(y)
ax.set_xticks(x[::25])
plt.show()
which looks like this:
3D-surface Plot
Do I need to interpolate the surface in between with more gridpoints, or is there a more elegant way? I'm a little lost in the documentation and syntax
Thanks in advance,
masterblibla
Related
I created this short code last night to create a scatter plot with a colorbar. The scatter plot looks as follows:
I want to mark the smallest values of my x, y and z values with a different marker colour and size. I couldn't manage to find any useful information on how to achieve this.
cm = plt.cm.get_cmap('YlOrRd')
x, y, z = np.loadtxt('test.txt', unpack=True)
ms=45
pareto = plt.scatter(x,y,c=z, cmap=cm,s=ms)
cbar = plt.colorbar()
cbar.set_label('test')
plt.savefig('pics/test/test.png', dpi=300)
I am developing a python GUI that plots many lines, arrows and rectangles on a matplotlib canvas.
The rectangles go aligned with the lines: Rotated rectangle above line
Here is the picture.
I want to set a transform on the Rectangle, so that the side's length perpendicular to the line are in axes coordinates units (transAxes), and the sides parallel to the line are in data coordinates units (transData).
I know that blended_transform is can be used to define to different transforms for x-axis and y-axis. This is similar, but the directions in which the transforms are applied are not neccessary the horizontal and vertical direction. Is there a way of defining a custom blended transform that works on rotated directions instead of x-y directions? The documentation on transforms is not very helpful when trying to create a custom one.
Thanks!
The questions in the comments weren't answered, so one needs to make some assumptions. Let's say the rotation is supposed to happen in display space and the axes coordinates are those in y-axis direction. Then a possible transform could look like
trans = ax.get_xaxis_transform() + mtrans.Affine2D().rotate_deg(angle)
In this case the first dimension are data coordinates, the second are axes coordinates.
Some example:
import matplotlib.pyplot as plt
import matplotlib.transforms as mtrans
fig, ax = plt.subplots()
angle = 38 # degrees
trans = ax.get_xaxis_transform() + mtrans.Affine2D().rotate_deg(angle)
ax.plot([5,9],[0,0], marker="o", transform=trans)
rect = plt.Rectangle((5,0), width=4, height=0.2, alpha=0.3,
transform=trans)
ax.add_patch(rect)
ax.set(xlim=(3,10))
plt.show()
If instead you want rotation about a point in data coordinates, a single transform is not doing the job. For example for a rotation about (5,5) in data space,
import matplotlib.pyplot as plt
import matplotlib.transforms as mtrans
fig, ax = plt.subplots()
ax.set(xlim=(3,10),ylim=(4,10))
fig.canvas.draw()
angle = 38 # degrees
x, y = ax.transData.transform((5,5))
_, yax = ax.transAxes.inverted().transform((0,y))
transblend = ax.get_xaxis_transform()
x, y = transblend.transform((5,yax))
trans = transblend + mtrans.Affine2D().rotate_deg_around(x,y, angle)
ax.plot([5,9],[yax,yax], marker="o", transform=trans)
rect = plt.Rectangle((5,yax), width=4, height=0.2, alpha=0.3,
transform=trans)
ax.add_patch(rect)
plt.show()
Note that this invalidates as soon as you change the limits or figure size.
Using matplotlib, I am attempting to display the histograms of 2 sets of data simultaneously on the side walls of a 3D plot, using this Matlab code and plot from wikipedia as my guide: https://commons.wikimedia.org/wiki/File:MultivariateNormal.png
I am able to plot my raw data on the base plane and have created and plotted my Gaussian fits on the side walls using the 'zdir' kwarg.
This example is able to leverage the 'zdir' kwarg to force where the curves are plotted,
Matplotlib 2d Plot on Faces of 3d Plot
but the matplotlib documentation confirms my AttributeErrors: Unknown property zdir; hist and hist2d don't support this argument.
This example seems to be plotting bars manually on the figure
plotting 3d histogram/barplot in python matplotlib as a way around the problem.
I've tried both .hist and .hist2d with and without zdir=''.
# data is a 2D np.array defined elsewhere
# define plot limits
X = np.linspace(0, np.amax(data), 100)
Y = np.linspace(0, np.amax(data), 100)
# initialize data into x and y sets
x_data = data[:, 0]
y_data = data[:, 1]
# fit a gaussian to both sets
x_mean, x_std = norm.fit(x_data)
x_gauss = norm.pdf(X, x_mean, x_std)
y_mean, y_std = norm.fit(y_data)
y_gauss = norm.pdf(Y, y_mean, y_std)
# initialize plot
figure = plt.figure()
ax = figure.add_subplot(111, projection='3d')
# label axes
ax.set_xlabel('Delta X (um)')
ax.set_ylabel('Delta Y (um)')
ax.set_zlabel('P (X,Y)')
# plot data on base plane
ax.scatter3D(x_data, y_data, zdir='z', zs=0.0, c='k', marker='.')
# plot histograms on walls
ax.hist((x_data, x_gauss), bins=30) #these 2 lines
ax.hist((y_data, y_gauss), bins=30) #are where I'm looking for help
# plot gaussians on walls
ax.plot3D(X, x_gauss, zdir='y', zs=np.amax(data), c='b')
ax.plot3D(Y, y_gauss, zdir='x', zs=np.amax(data), c='g')
# show plot
plt.show()
Is there a direct match in matplotlib for the method Matlab that draws histograms on a specific plane of a 3D plot? Thank you for your help! I am very new to plotting and welcome any other idiomatic or depreciated changes you can see. I always like to see how other coders think.
I am trying to plot the following charts with Matpltlib:
I would like to have the colored dots at a constant distance from the bottom of the charts.
However as you can see they jump all over the place as their y coordinate is given in y value, and the y axis is different in each chart. Is there a way to define their y position in pixels from the x axis? Without having to resort to % of (top of the chart - bottom of the chart) would be ideal. Thanks!
You can plot the points in axes coordinates instead of data coordinates. Axes coordinates range from 0 to 1 (lower left corner to upper right corner).
In order to use axes coordinates, you need to supply Axes.transAxes to the plot's transform argument - also see the transformation tutorial.
Here is a minimal example:
import matplotlib.pyplot as plt
plt.plot([1,5,9], [456,894,347], "r-",
label="plot in data coordinates")
plt.plot([0.2,0.3,0.7], [0.2,0.2,0.5], "bo",
transform=plt.gca().transAxes, label="plot in axes coordinates")
plt.legend()
plt.show()
If you want to specify the horizontal coordinate in data coordinates, and the vertical one in axes coordinates, you can use a blended transformation,
matplotlib.transforms.blended_transform_factory(ax.transData, ax.transAxes)
This can be used as follows.
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
ax = plt.gca()
plt.plot([12,25,48], [456,894,347], "r-",
label="plot in data coordinates")
plt.plot([0.2,0.3,0.7], [0.2,0.2,0.5], "bo",
transform=ax.transAxes, label="plot in axes coordinates")
#blended tranformation:
trans = transforms.blended_transform_factory(ax.transData, ax.transAxes)
plt.plot([15,30,35], [0.75,0.25,0.5], "gs", markersize=12,
transform=trans, label="plot x in data-,\ny in axes-coordinates")
plt.legend()
plt.show()
I'm having some trouble with color maps. Basically, what I would like to produce is similar to the image below.
On the bottom subplot I would like to be able to plot the relevant colour, but spanning the entire background of the subplot.i.e it would just look like a colourmap over the entire plot, with no lines or points plotted. It should still correspond to the colours shown in the scatter plot.
Is it possible to do this? what I would ideally like to do is put this background under the top subplot. ( the y scales are in diferent units)
Thanks for and help.
code for bottom scatter subplot:
x = np.arange(len(wind))
y = wind
t = y
plt.scatter(x, y, c=t)
where wind is a 1D array
You can use imshow to display your wind array. It needs to be reshaped to a 2D array, but the 'height' dimensions can be length 1. Setting the extent to the dimensions of the top axes makes it align with it.
wind = np.random.randn(100) + np.random.randn(100).cumsum() * 0.5
x = np.arange(len(wind))
y = wind
t = y
fig, ax = plt.subplots(2,1,figsize=(10,6))
ax[0].plot(x,y)
ax[1].plot(x, 100- y * 10, lw=2, c='black')
ymin, ymax = ax[1].get_ybound()
xmin, xmax = ax[1].get_xbound()
im = ax[1].imshow(y.reshape(1, y.size), extent=[xmin,xmax,ymin,ymax], interpolation='none', alpha=.5, cmap=plt.cm.RdYlGn_r)
ax[1].set_aspect(ax[0].get_aspect())
cax = fig.add_axes([.95,0.3,0.01,0.4])
cb = plt.colorbar(im, cax=cax)
cb.set_label('Y parameter [-]')
If you want to use it as a 'background' you should first plot whatever you want. Then grab the extent of the bottom plot and set it as an extent to imshow. You can also provide any colormap you want to imshow by using cmap=.