Matplotlib: imshow in 3d plot - python

In the plot below, taken from matplotlib's gallery, contourf is used to create a 2d plot beneath the 3d one. My question is, is it possible to use imshow to do the same thing? I would like the colors in the 2d plot to be smoother.
Making the 2d plot seems to be possible because contourf accepts a zdir argument, while I've looked and imshow doesn't. That suggests that it isn't possible, but why not? pcolor would also get the job done, is it possible with that?

Just specify the levels= option for the contourf, e.g.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np
plt.clf()
fig = plt.figure(1)
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contourf(X, Y, Z, zdir='z', offset=-100,
levels=np.linspace(-100,100,1200),cmap=plt.cm.jet)
cset = ax.contourf(X, Y, Z, zdir='x', offset=-40, cmap=plt.cm.jet)
cset = ax.contourf(X, Y, Z, zdir='y', offset=40, cmap=plt.cm.jet)
ax.set_xlabel('X')
ax.set_xlim(-40, 40)
ax.set_ylabel('Y')
ax.set_ylim(-40, 40)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)
plt.show()

A little longer code then sega_sai's answer but faster and to my experience much better for more complex surfaces.
Use plot_surface to plot a flat surface where you want it and facecolors to color it with the values you want
You might need to make your data smoother with scipy's zoom
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np
plt.clf()
fig = plt.figure(1)
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contourf(X, Y, Z, zdir='x', offset=-40, cmap=plt.cm.jet)
cset = ax.contourf(X, Y, Z, zdir='y', offset=40, cmap=plt.cm.jet)
### strating here:
# normalize Z to [0..1]
Z=Z-Z.min()
Z=Z/Z.max()
#use zoom to make your data smoother
from scipy.ndimage.interpolation import zoom
#make data 5 times smoother
X=zoom(X,5)
Y=zoom(Y,5)
Z=zoom(Z,5)
#draw a surface at -100, using the facecolors command to color it with the values of Z
cset = ax.plot_surface(X, Y, np.zeros_like(Z)-100,facecolors=plt.cm.jet(Z),shade=False)
ax.set_xlabel('X')
ax.set_xlim(-40, 40)
ax.set_ylabel('Y')
ax.set_ylim(-40, 40)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)
plt.show()
This also makes it a little harder to create a color bar, in order to that:
cb = plt.cm.ScalarMappable(cmap=plt.cm.jet)
cb.set_array(Z)
plt.colorbar(cb)
plt.show()

Related

Plotting 3D sale graph ('WeekDay', 'Hour', 'SoldItems')

I am trying for first time to plot 3d chart and failing measurably. Getting error "Argument Z must be 2-dimensional." Not sure what should I do to make this work. I can plot sold items against both other arguments, thought it will catch this. Will appreciate any help and explanation.
Dataset records sale each hour.
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm
fig = plt.figure()
ax = fig.gca(projection='3d')
X = dataset['WeekDay']
Y = dataset['Hour']
Z = dataset['SoldItems']
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contourf(X, Y, Z, zdir='z', offset=0, cmap=cm.coolwarm)
cset = ax.contourf(X, Y, Z, zdir='x', offset=0, cmap=cm.coolwarm)
cset = ax.contourf(X, Y, Z, zdir='y', offset=0, cmap=cm.coolwarm)
ax.set_xlabel('X')
ax.set_xlim(0, 6)
ax.set_ylabel('Y')
ax.set_ylim(0, 23)
ax.set_zlabel('Z')
ax.set_zlim(0, 1000)
plt.show()

Mayavi : surface plot and 3D contours

Good evening everyone, I am a long time user of Matplotlib and I recently discovered Mayavi.
With Matplotlib, I can plot a 3D surface with projected contours of the surface plot for each axis and I was wondering if the same could be done with Mayavi.
Here is an example of what I have done so far with Matplotlib (source), but I have not been able to find a similar way to plot contours with Mayavi on the internet:
Can someone who knows Mayavi tell me if I can plot 3D contours for each axis like with Matplotlib?
Matplotlib code
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contour(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
ax.set_xlabel('X')
ax.set_xlim(-40, 40)
ax.set_ylabel('Y')
ax.set_ylim(-40, 40)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)
plt.show()
Mayavi code
from mpl_toolkits.mplot3d import axes3d
from mayavi import mlab
X, Y, Z = axes3d.get_test_data(0.05)
Z = np.rollaxis(Z,0,2)
X = np.rollaxis(X,0,2)
Y = np.rollaxis(Y,0,2)
mlab.surf(X, Y, Z, warp_scale="auto", opacity=1)
mlab.axes(xlabel='X', ylabel='Y', zlabel='Z')
mlab.show()

Mark projected min and max in 3D surface-/contourplot

