pcolormesh () and contourf() do not work - python

Esteemed experts, am back with a problem I presented about two months ago, I have been working on it since with no success. This concerns superposition of contours on a basemap. I have looked at numerous examples on this, e.g. the example here: http://nbviewer.ipython.org/github/Unidata/tds-python-workshop/blob/master/matplotlib.ipynb
A sample of the data is on one of my previous posts, here: Contours with map overlay on irregular grid in python.
After preparing the data, here are plotting methods:
# Setting the plot size and text
fig = plt.figure(figsize=(10,8))
lev = [15, 20, 25, 30, 35, 40,45]
norm1 = colors.BoundaryNorm(lev, 256)
# Draw filled contours
# 1. pcolor does not show the filled contours
#cs = plt.pcolor(x,y,zi, cmap = cm.jet, norm = norm1)
# 2. pcolormesh does not show the filled contours
#cs = plt.pcolormesh(x,y,zi, shading = "flat", cmap=cmap)
# 3. contourf does not show the filled contours
#cs = plt.contourf(xi, yi, zi) #, levels=np.linspace(zi.min(),zi.max(),5))
cs = plt.contourf(xi, yi, zi, cmap = cm.jet, levels = lev, norm = norm1)
# 4. Draw line contours with contour()
#cs = m.contour(x,y,zi,linewidths=1.2) # This works
plt.scatter(data.Lon, data.Lat, c=data.Z, s=100,
vmin=zi.min(), vmax=zi.max()) # Does not work at all
# Color bar
#cbar = m.colorbar(fig,location='right',pad="10%")
fig.colorbar(cs)
# Plot a title
plt.figtext(.5,.05,'Figure 1. Mean Rainfall Onset Dates',fontsize=12,ha='center')
plt.show()
Sorry I am not able to post the plot examples, but:
pcolor, pcolormesh and contourf above all give a map without any filled contours but with a colorbar
the above plots without the map object give filled contours including scatter plot (without map background)
contour gives the map with contour lines superposed:
I am baffled because this is an example copy-pasted from the example in the link quoted above.
Any hint as to a possible cause of the problem would be appreciated
Zilore Mumba

you need to use the basemap to plot the contours vs using matplotlib.pyplot. see my example for some of my code.
#Set basemap and grid
px,py=n.meshgrid(x,y)
m=Basemap(projection='merc',llcrnrlat=20,urcrnrlat=55,
llcrnrlon=230,urcrnrlon=305,resolution='l')
X,Y=m(px,py)
#Draw Latitude Lines
#labels[left,right,top,bottom] 1=True 0=False
parallels = n.arange(0.,90,10.)
m.drawparallels(parallels,labels=[1,0,0,0],fontsize=10,linewidth=0.)
# Draw Longitude Lines
#labels[left,right,top,bottom] 1=True 0=False
meridians = n.arange(180.,360.,10.)
m.drawmeridians(meridians,labels=[0,0,0,1],fontsize=10,linewidth=0)
#Draw Map
m.drawcoastlines()
m.drawcountries()
m.drawstates()
m.fillcontinents(color='grey',alpha=0.1,lake_color='aqua')
#Plot Contour lines and fill
levels=[5.0,5.1,5.2,5.3,5.4,5.6,5.7,5.8,5.9,6.0]
cs=m.contourf(px,py,thickness,levels,cmap=p.cm.RdBu,latlon=True,extend='both')
cs2=m.contour(px,py,thickness,levels,latlon=True,colors='k')
#Plot Streamlines
m.streamplot(px,py,U,V,latlon=True,color='k')
#Add Colorbar
cbar = p.colorbar(cs)
cbar.add_lines(cs2)
cbar.ax.set_ylabel('1000 hPa - 500 hPa Thickness (km)')
#Title
p.title('Geostrophic Winds with Geopotential Thickness')
p.show()

