Related
I would like to plot my model's grid on a basemap (here a Lambert Conformal projection) so that the code reads the coordinates of each grid point from the netCDF (.nc) file (the .nc file only includes these coordinates) and and connects them rectangularly (it's a C-grid) to eachother by lines and plots them. So far I have plotted these coordinates as dots on the map with "map.scatter"; but it doesn't make any sense to me to have only dots on my map as the model grid!
Here is my written code so far:
from mpl_toolkits.basemap import Basemap
from netCDF4 import Dataset as open_ncfile
import matplotlib.pyplot as plt
import matplotlib.lines as lines
import numpy as np
#-- open netcdf file
nc = open_ncfile('/desktop/grid.nc')
#-- read variable
lat = nc.variables['grid_corner_lat'][:]
lon = nc.variables['grid_corner_lon'][:]
#-- create figure and axes instances
fig = plt.figure(figsize=(15,15))
ax = fig.add_axes([0.1,0.1,0.8,0.9])
map = Basemap(llcrnrlon=-25,llcrnrlat=70,urcrnrlon=30,urcrnrlat=80,\
rsphere=(6378137.00,6356752.3142),\
resolution='l',area_thresh=1000.,projection='lcc',\
lat_0=85.,lat_1=75.,lon_0=0.,ax=ax)
map.drawcoastlines()
map.fillcontinents(color='0.90',lake_color='0.90')
# draw parallels and meridians.
map.drawparallels(np.arange(70.,90.,5.),labels=[1,1,0,1],fontsize=10)
map.drawmeridians(np.arange(-180.,180.,10.),labels=[1,1,0,1],fontsize=10)
map.drawmapboundary(fill_color='white')
x, y = map(lon,lat)
map.scatter(x,y,0.01,marker='.',color='k')
#-- add plot title
plt.show()
So, I would appreciate any help or comment :)
I have some trouble using scatter in python. I have 2 vectors of size 100 of latitudes and longitudes, and a vector 100 of corresponding data of values between 1 and 2.
I am trying to display these data on a north polar stereographic projected map, but nothing appears on the figure. Here is my code:
import numpy as np
import matplotlib as mpl
from matplotlib import pyplot as plt
from matplotlib import colors as mpl_colors
from mpl_toolkits.basemap import Basemap`
lon=np.linspace(-180,180,num=100)
lat=np.linspace(75,75,num=100)
data=1+np.random.rand(100)
cmap = plt.cm.jet
norm_color = mpl_colors.Normalize(vmin=None, vmax=None, clip=False)
fig=plt.figure()
m = Basemap(projection='npstere',boundinglat=65,lon_0=310,resolution='l')
x,y = m(lon,lat)
m.scatter(x, y,marker='+',c=data,cmap=cmap, norm=norm_color,edgecolor='none')
plt.show()
When I just scatter the coordinates: m.scatter(x, y,marker='+') it works fine (I have "+" at the corresponding coordinates, i.e on the 75° latitude projected circle). But when I want to add the data, nothing is displayed.
Where am I not using scatter right ?
I found what was the problem.
It is the simultaneous use of the options marker='+' and edgecolor='None'.
The latter allows to change the color of the edge of the marker. With the marker '+', the edge is the marker itself: that is why it was not displayed.
In replacement of the line m.scatter(x, y,marker='+',c=data,cmap=cmap, norm=norm_color,edgecolor='none') the following work:
m.scatter(x, y,marker='+',c=data,cmap=cmap, norm=norm_color)
or
m.scatter(x, y,marker='o',c=data,cmap=cmap, norm=norm_color,edgecolor='none')
I'm trying to recreate this projection using matplotlib Fundamental Lune Plot. The reference material associated with this specific projection is here, Carl Tape Moment Tensors
The geophysics behind the plot isn't crucial, but essentially its a projection between longitudes of -30 and 30 degrees and latitudes -90 to 90. I've thought that Basemap might be a good way of creating the projection, but I cannot seem to figure out how to only show this fundamental lune section. Here is what I've been playing around with,but it still shows the entire globe:
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
m = Basemap(
resolution='l', # coastline resolution, can be 'l' (low), 'h'
projection='hammer', # Hammer projection
lat_ts=0, # latitude of true scale
lon_0=0, # longitude of the plotting domain center
lat_0=0) # latitude of the plotting domain center
# draw parallels and meridians.
m.drawparallels(np.arange(-90.,90.,10.))
m.drawmeridians(np.arange(-30.,31.,10.))
ax = plt.gca()
plt.show()
Can anybody offer some guidance or suggestions?
In Basemap, I believe the Hammer projection is "global", meaning that it doesn't take extent inputs so it makes sense the entire globe would always show. As of 2022 Basemap is heavily deprecated / not supported.
I was able to make the plot you want using Cartopy instead. The following code produces image below and on the left, with some demo data:
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import matplotlib.path as mpath
# The Sinusoidal projection was added to Cartopy in version 0.14
fig = plt.figure(figsize=(3, 5))
ax = fig.add_subplot(111, projection=ccrs.Sinusoidal())
# Here I define a matplotlib Path object to use as the boundary
outlinex = np.concatenate([[-30],np.tile(-30,180), np.tile(30,180),[-30]])
outliney = np.concatenate([[-90],np.arange(-90,90),np.arange(89,-91,-1),[-90]])
outlinecodes = np.array([mpath.Path.MOVETO]+[mpath.Path.LINETO]*360+[mpath.Path.MOVETO])
outlinepath = mpath.Path(np.column_stack([outlinex[::-1], outliney[::-1]]), outlinecodes[::-1])
# For good measure, plot some data
ax.plot(np.arange(-10,25), np.linspace(80,45,35), transform=ccrs.Geodetic())
ax.plot(np.tile(25,91),np.arange(45,-46,-1), transform=ccrs.Geodetic())
# Plot gridlines and set the boundary
ax.gridlines(xlocs=np.arange(-30,31,10), ylocs=np.arange(-90,91,45))
ax.set_boundary(outlinepath, transform=ccrs.Geodetic())
# The plotting will have automatically set the extents, so set them to what we want
ax.set_extent((-30,30,-90,90))
plt.show()
Note, that if you omit the set_boundary elements and just use the set_extent, you'll get the image on the right, rather than the image on the left.
I am making Polar Stereographic Projection maps of some climate model outputs. For some of these data, the plot looks weird. For example, in this figure:
only two color contours showed up while the actual data should span much wider range. Furthermore, a large portion of the region should be blank since the data are masked out by netcdf module already (they are undefined).
from netCDF4 import Dataset
import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.basemap import Basemap
from pylab import *
fig_index=1
fig = plt.figure(num=fig_index, figsize=(12,7), facecolor='w')
fbot_levels = arange(0.05,1.0,0.05)
fname='alb.nc4'
ncfile = Dataset(fname, 'r', format='NETCDF4')
TS2=ncfile.variables['SIALB'][0]
LON=ncfile.variables['lon'][:]
LAT=ncfile.variables['lat'][:]
ncfile.close()
lon,lat=np.meshgrid(LON,LAT)
ax2 = plt.axes([0.2, 0.225, 0.6, 0.6])
meridians=[0,1,1,1]
m = Basemap(projection='spstere',lon_0=0,boundinglat=-45)
m.drawcoastlines()
x, y =m(lon,lat)
plt.contourf(x,y,TS2, fbot_levels, origin='lower')
m.drawparallels(np.arange(-90.,120.,15.),labels=[1,0,0,0]) # draw parallels
m.drawmeridians(np.arange(0.,420.,30.),labels=meridians) # draw meridians
coloraxis = [0.1, 0.1, 0.8, 0.035]
cx = fig.add_axes(coloraxis, label='m', title='K')
cbar=plt.colorbar(cax=cx,orientation='horizontal',ticks=list(fbot_levels))
plt.show()
You can find the dataset in netcdf format which is used to generate the figure here
https://dl.dropboxusercontent.com/u/45427012/alb.nc4
I am using basemap-1.0.6 with matplotlib-1.2.1 on py2.7.
Your Basemap object (m) also serves as the mpl axes. When plotting, you should use that instead of using plt.. So:
m.contourf(x,y,TS2, fbot_levels, origin='lower')
Stretching the levels between 0.5 and 0.9 highlights the different contours further.
I have a problem changing my axis labels in Matplotlib. I want to change the radial axis options in my Polar Plot.
Basically, I'm computing the distortion of a cylinder, which is nothing but how much the radius deviates from the original (perfectly circular) cylinder. Some of the distortion values are negative, while some are positive due to tensile and compressive forces. I'm looking for a way to represent this in cylindrical coordinates graphically, so I thought that a polar plot was my best bet. Excel gives me a 'radar chart' option which is flexible enough to let me specify minimum and maximum radial axis values. I want to replicate this on Python using Matplotlib.
My Python script for plotting on polar coordinates is as follows.
#!usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-180.0,190.0,10)
theta = (np.pi/180.0 )*x # in radians
offset = 2.0
R1 = [-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358]
fig1 = plt.figure()
ax1 = fig1.add_axes([0.1,0.1,0.8,0.8],polar=True)
ax1.set_rmax(1)
ax1.plot(theta,R1,lw=2.5)
My plot looks as follows:
But this is not how I want to present it. I want to vary my radial axis, so that I can show the data as a deviation from some reference value, say -2. How do I ask Matplotlib in polar coordinates to change the minimum axis label? I can do this VERY easily in Excel. I choose a minimum radial value of -2, to get the following Excel radar chart:
On Python, I can easily offset my input data by a magnitude of 2. My new dataset is called R2, as shown:
#!usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-180.0,190.0,10)
theta = (np.pi/180.0 )*x # in radians
offset = 2.0
R2 = [1.642,1.517,1.521,1.654,1.879,2.137,2.358,2.483,2.479,2.346,2.121,1.863,\
1.642,1.517,1.521,1.654,1.879,2.137,2.358,2.483,2.479,2.346,2.121,1.863,1.642,\
1.517,1.521,1.654,1.879,2.137,2.358,2.483,2.479,2.346,2.121,1.863,1.642]
fig2 = plt.figure()
ax2 = fig2.add_axes([0.1,0.1,0.8,0.8],polar=True)
ax2.plot(theta,R2,lw=2.5)
ax2.set_rmax(1.5*offset)
plt.show()
The plot is shown below:
Once I get this, I can MANUALLY add axis labels and hard-code it into my script. But this is a really ugly way. Is there any way I can directly get a Matplotlib equivalent of the Excel radar chart and change my axis labels without having to manipulate my input data?
You can just use the normal way of setting axis limits:
#!usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-180.0,190.0,10)
theta = (np.pi/180.0 )*x # in radians
offset = 2.0
R1 = [-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358,-0.483,-0.479,-0.346,-0.121,0.137,0.358,0.483,0.479,0.346,0.121,\
-0.137,-0.358]
fig1 = plt.figure()
ax1 = fig1.add_axes([0.1,0.1,0.8,0.8],polar=True)
ax1.set_ylim(-2,2)
ax1.set_yticks(np.arange(-2,2,0.5))
ax1.plot(theta,R1,lw=2.5)