I'm trying to plot a 3D surface with plot_trisurf like this:
xs = NP.array([ 0.00062 0.00661 0.02000 0.01569 0.00487 0.01784])
ys = NP.array([ 0.99999 0.66806 0.50798 0.61230 0.83209 0.86678])
zs = NP.array([-0.24255 -0.42215 -0.31854 -0.77384 -0.77906 -0.98167])
ax=fig.add_subplot(1,2,1, projection='3d')
ax.grid(True)
ax.plot_trisurf(xs, ys, zs, triangles = triangles, alpha = 0.0, color = 'grey')
This gives me
Now I have two problems:
The triangles are black, can I change this problem? (It works in 2D
with triplot with color = 'grey' but this doesn't seem to work
here.
(If it is visible) The grid of the 3D plot leaves traces in
the triangles: it seems like the grid is printed on top of the
triangles, while I (of course) want the triangles to be plotted on
top of the grid.
change the last line to:
ax.plot_trisurf(xs, ys, zs, triangles=triangles,
color=(0,0,0,0), edgecolor='Gray')
the color that you are specifying is used as facecolor; if you want to have transparent faces, instead of alpha=0 pass color=(r,g,b,0); the 0 in the tuple would be the alpha of the facecolor; so it will results in transparent faces;
Related
I've been working on this complicated plot of trajectories of rockets and maps and things... I came to the point that I needed to include markers on specific places of my map:
Figure without the marker
It's a long code, that requires a lot of data to reproduce, but when I include this line:
ax.scatter(-147.338786 65.32957 85.001453, c='aqua', marker='o', s = 100, label = 'PMC - Water release'
,edgecolors = 'black')
This is the result:
Figure with the marker
I'm using a figure generated with another code to generate the map as a png and add that to the 3D plot like so:
fig = plt.figure(figsize=(16,14))
ax = fig.gca(projection='3d')
ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))
ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))
k=.01
xx, yy = np.meshgrid(np.linspace(xlims[0],xlims[1],377), np.linspace(ylims[0]+k,ylims[1]+k,317))
# create vertices for a rotated mesh (3D rotation matrix)
X = xx#np.cos(theta)
Y = yy#np.sin(theta)
Z = yy*.0-2.
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=plt.imread(myfolder +
'basemap.png'), shade=False)
basemap.png is the name of the map (sized 377x317).
Does anybody know how to override the figure coming to the foreground with the marker? I don't know why it would do that, but that line (ax.scatter) is the only difference between figure 1 and figure 2.
edit: I did change the order of plot calls and so on, with no positive results
I am working on a calculation in Python which calculates the physical properties of an object for angles in the range 0 < θ < π/2 and 0 < φ < π/2 (i.e. the first octant). To visualize the properties I am currently plotting them as color values on a 3D unit sphere. Producing this plot for reasonable resolution is a fairly resource intensive process, but I have no interest in being able to look at the plot from any other angle.
What I would like to create instead is a 2D image plot similar to what imshow would create except that it should have the triangular outline of a sphere octant being projected into 2D. Note that I am not asking how to project the 3D data into 2D, but rather how to display the 2D data in a manner which looks similar to a sphere octant viewed from θ = π/4, φ = π/4.
My current code is below. The specifics may not be that relevant to an answer, but it gives an idea of what I am trying to do.
'''
The code above this point produces three arrays stored in a dictionary
called phs with the three entries using the keys 'I', 'II', 'III. Each
array is a function of theta and phi where
theta = np.linspace( 0, 90, nPoints)
phi = np.linspace( 0, 90, nPoints)
also
types = ('I', 'II', 'III')
'''
# Colormaps
mx = np.maximum( np.maximum( phs['I'], phs['II']), phs['III'])
cmap = cm.ScalarMappable( cmap='BuPu')
cmap.set_array( mx)
clrs = dict()
for type in types:
clrs[type] = cmap.to_rgba( phs[type])
# Convert to Cartesian coordinates with unit radius
xM, yM, zM = plotCartesianFixedR( thetaM, phiM)
# Plot
fig = plt.figure( figsize=(16,7))
ax = dict()
ax['I'] = plt.subplot( 131, projection='3d')
ax['II'] = plt.subplot( 132, projection='3d')
ax['III'] = plt.subplot( 133, projection='3d')
surf = dict()
for type in types:
surf[type] = ax[type].plot_surface( xM, yM, zM, rstride=1, cstride=1,
facecolors=clrs[type], shade=False)
# Set axis properties
ax[type].set_xticklabels([])
ax[type].set_yticklabels([])
ax[type].set_zticklabels([])
ax[type].view_init(elev=45, azim=45)
# Colorbar
plt.colorbar( cmap, shrink=1)
ax['I'].set_title( 'Log$_{10}(|\Delta k|)$ Type I (ssf)')
ax['II'].set_title( 'Log$_{10}(|\Delta k|)$ Type II (sff)')
ax['III'].set_title( 'Log$_{10}(|\Delta k|)$ Type III (fsf)')
# Add title
if title:
plt.suptitle(title)
The output looks like:
Just to restate the problem; I would like to reproduce this plot almost exactly but in 2D without including the background axes.
I want to plot a surface in Matplotlib consisting of zeros everywhere, except for a rectangular region centered in (0, 0), with sides (Dx, Dy), consisting of ones - kind of like a table, if you wil; I can do that using the plot_surface command, no worries there. I also want to plot its projections in the "x" and "y" directions (as in this demo) and that's when the results become weird: Python seems to be interpolating my amplitude values (which, again, should be either zero or one) for the contour plots and showing some lines with values that do not correspond to my data points.
This is what I'm doing:
import numpy
from matplotlib import pylab
from mpl_toolkits.mplot3d import axes3d
Dx = 1. # Define the sides of the rectangle
Dy = 2.
x_2D = numpy.linspace(-Dx, Dx, 100) # Create the mesh points
y_2D = numpy.linspace(-Dy, Dy, 100)
x_mesh, y_mesh = numpy.meshgrid(x_2D, y_2D)
rect_2D = numpy.zeros(x_mesh.shape) # All values of "rect_2D" are zero...
for i in range(x_2D.size):
for j in range(y_2D.size):
if numpy.abs(x_mesh[i, j]) <= Dx/2 and numpy.abs(y_mesh[i, j]) <= Dy/2:
rect_2D[i, j] = 1. # ... except these ones
fig = pylab.figure(figsize=(9, 7))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x_mesh, y_mesh, rect_2D, alpha=0.3)
ax.contour(x_mesh, y_mesh, rect_2D, zdir='x', offset=-1.5, cmap=pylab.cm.brg)
ax.contour(x_mesh, y_mesh, rect_2D, zdir='y', offset=3, cmap=pylab.cm.brg)
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-3, 3)
ax.set_zlim(0., 1.5)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
The resulting figure has a dark green line with amplitude a bit below 0.8 on both the "x" and "y" projections, which does not exist in my "rect_2D" variable. Does anyone knows if this is a bug or if there is a mistake in my code? Any suggestions on how to get rid of it? Thanks in advance!
Add a levels = [0], kwarg to your ax.contour call. This specifies where along the zdir axis your contours are computed. See mpl.axes.Axes.contour docstring for more info.
The problem is that without specifying levels, contour automatically computes the locations to plot contours and one of these contours is selected just past the 'edge of your table', but before your Zdata is 0. At these points contour interpolates between 0 and 1.
In matplotlib, I'm looking to create an inset color bar to show the scale of my contour plot, but when I create the contour using contour, the color bar has white stripes running through it, whereas when I use contourf, the colorbar has the proper "smooth" appearance:
How can I get that nice smooth colorbar from the filled contour on my normal contour plot? I'd also be OK with a filled contour where the zero-level can be set to white, I imagine.
Here is code to generate this example:
from numpy import linspace, outer, exp
from matplotlib.pyplot import figure, gca, clf, subplots_adjust, subplot
from matplotlib.pyplot import contour, contourf, colorbar, xlim, ylim, title
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
# Make some data to plot - 2D gaussians
x = linspace(0, 5, 100)
y = linspace(0, 5, 100)
g1 = exp(-((x-0.75)/0.2)**2)
g2 = exp(-((y-4.25)/0.1)**2)
g3 = exp(-((x-3.5)/0.15)**2)
g4 = exp(-((y-1.75)/0.05)**2)
z = outer(g1, g2) + outer(g3, g4)
figure(1, figsize=(13,6.5))
clf()
# Create a contour and a contourf
for ii in range(0, 2):
subplot(1, 2, ii+1)
if ii == 0:
ca = contour(x, y, z, 125)
title('Contour')
else:
ca = contourf(x, y, z, 125)
title('Filled Contour')
xlim(0, 5)
ylim(0, 5)
# Make the axis labels
yt = text(-0.35, 2.55, 'y (units)', rotation='vertical', size=14);
xt = text(2.45, -0.4, 'x (units)', rotation='horizontal', size=14)
# Add color bar
ains = inset_axes(gca(), width='5%', height='60%', loc=2)
colorbar(ca, cax=ains, orientation='vertical', ticks=[round(xx*10.0)/10.0 for xx in linspace(0, 1)])
if ii ==1:
ains.tick_params(axis='y', colors='#CCCCCC')
subplots_adjust(left=0.05, bottom=0.09, right=0.98, top=0.94, wspace=0.12, hspace=0.2)
show()
Edit: I realize now that at the lower resolution, the white striping behavior is hard to distinguish from some light transparency. Here's an example with only 30 contour lines which makes the problem more obvious:
Edit 2: While I am still interested in figuring out how to do this in the general general case (like if there's negative values), in my specific case, I have determined that I can effectively create something that looks like what I want by simply setting the levels of a filled contour to start above the zero-level:
ca = contourf(x, y, z, levels=linspace(0.05, 1, 125))
Which basically looks like what I want:
A simple hack is to set the thickness of the lines in the colorbar to some higher value.
E.g. storing the colorbar object as cb and adding the following lines to your example
for line in cb.lines:
line.set_linewidth(3)
gives
I have one question about the grid lines matplotlib.
I am not sure if this is possible to do or not.
I am plotting the following graph as shown in the image.
I won't give the entire code, since it is involving reading of files.
However the important part of code is here -
X, Y = np.meshgrid(smallX, smallY)
Z = np.zeros((len(X),len(X[0])))
plt.contourf(X, Y, Z, levels, cmap=cm.gray_r, zorder = 1)
plt.colorbar()
...
# Set Border width zero
[i.set_linewidth(0) for i in ax.spines.itervalues()]
gridLineWidth=0.1
ax.set_axisbelow(False)
gridlines = ax.get_xgridlines()+ax.get_ygridlines()
#ax.set_axisbelow(True)
plt.setp(gridlines, 'zorder', 5)
ax.yaxis.grid(True, linewidth=gridLineWidth, linestyle='-', color='0.6')
ax.xaxis.grid(False)
ax.xaxis.set_ticks_position('none')
ax.yaxis.set_ticks_position('none')
Now, my questions is like this -
If I put the grid lines below the contour, they disappear since they are below it.
If I put the grid line above the contour, they looks like what they are looking now.
However, what I would like to have is the grid lines should be visible, but should be below the black portion of the contour. I am not sure if that is possible.
Thank You !
In addition to specifying the z-order of the contours and the gridlines, you could also try masking the zero values of your contoured data.
Here's a small example:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-2*np.pi, 2*np.pi, 0.1)
y = np.arange(-2*np.pi, 2*np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) - np.cos(Y)
Z = np.ma.masked_less(Z, 0) # you use mask_equal(yourData, yourMagicValue)
fig, ax = plt.subplots()
ax.contourf(Z, zorder=5, cmap=plt.cm.coolwarm)
ax.xaxis.grid(True, zorder=0)
ax.yaxis.grid(True, zorder=0)
And the output: