I am making a plot as in:
http://matplotlib.org/examples/mplot3d/polys3d_demo.html
but in the example they declare:
ys[0], ys[-1] = 0, 0
so that the polygons have a point on the x,y plane.
My data does not have zeros at the end points. So, when I plot it, the polygons do not touch the x,y plane as they do nicely in the example. Is there a hack to make the polygons drop to the (x,y) plane even if the f(x,y) datapoint at the end points is not zero?
Here is my code now. The (x,y) plane is determined by the 1D arrays U_array and d_array. The z-variable is called zvar and is a 2D array:
fig = plt.figure()
ax = fig.gca(projection='3d')
xs = U_array
verts = []
zs = list(d_array)
indx = 0
for z in zs:
ys = np.copy(zvar[:,indx])
# ys[0], ys[-1] = 0, 0
verts.append(list(zip(xs, ys)))
indx = indx + 1
poly = PolyCollection(verts, facecolors = facecolors)
poly.set_alpha(0.7)
ax.add_collection3d(poly, zs=zs, zdir='y')
plt.show()
How can I make my plot without the commented line above where I artificially make my data points zero at the ends?
Thanks. Also, out of curiosity, why is zs in here not really the z-variable? ...
Related
I have a matplotlib contourf plot of longitudes and pressure levels in the vertical. I am trying to plot streamlines on this using the plt.streamplot function in matplotlib and using U and V wind data.
If I plot only the streamplot, it works fine. But I cannot get the streamlines to overlay on the contour plot.
Here is my code:-
fig, axes = plt.subplots(nrows, ncols, sharex=True, sharey=True)
if (nrows==1 and ncols==1):
axes=[axes]
else:
axes=axes.flat
for i, ax in enumerate(axes):
X,Y = np.meshgrid(x[i],y[i])
levels=np.arange(vmin,vmax,step)
h = ax.contourf(X,Y,z[i],cmap=cmap,levels=levels,extend='both')
w = ax.streamplot(X, Y, W[i], Z[i], linewidth=0.2, color='gray')
And this is the plot I get:
The following is the streamline plot, not sure why the y axis is from 0-120 instead of 0 to 1000:
You use curvilinear coordinate system for contour plot (lat-p).
You have to convert u,v to coordinate system of contour something like here (this is example for lat-lon you have to modify it to use pressure levels):
def myStreamPlot(lon,lat,u,v,color='k',density=2.5):
from scipy.interpolate import griddata
n,m = u.shape[1],u.shape[0]
x = np.linspace(np.nanmin(lon), np.nanmax(lon), n)
y = np.linspace(np.nanmin(lat), np.nanmax(lat), m)
xi, yi = np.meshgrid(x,y)
lon = lon.ravel()
lat = lat.ravel()
u = u.ravel()
v = v.ravel()
gu = griddata(zip(lon,lat), u, (xi,yi))
gv = griddata(zip(lon,lat), v, (xi,yi))
gspd = np.sqrt(gu**2 + gv**2)
SL = plt.streamplot(x,y,gu,gv,linewidth=1.,color=color,density=density)
This code use griddata function of scipy.interpolate: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.griddata.html
I am able to make a plot of data points based on their Lat and Long, which looks like:
whereby the orange is made up of points like:
using the code:
m = Basemap(projection='merc',llcrnrlat=-0.5,urcrnrlat=0.5,\
llcrnrlon=9,urcrnrlon=10,lat_ts=0.25,resolution='i')
m.drawcoastlines()
m.drawcountries()
# draw parallels and meridians.
parallels = np.arange(-9.,10.,0.5)
# Label the meridians and parallels
m.drawparallels(parallels,labels=[False,True,True,False])
# Draw Meridians and Labels
meridians = np.arange(-1.,1.,0.5)
m.drawmeridians(meridians,labels=[True,False,False,True])
m.drawmapboundary(fill_color='white')
x,y = m(X, Y) # This is the step that transforms the data into the map's projection
scatter = plt.scatter(x,y)
m.scatter(x,y)
where X and Y are numpy arrays.
I want to get the X and Y co-ordinate of a point that I click on.
I can get the co-ord using:
coords = []
def onclick(event):
if plt.get_current_fig_manager().toolbar.mode != '':
return
global coords
ix, iy = event.x, event.y
print('x = %d, y = %d'%(ix, iy))
global coords
coords.append((ix, iy))
return coords
cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
but this seems to return the figure co-ordinates. Is there a way to convert these to their respective lat and long co-ordinates?
I then plan to use these to find the nearest point in the original X and Y arrays to where I click
First of all you would want to use the data coordinates
ix, iy = event.xdata, event.ydata
Then to get lon/lat coordinates you need to apply the inverse map transform
lon, lat = m(event.xdata, event.ydata, inverse=True)
Does anyone know how to implement easily colormaps to 3d bar plots in matplotlib?
Consider this example, how do I change each bar according to a colormap? For example, short bars should be mainly blue, while taller bars graduate their colors from blue towards the red...
In the physical sciences, it's common to want a so-called LEGO plot, which is I think what the original user is going for. Kevin G's answer is good and got me to the final result. Here's a more advanced histogram, for x-y scatter data, colored by height:
xAmplitudes = np.random.exponential(10,10000) #your data here
yAmplitudes = np.random.normal(50,10,10000) #your other data here - must be same array length
x = np.array(xAmplitudes) #turn x,y data into numpy arrays
y = np.array(yAmplitudes) #useful for regular matplotlib arrays
fig = plt.figure() #create a canvas, tell matplotlib it's 3d
ax = fig.add_subplot(111, projection='3d')
#make histogram stuff - set bins - I choose 20x20 because I have a lot of data
hist, xedges, yedges = np.histogram2d(x, y, bins=(20,20))
xpos, ypos = np.meshgrid(xedges[:-1]+xedges[1:], yedges[:-1]+yedges[1:])
xpos = xpos.flatten()/2.
ypos = ypos.flatten()/2.
zpos = np.zeros_like (xpos)
dx = xedges [1] - xedges [0]
dy = yedges [1] - yedges [0]
dz = hist.flatten()
cmap = cm.get_cmap('jet') # Get desired colormap - you can change this!
max_height = np.max(dz) # get range of colorbars so we can normalize
min_height = np.min(dz)
# scale each z to [0,1], and get their rgb values
rgba = [cmap((k-min_height)/max_height) for k in dz]
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=rgba, zsort='average')
plt.title("X vs. Y Amplitudes for ____ Data")
plt.xlabel("My X data source")
plt.ylabel("My Y data source")
plt.savefig("Your_title_goes_here")
plt.show()
Note: results will vary depending on how many bins you choose and how much data you use. This code needs you to insert some data or generate a random linear array. Resulting plots are below, with two different perspectives:
So maybe not exactly what you're looking for (perhaps a good starting point for you), but using
Getting individual colors from a color map in matplotlib
can give varying solid colors for the bars:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.cm as cm # import colormap stuff!
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x, y = np.random.rand(2, 100) * 4
hist, xedges, yedges = np.histogram2d(x, y, bins=4, range=[[0, 4], [0, 4]])
# Construct arrays for the anchor positions of the 16 bars.
# Note: np.meshgrid gives arrays in (ny, nx) so we use 'F' to flatten xpos,
# ypos in column-major order. For numpy >= 1.7, we could instead call meshgrid
# with indexing='ij'.
xpos, ypos = np.meshgrid(xedges[:-1] + 0.25, yedges[:-1] + 0.25)
xpos = xpos.flatten('F')
ypos = ypos.flatten('F')
zpos = np.zeros_like(xpos)
# Construct arrays with the dimensions for the 16 bars.
dx = 0.5 * np.ones_like(zpos)
dy = dx.copy()
dz = hist.flatten()
cmap = cm.get_cmap('jet') # Get desired colormap
max_height = np.max(dz) # get range of colorbars
min_height = np.min(dz)
# scale each z to [0,1], and get their rgb values
rgba = [cmap((k-min_height)/max_height) for k in dz]
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=rgba, zsort='average')
plt.show()
Personally, I find that ugly as sin! But it probably won't look too bad with a sequential colormap - https://matplotlib.org/examples/color/colormaps_reference.html
When I plot Axes3D object, the number of ticks on X/Y axes are somehow changing by themselves (for example, for 1x1 object, there are five ticks on each axes, while for 2x2 object, there are 7 ticks on each axes, see below screenshots)
3D plot for 1x1 object:
3D plot for 2x2 object:
The problem is that number of my tick-labels are lower than the number of ticks, therefore all tick-labels moved to the beginning of the axes.
So, how can I reduce/setup number of ticks?
Here is my code:
my_w = 2
my_h = 2
x1_list_int = []
x2_list_int = []
y1_list_int = [[],[]]
y1_list_int = [[0 for x in range(my_w)] for y in range(my_h)] #matrix initialization
for i in xrange(my_w):
print i
x1_list_int.append(i*10)
x2_list_int.append(i+1)
for i in xrange(my_w):
for j in xrange(my_h):
y1_list_int[i][j] = (i-3)*(j-2)+20
data = np.array(y1_list_int)
column_names = x2_list_int
row_names = x1_list_int
fig = plt.figure()
ax = Axes3D(fig)
lx= len(data[0]) # Work out matrix dimensions
ly= len(data[:,0])
xpos = np.arange(0,lx,1) # Set up a mesh of positions
ypos = np.arange(0,ly,1)
xpos, ypos = np.meshgrid(xpos+0.25, ypos+0.25)
xpos = xpos.flatten() # Convert positions to 1D array
ypos = ypos.flatten()
zpos = np.zeros(lx*ly)
dx = 0.5 * np.ones_like(zpos)
dy = dx.copy()
dz = data.flatten()
ax.bar3d(xpos,ypos,zpos, dx, dy, dz, color='#00ceaa')
ax.w_xaxis.set_ticklabels(column_names)
ax.w_yaxis.set_ticklabels(row_names, rotation = 0)
label_x1 = 'X1'
label_x2 = 'X2'
label_y1 = 'Y1'
ax.set_xlabel(label_x2)
ax.set_ylabel(label_x1)
ax.set_zlabel(label_y1)
#-- save plot to the file
plt.savefig(self.picture_file_path_1)
....
plt.close() # final. data clean-up
I have found solution. Here it is:
from matplotlib.ticker import MaxNLocator
.....
ax.w_yaxis.set_major_locator(MaxNLocator(len(x1_list_int)+1))
ax.w_xaxis.set_major_locator(MaxNLocator(len(x2_list_int)+1))
.....
I'm trying to change the opacity of a tripcolor garph. Setting the alpha parameter is changing the opacity but is also showing up the mesh grid. I think that this is happening because the alpha parameter is not changing the opacity of the edges too. I tried to set edgecolor='none' but this is not solving my problem. Is there a way of changing the opacity without displaying the mesh grid?
"""
Pseudocolor plots of unstructured triangular grids.
"""
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np
import math
# Creating a Triangulation without specifying the triangles results in the
# Delaunay triangulation of the points.
# First create the x and y coordinates of the points.
n_angles = 36
n_radii = 8
min_radius = 0.25
radii = np.linspace(min_radius, 0.95, n_radii)
angles = np.linspace(0, 2*math.pi, n_angles, endpoint=False)
angles = np.repeat(angles[...,np.newaxis], n_radii, axis=1)
angles[:,1::2] += math.pi/n_angles
x = (radii*np.cos(angles)).flatten()
y = (radii*np.sin(angles)).flatten()
z = (np.cos(radii)*np.cos(angles*3.0)).flatten()
# Create the Triangulation; no triangles so Delaunay triangulation created.
triang = tri.Triangulation(x, y)
# Mask off unwanted triangles.
xmid = x[triang.triangles].mean(axis=1)
ymid = y[triang.triangles].mean(axis=1)
mask = np.where(xmid*xmid + ymid*ymid < min_radius*min_radius, 1, 0)
triang.set_mask(mask)
# Illustrate Gouraud shading.
plt.figure()
plt.gca().set_aspect('equal')
plt.tripcolor(triang, z, shading='gouraud', cmap=plt.cm.rainbow, alpha=0.5, edgecolor='none')
plt.colorbar()
plt.title('tripcolor of Delaunay triangulation, gouraud shading')
plt.show()
Thank you very much for your time,
Dorin
you can try it with: " edgecolors='k', linewidth=0.0 " so this can set the linewidth to zero, which makes the line disapp