Without knowing how your data look like it's a bit difficult to answer your question, but I'll try anyway. You might want to grid your data, for example, with an histogram, then contour the results.
For example, if you're interested in plotting 2D contours of points that have coordinates (x,y) and a third property (z) you want to use for the colors, you might give this a try
from numpy import *
H=histogram2d(x,y,weights=z)
contourf(H[0].T,origin='lower')
But, like I said, it's hard to understand what you're looking for if you're not giving details about your data. Have a look at the matplotlib guide for more examples http://matplotlib.org/examples/pylab_examples/contourf_demo.html

Related

Fill oceans in high resolution to hide low resolution contours in basemap

When plotting low-resolution contours over a high-resolution coastline I get the following result
I would like to fill the area outside of the coastlines (caused by the low resolution of the underlining filled contour plot) with the ocean color at high resolution.
I tried to use the land-sea mask option without coloring the land
m.drawlsmask(land_color=(0, 0, 0, 0), ocean_color='#2081C3',
resolution='h', lakes=True, zorder=2, grid=1.25)
but the 1.25 resolution is not enough for this level of detail (see second image)
Unfortunately there is no builtin method that fills the ocean (and lakes) with the same resolution used for the coastlines ('h' in my case). As a workaround is there any way to fill the area "outside" of the coastline using the original resolution?
I could use a high resolution land-sea mask in drawlsmask but that's a waste of resource since basemap already has indirectly that information with the polygons given by the coastlines.
General notes:
It looks like other questions on Stack Overflow suggest to use the builtin land sea mask of basemap. I can't because it is too low resolution at this zoom level.
Unfortunately I cannot use Cartopy. I already built my entire pipeline on Cartopy but it is way too slow for what I have to do.
I ended up using the solution posted in Fill oceans in basemap adapted to my needs. Note that, in order to retain the lakes, I had to do multiple passes of fillcontinents, so that's how I did
# extents contain the projection extents as [lon1, lon2, lat1, lat2]
m = Basemap(projection='merc',
llcrnrlat=extents[2],
urcrnrlat=extents[3],
llcrnrlon=extents[0],
urcrnrlon=extents[1],
lat_ts=20,
resolution='h')
m.fillcontinents(color='#c5c5c5', lake_color='#acddfe', zorder=1)
# Fill again the lakes over the contour plot
m.fillcontinents(color=(0, 0, 0, 0), lake_color='#acddfe', zorder=3)
ax = plt.gca()
# Workaround to add high resolution oceans
x0,x1 = ax.get_xlim()
y0,y1 = ax.get_ylim()
map_edges = np.array([[x0,y0],[x1,y0],[x1,y1],[x0,y1]])
# getting all polygons used to draw the coastlines of the map
polys = [p.boundary for p in m.landpolygons]
polys = [map_edges]+polys[:]
codes = [
[Path.MOVETO] + [Path.LINETO for p in p[1:]]
for p in polys
]
polys_lin = [v for p in polys for v in p]
codes_lin = [c for cs in codes for c in cs]
path = Path(polys_lin, codes_lin)
patch = PathPatch(path, facecolor='#acddfe', lw=0, zorder=2)
ax.add_patch(patch)
m.drawcountries(linewidth=0.6)
m.readshapefile(f'{SHAPEFILES_DIR}/ITA_adm_shp/ITA_adm2',
'ITA_adm2', linewidth=0.1, color='gray', zorder=5)
which gives something like this
Not perfect (because the shapefile which defines the coastline has a different resolution), but definitely better than before.

How to remove white spaces in the graph plot in python?

I have a problem after plotting the graph with matplolib using the python. I got the figure but the figure is having the white spaces of which i don't require. I have read most of the links that were provided by stack overflow but none is regarding to my issue. Now, I want to remove white spaces and require the whole image with picture.
Actually, I am new to the plot in python. I have created a plot of which the black colour is box and the grey colour is the frame.
I created the top vie of the 3D plot this as an image(.png) using the following code.
def cuboid(center, size):
ox, oy, oz = center
l, w, h = size
###Added the fig in order to be able to plot it later
ax = fig.gca(projection='3d') ##plot the project cuboid
X=[ox-l/2,ox-l/2,ox-l/2,ox-l/2,ox+l/2,ox+l/2,ox+l/2,ox+l/2] ##corner points of the cuboid
Y=[oy+w/2,oy-w/2,oy-w/2,oy+w/2,oy+w/2,oy-w/2,oy-w/2,oy+w/2]
Z=[oz-h/2,oz-h/2,oz+h/2,oz+h/2,oz+h/2,oz+h/2,oz-h/2,oz-h/2]
# ax.scatter(X,Y,Z,c='g',marker='o') #the plot before rotated
X_new = ([]) #attaining new corner points after rotated
Y_new = ([])
Z_new = ([])
for i in range(0,8):
c=np.matrix([[X[i]], ##reading every corner points into matrix format
[Y[i]],
[Z[i]]])
u=Rot_Mat*c ##rotating every corner point with the rotation matrix
X_new = np.append(X_new, u.item(0)) ##appending the corner points with the neighbours
Y_new = np.append(Y_new, u.item(1))
Z_new = np.append(Z_new, u.item(2))
print('\nvertex=\n',c)
print('\nnew_vertex=\n',u)
###Doing a dot product between Rot_Mat and c as earlier but using np.dot as it is necessary with Numpy format, reshaping from(3,1) to (3)
side[i,:] = np.dot(Rot_Mat, c).reshape(3)
sides = [[side[0],side[1],side[2],side[3]], ##defining the 6 sides of cuboid
[side[4],side[5],side[6],side[7]],
[side[0],side[1],side[4],side[5]],
[side[2],side[3],side[4],side[5]],
[side[1],side[2],side[5],side[6]],
[side[4],side[7],side[0],side[3]]]
ax.scatter(X_new,Y_new,Z_new,c='blue',marker='') #the plot of corner points after rotated
ax.add_collection3d(Poly3DCollection(sides, facecolors='black', linewidths=1, edgecolors='black', alpha=.25)) ###This draw the plane sides as requred
fig.tight_layout()
# Hide grid lines
ax.grid(False)
# Hide axes ticks
ax.set_xticks([])
ax.set_yticks([])
ax.set_zticks([])
plt.axis('off') #removes the axes from grams
The initialisation data to create this cuboid plot is given as follows:
fig=plt.figure(figsize=(6,6)) ##to obtain figure and dimensions of graph
ax = fig.add_axes([0,0,1,1], projection='3d')
#plot planes
p = Rectangle((0,-0.7), 4.5,1.4, color="lightgrey", alpha=0.2) #plots the background frame
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=0, zdir="z")
i=pd.read_excel('Bond0.dump.xlsx') ##to read the excel file format
X=i['x'] ## to import the variable on to axes from data set
Y=i['y']
Z=i['z']
j=pd.read_excel('paketone4000.dump.xlsx') ##to read the excel file format
X=j['x'] ## to import the variable on to axes from data set
Y=j['y']
Z=j['z']
a=j['x']##import centre of mass from excel file format
b=j['y']
c=j['z']
#cuboid initialising parameters
center = [a[0], b[0], c[0]] ##centre of the body
length = 0.3 ##defining length, breadth, height
width = 0.4
height = 0.1
side = np.zeros((8,3)) ###This numpy vector will be used to store the position of the sides
The expected outcome is that i have to remove the white spaces in the picture and form a picture with the grey frame (vertical dimensions=(0,4.5), horizontal dimention=(-0.7,0.7))

matplotlib contour not encapsulating the limits as expected