I am using the standard matplotlib surfaceplot as an example here.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contour(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
ax.set_xlabel('X')
ax.set_xlim(-40, 40)
ax.set_ylabel('Y')
ax.set_ylim(-40, 40)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)][1]][1]
I would like to mark the two extrema of the surface with a "X" on their respective position on the contour.
How can this be achieved?
I tried:
max_column = np.argmax(np.max(Z, axis=0))
max_row = np.argmax(np.max(Z, axis=1))
min_column = np.argmin(np.min(Z, axis=0))
min_row = np.argmin(np.min(Z, axis=1))
target = [max_row,max_column,0]
ax.plot([target[0]],[target[1]],[0],'r',marker = u'X',markersize = 8)
I guess I need somehow the projected coordinates.
Additionally I would like to draw a hairline-cross with lines on the 2D plane where the extrema are.
First you need to find out the points corresponding to the minimum and maximum of the Z array.
You can then plot those points, where setting one of the coordinates to the values of the respective offset from the contour lets them be projected.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contour(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
ax.set_xlabel('X')
ax.set_xlim(-40, 40)
ax.set_ylabel('Y')
ax.set_ylim(-40, 40)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)
# calc index of min/max Z value
xmin, ymin = np.unravel_index(np.argmin(Z), Z.shape)
xmax, ymax = np.unravel_index(np.argmax(Z), Z.shape)
# min max points in 3D space (x,y,z)
mi = (X[xmin,ymin], Y[xmin,ymin], Z.min())
ma = (X[xmax, ymax], Y[xmax, ymax], Z.max())
# Arrays for plotting,
# first row for points in xplane, last row for points in 3D space
Ami = np.array([mi]*4)
Ama = np.array([ma]*4)
for i, v in enumerate([-40,40,-100]):
Ami[i,i] = v
Ama[i,i] = v
#plot points.
ax.plot(Ami[:,0], Ami[:,1], Ami[:,2], marker="o", ls="", c=cm.coolwarm(0.))
ax.plot(Ama[:,0], Ama[:,1], Ama[:,2], marker="o", ls="", c=cm.coolwarm(1.))
ax.view_init(azim=-45, elev=19)
plt.savefig(__file__+".png")
plt.show()

Matplotlib 2d Plot on Faces of 3d Plot

I am producing plots of a spacecraft's trajectory at a specific point in its orbit.
I have a piece of code which produces a 3d line plot in 3dMatplotlib (a part of mycode and figure is shown here (I have drastically reduced the number of points within X,Y,Z to ~20 per array to make it easier to simply copy and paste as the principle is the same):
#
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D
from numpy import *
XdS=[14.54156005, 14.53922242, 14.53688586, 14.53454823, 14.5322106 , 14.52987297, 14.52753426, 14.52519555, 14.52285792, 14.52051922, 14.51818051, 14.51584073, 14.51350095, 14.51116117, 14.5088214 , 14.50648162, 14.50414076, 14.50179991, 14.49945906, 14.49711821]
YdS=[31.13035144, 31.12920087, 31.12805245, 31.12690188, 31.12575131, 31.12460073, 31.12345016, 31.12229745, 31.12114473, 31.11999201, 31.1188393 , 31.11768443, 31.11652957, 31.11537471, 31.11421984, 31.11306283, 31.11190582, 31.11074882, 31.10959181, 31.1084348]
ZdS=[3.94109446, 3.94060316, 3.94011186, 3.93962083, 3.93912926, 3.93863796, 3.93814639, 3.93765482, 3.93716325, 3.93667169, 3.93617985, 3.93568828, 3.93519618, 3.93470434, 3.9342125 , 3.9337204 , 3.93322829, 3.93273592, 3.93224382, 3.93175144]
fig=plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(XdS,YdS,ZdS,c='black',linewidth=2)
ax.set_xlabel('XKSM (Saturn Radii)')
ax.set_ylabel('YKSM (Saturn Radii)')
ax.set_zlabel('ZKSM (Saturn Radii)')
plt.show()
#
What I want to do is be able to plot the 2d plots X vs Y, X vs Z, and Y vs Z on the edges/planes of this plot i.e. show what the 3d trajectory looks like looking at it in the 3 2d planes and display them at each axis of the current plot. (It isn’t actually as complicated as it might sound, as I already have the X,Y,Z, values for the trajectory). Here I found a similar example which achieves this, however utilising all 3d plot functions, available at: http://matplotlib.org/1.3.1/examples/mplot3d/contour3d_demo3.html : If you check out check out the link it will show the type of image i am trying to achieve.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contour(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
ax.set_xlabel('X')
ax.set_xlim(-40, 40)
ax.set_ylabel('Y')
ax.set_ylim(-40, 40)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)
plt.show()
This is in theory exactly what I need, in the way it takes sort of a planar view of the 3d situation. However I cannot implement a 2d line plot on a 3d axis nor can I use the offset command in a 2d plot (getting the error: TypeError: There is no line property "offset").
Is there a 2d equivalent to the 3d “offset” command and Is it possible to plot the 2d values on the planes of the 3d plot as I desire? Also is there a way to plot 2d lines having initialised a 3d projection? Can anyone offer any ideas/point me in any direction in general to help me achieve this?
My sincere thanks in advance and apologies if any part of this post is out of order, this is my first one!
Try this:
xmin = min(XdS)
ymax = max(YdS)
zmin = min(ZdS)
length_of_array = len(XdS)
xmin_array = [xmin] * length_of_array
ymax_array = [ymax] * length_of_array
zmin_array = [zmin] * length_of_array
fig=plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(XdS,YdS,ZdS,zdir='z', c='r')
ax.plot(XdS,YdS,zmin_array, zdir='z', c='g')
ax.plot(xmin_array, YdS, ZdS, 'y')
ax.plot(XdS,ymax_array,ZdS,'b')
ax.set_xlabel('XKSM (Saturn Radii)')
ax.set_ylabel('YKSM (Saturn Radii)')
ax.set_zlabel('ZKSM (Saturn Radii)')
plt.show()

pyplot static color colormap

I'm using the following code to generate a pyplot with a colormap:
# Create a 3d plot
fig = pyplot.figure()
ax = fig.gca(projection='3d')
# Plot the frequency-time
ax.plot_surface(X, Y, Z, rstride=4, cstride=5 + (samplerate / 20), alpha=0.3)
cset = ax.contour(X, Y, Z, zdir='y', offset=tlen, cmap=cm.coolwarm)
However I would like to use a colormap with a static color: #066. So no gradient effect.
Is there anyway to achieve this?
Greetings,
Mat
If you want to use a constant color don't pass the cmap parameter, use the colors instead:
cset = ax.contour(X, Y, Z, zdir='y', offset=tlen, colors='r')

Categories