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)
Related
I am trying to plot an animation of the motion of several different ships in a North-East frame. Each ship is identified by a circle marker, color, and an ID. The vessel information is stored in a list of Vessel objects each with a positions attribute which stores north and east coordinates.
I only want to keep the newest ship's position, so all earlier points should be cleared.
What I have written so far plots the dots but I cannot find a way to specify additional parameters such as name and color arguments. I would prefer to not have to create an individual line object for each vessel because the IDs are not necessarily sorted and there may be a need for static object in the future which are stored in a separate list.
The code I have so far is
def plot_animation(vessels, objects, ts=10, n_min=3, **kwargs):
import matplotlib.animation as animation
"""Plots the results of a simulation
input:
vessels: List of `Vessel()` type
n_min: The number of minutes between each position scatter point
**kwargs: Keyword arguments for the plotting commands
output:
None
"""
pos_marker = kwargs.get("pos_marker", "o") # options
pos_marker_size = kwargs.get("pos_marker_size", 50)
frames = len(vessels[0].get_positions()) # number of simulation time-points
axis_min = 0
axis_max = 0
for v in vessels: # for determining axis bounds
positions = v.get_positions()
axis_min = min(min([min(pos) for pos in positions]), axis_min)
axis_max = max(max([max(pos) for pos in positions]), axis_max)
fig = plt.figure()
ax = fig.add_subplot(
111, autoscale_on=False, xlim=(axis_min, axis_max), ylim=(axis_min, axis_max)
)
ax.set_aspect("equal")
ax.grid()
ax.set_xlabel("East [km]")
ax.set_ylabel("North [km]")
(line,) = ax.plot([], [], "o")
def init():
line.set_data([], [])
return (line,)
def animate(i):
x = []
y = []
for v in vessels:
positions = v.get_positions()
north = positions[i].north
east = positions[i].east
x.append(east)
y.append(north)
line.set_data(x, y)
return (line,)
ani = animation.FuncAnimation(
fig, animate, frames=frames, init_func=init, blit=True
)
plt.show()
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
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
Let's say I have two lists, x and y of same length. This length is not fixed, but always nonzero. They are x and y values of non-negative points.
I want to create a a color density map much like http://www.mathworks.com/matlabcentral/fx_files/31726/1/datadensitymap.jpg .
Here's my attempt borrowing from a few places I've found on the internet:
density = stats.gaussian_kde([x,y])
color = density([x,y])
x1 = np.array(x)
y1 = np.array(y)
xmin = x1.min()
xmax = x1.max()
ymin = y1.min()
ymax = y1.max()
xscale = (xmax-xmin)/100
yscale = (ymax-ymin)/100
X, Y = np.mgrid[xmin:xmax:xscale, ymin:ymax:yscale]
positions = np.vstack([X.ravel(), Y.ravel()])
Z = np.reshape(density(positions).T, X.shape)
cmap = plt.get_cmap("hot")
plt.imshow(np.rot90(Z), cmap=cmap, extent=[xmin, xmax, ymin, ymax])
plt.scatter(x, y, c=color, cmap=cmap)
When I run this code the plot doesn't render; the title and labels are mashed together.
When I take out the call to imshow, the scatterplot shows perfectly with the density colors on the points showing correctly.
As it turns out, the plot was rendering, but because x had values much larger than y the rendered graph had no height. Setting aspect="auto" fixed it:
plt.imshow(np.rot90(Z), cmap=cmap, extent=[xmin, xmax, ymin, ymax], aspect="auto")
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? ...