I'm trying to make a figure that shows both a heatmap and a contourplot of the same data.
Currently the contour does not connect to the edges of the image, leaving the '6's and '8's at the edge of the plots out of the contour plot.
I would want the contour to actually enclose all the values containing the values specified in the levels.
# make array
a = np.array( [(1,2,3,4,5,6),
(2,3,4,5,6,7),
(3,4,5,6,7,8),
(4,5,6,7,8,9),
(5,6,7,8,9,10)])
fig,ax = plt.subplots(figsize=(10,4.5))
#plot both colors and contour
im = ax.pcolormesh(a,norm=colors.LogNorm(vmin=1, vmax=10),
cmap='rainbow')
contour = ax.contour(a,levels=[2,4,6,8],colors='k')
# indicate the data
for i in range(0,6):
for j in range(0,5):
plt.text(i+.5,j+.5,str(a[j,i]))
Figure showing heatmap and contours:
UPDATE:
I've provisionally solved the problem by enlarging the dataset and zooming in on the original frame.

Using color scales as axes in matplotlib

I'm trying to create a visualization that varies color (specifically the H and V values of an HSV color scheme while keeping S constant), while representing the response of a given function to those colors.
Effectively, it's a heat map where the x and y axes are colors rather than numbers. Hunting through the matplotlib gallery I can find a lot of examples based on colorbars such as those found here, and here.
The colorbar implementation is close to what I'm looking for, with these important caveats:
I'm looking to align the colors as ticks on the main figure, rather than adding ticks to the colorbar itself. Principally this calls for making sure the plot and the colorbar are aligned, and I haven't found any way of actually guaranteeing this.
I'm trying to ensure that the color bar will display on the left of the figure (in place of the standard x-axis) rather than to the right.
The second point sounds trivial, but I haven't found any documented way of achieving it unfortunately.
Is there any way of creating a plot like this in matplotlib that would be considerably less effort than creating it from scratch in d3 or a similar lower-level visualization library?
I'm still not quite sure about it; but I'll give a try. Sorry if I misunderstood it.
Major thoughts are using GridSpec to solve your two requirements: aligning the "color axes" and put them beside the classic axes. The alignment should be correct because corresponding axes between ax_x/ax_y and the main ax are the same.
import matplotlib.pyplot as plt
from matplotlib.colors import hsv_to_rgb
from matplotlib.gridspec import GridSpec
import numpy as np
# Create a spectrum sample
# Convert HSV to RGB so that matplotlib can plot;
# hsv_to_rgb assumes values to be in range [0, 1]
N = 0.001
v_y, h_x = np.mgrid[0:1:N, 0:1:N]
c = hsv_to_rgb(np.stack([h_x, np.ones(h_x.shape), v_y], axis=2))
c_x = hsv_to_rgb(np.stack([h_x, np.ones(h_x.shape), np.zeros(v_y.shape)], axis=2))
c_y = hsv_to_rgb(np.stack([np.zeros(h_x.shape), np.ones(h_x.shape), v_y], axis=2))
fig = plt.figure()
# Ratio to adjust width for "x axis" and "y axis"
fig_ratio = np.divide(*fig.get_size_inches())
gs = GridSpec(2, 2, wspace=0.0, hspace=0.0,
width_ratios=[1, 20], height_ratios=[20/fig_ratio, 1])
# Lower-left corner is ignored
ax_y = plt.subplot(gs[0])
ax = plt.subplot(gs[1])
ax_x = plt.subplot(gs[3])
# Image are stretched to fit the ax since numbers are hided or not important in this figure.
img = ax.imshow(c, aspect='auto', origin='lower')
# Colorbar on img won't give correct results since it is plot with raw RGB values
img_x = ax_x.imshow(c_x, aspect='auto', origin='lower')
img_y = ax_y.imshow(c_y, aspect='auto', origin='lower')
# Remove ticks and ticklabels
for ax in [ax_y, ax, ax_x]:
ax.tick_params(left=False, bottom=False,
labelleft=False, labelbottom=False)
plt.show()
Response to the comment:
To clarify, you're making three plots, and using imshow plots as axes by assigning them to quadrants of the grid?
Yes, it's a 2x2 grid and I ignored the lower-left one. The documentation might not be great but what I did is similar to this part.
And presumably if I wanted to add space between the axes here and the main plot I would increase wspace and hspace?
Yes, it is briefly demonstrated in this part of documentation. Besides, I adjusted it with width_ratios and height_ratios so that 3 parts of the figure are not the same size, like this.
Also, just to confirm, there is a fully black axis on the bottom of this image, and it's not a misalignment of the left axis.
The bottom is the colored x axis. It is black because I thought it corresponds to v=0. If you change
c_x = hsv_to_rgb(np.stack([h_x, np.ones(h_x.shape), np.zeros(v_y.shape)], axis=2))
to
c_x = hsv_to_rgb(np.stack([h_x, np.ones(h_x.shape), np.ones(v_y.shape)], axis=2))
You would get this figure, proving it's not misaligned:
If it's easier, you can also ignore the whole hsv thing, use a gray box or something as the central image.
I'm sorry but I'm really slow on this. I'm still having no idea what you want to show in the figure. So I don't know how to help. If you remove or comment out the line
img = ax.imshow(c, aspect='auto', origin='lower')
You got this:

Python: Matplotlib Surface_plot

I'm trying to Plot a high resolution surface_plot, but I would also really like some nice grid lines on top of it. If i use the gridlines in the same argument
ax.plot_surface(x_itp, y_itp, z_itp, rstride=1, cstride=1, facecolors=facecolors, linewidth=0.1)
I get a LOT of grid lines. If I, on the other hand, set "rstride" and "cstride" to higher values, my sphere will become ugly.
I then tried to smash a
ax.plot_wireframe(x_itp, y_itp, z_itp, rstride=3, cstride=3)
in afterwards, but it just lies on top of the colored sphere.. meaning that I can see the backside of the wireframe and then the surface_plot behind it all.
Have anyone tried this?
Another option was to use "Basemap" which can create a nice grid, but then I will have to adapt my colored surface to that.?!
My plot looks like this:
If I add edges to the map with a higher "rstride" and "cstride" then it looks like this:
code :
norm = plt.Normalize()
facecolors = plt.cm.jet(norm(d_itp))
# surface plot
fig, ax = plt.subplots(1, 1, subplot_kw={'projection':'3d', 'aspect':'equal'})
ax.hold(True)
surf = ax.plot_surface(x_itp, y_itp, z_itp, rstride=4, cstride=4, facecolors=facecolors)
surf.set_edgecolors("black")
I want to show the \theta and \phi angles around the sphere.. maybe with 30 degrees apart.
Cheers!
Morten
It looks like you may need to use basemap. With plot_surface() you can either have high resolution plot or low resolution with good grid on top. But not both. I just made a simple basemap with contour plot. I think you can do easily apply pcolor on it. Just do not draw continent and country boundary. Then, you have a nice sphere which gives more control. After making your plot, you can easily add grid on it.
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
map = Basemap(projection='ortho',lat_0=45,lon_0=-150)
map.drawmapboundary(fill_color='aquamarine')
map.drawmeridians(np.arange(0,360,30)) # grid every 30 deg
map.drawparallels(np.arange(-90,90,30))
nlats = 73; nlons = 145; delta = 2.*np.pi/(nlons-1)
lats = (0.5*np.pi-delta*np.indices((nlats,nlons))[0,:,:])
lons = (delta*np.indices((nlats,nlons))[1,:,:])
wave = 0.6*(np.sin(2.*lats)**6*np.cos(4.*lons))
mean = 0.5*np.cos(2.*lats)*((np.sin(2.*lats))**2 + 2.)
x, y = map(lons*180./np.pi, lats*180./np.pi) # projection from lat, lon to sphere
cs = map.contour(x,y,wave+mean,15,linewidths=1.5) # contour data. You can use pcolor() for your project
plt.title('test1')
plt.show()

Categories

Resources