Hello I have this code here, that I use to plot climate maps of aerosols.
import matplotlib.pyplot as plt
from netCDF4 import Dataset as netcdf_dataset
import numpy as np
from cartopy import config
import cartopy.crs as ccrs
import cartopy.feature as cfeature
AODs_Season = netcdf_dataset('/home/vescovint/Documents/AOD_0219_DJF.nc')
lats = AODs_Season.variables['lat'][:]
lons = AODs_Season.variables['lon'][:]
AODS = AODs_Season.variables['AOD_550_Dark_Target_Deep_Blue_Combined_Mean_Mean'][0, :, :]
ax = plt.axes(projection=ccrs.PlateCarree())
plt.contourf(lons, lats, AODS, 60, transform=ccrs.PlateCarree(), cmap='YlOrRd')
plt.colorbar(shrink=0.55)
plt.gcf().set_size_inches(15, 11)
ax.coastlines()
plt.savefig('/home/vescovint/Documents/AOD_Maps/DJF2002')
My problem is that, all my maps avec different range of value on the colorbar from 0 to 5 and i would to set it to min = 0 and max = 3.
I can't figure it out, if anyone can help me, I would be grateful.
Thomas
You can use clim() method from pyplot. For example:
plt.clim(0,3)
to set the color range of your plot (see doc)
Related
I am trying to plot wind quivers from a NetCDF file, however, I can only plot one line of quivers, straight across the base map, as seen in the image. The code is below. Thank you very much for any help :)
data is here, please replace with the onedrive folder, thanks
https://drive.google.com/file/d/160121aFx0Ys6G1jdQZOCT2Ve9eZgOyUy/view?usp=sharing
import xarray as xr
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
data = xr.open_dataset(<Insert google drive file data here>)
data = data.sel(time='2010-04-14T00:00:00.000000000')
X = data.longitude; Y = data.latitude
U = data.u10[200]; V = data.v10[200]
plt.figure()
ax = plt.subplot(111,projection=ccrs.PlateCarree())
ax.quiver(X[::5], Y[::5], U[::5], V[::5],color='green')
plt.show()
I would expect all the quivers to be plotted, so the graph should be full of the green arrows
Currently, this is the plotted image:
You are only taking data from the last row with data.u10[200]. Instead for the quiver, make coordinates as 2D arrays and plot for instance every 5 point of the dataset. Here is my solution, I downloaded and saved your data as "exdata.nc".
#!/usr/bin/env ipython
# --------------------
import xarray as xr
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import numpy as np
# --------------------------------------------------------------------
data = xr.open_dataset('exdata.nc')
data = data.sel(time='2010-04-14T00:00:00.000000000')
X = data.longitude; Y = data.latitude
# --------------------------------------------------------------------
XM,YM = np.meshgrid(X,Y)
U = data.u10; V = data.v10
skipx, skipy = 5,5
# ----------------------------------------------------------------
plt.figure(figsize=(12,12))
ax = plt.subplot(111,projection=ccrs.PlateCarree())
ax.quiver(XM[::skipy,::skipx], YM[::skipy,::skipx], U[::skipy,::skipx], V[::skipy,::skipx],color='green')
ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.OCEAN)
plt.show()
# ---------------------------------
Hope this helps as an example!
Hello everyone.In the picture you can see a sample of my code(it repeats for i==6),and the outputs.Can somone tell me how to add coastlines/boundaries to maps?"ax.coastlines() failed. Thank you
I think the problem is that your axes is not a geoAxes. To make it a geoAxes you have to tell matplotlib what projection (e.g. PlateCarree) you would like to use.
What you could do is using the cartopy library and adding the projection key word to your subplot. See example below:
import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
# Create sample data
lon = np.arange(129.4, 153.75+0.05, 0.25)
lat = np.arange(-43.75, -10.1+0.05, 0.25)
data = 10 * np.random.rand(len(lat), len(lon))
data_array = xr.Dataset({"DC": (["lat", "lon"], data),
'DMC': (["lat", "lon"], data),
'FFMC': (["lat", "lon"], data)},
coords={"lon": lon,"lat": lat})
# Just checking the datasets are not empty
print(data_array)
#< Plotting
fig, axes = plt.subplots(nrows=3, ncols=3, subplot_kw={'projection': ccrs.PlateCarree()}) # Use PlateCarree projection
data_array['DC'].plot(ax=axes[0,0], cmap='Spectral_r', add_colorbar=True, extend='both')
axes[0,0].coastlines() # Add coastlines
I have a 2-d numpy array with with some data, in x and y coordinates. With each x and y point is also associated a latitude and a longitude (also 2-d numpy arrays). There are some values in the oceans, but not over land.
When I plot the data in x and y coordinates, I get the following:
plt.imshow(data)
Then, I want to plot this data on a map using lon-lat coordinates. If I do so as following, I get some plotted data on land, since some interpolation is operated.
import cartopy.crs as ccrs
ax = plt.axes(projection=ccrs.Robinson())
plt.pcolor(lon, lat, data, transform=ccrs.PlateCarree())
ax.coastlines()
I obtain the same for any type of plot that I can use on a map (pcolormesh, contour, contourf).
How can this be avoided since no data would show on land, where values should be Nans?
Thank you!
The data is part of the CMIP6 project. It can be accessed through Pangeo by accessing ocean.pangeo.io and running the following code:
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import xarray as xr
import zarr
import gcsfs
import intake
from dask.distributed import Client
from dask_kubernetes import KubeCluster
cluster = KubeCluster()
cluster.adapt(minimum=1, maximum=20, interval='2s', wait_count=10)
client = Client(cluster)
client
url = 'https://raw.githubusercontent.com/NCAR/intake-esm-datastore/master/catalogs/pangeo-cmip6.json'
col = intake.open_esm_datastore(url)
col_hist = col.search(variable_id='o2', table_id='Omon', experiment_id='historical')
dict_hist = col_hist.to_dataset_dict(zarr_kwargs={'consolidated': True})
import cartopy.crs as ccrs
import cartopy.feature as cfeature
models = list(dict_hist.keys())
model = models[5]
ds = dict_hist[model]
sub1 = ds.o2.sel(member_id=ds.member_id.values[0], time=ds.time.values[0])
sub2 = sub1.sel(lev=100, method='nearest')
ax = plt.axes(projection=ccrs.Robinson())
q = sub2.plot(ax=ax, transform=ccrs.PlateCarree(), x='lon', y='lat', vmin=0, vmax=0.4, cbar_kwargs={'shrink': 0.5})
ax.set_global(); ax.coastlines();
Edited to account for comments on data.
The issue with the filled areas is one of wrapping. What you see is data plotting from e.g. +179.8 (right side of plot) to -178.4 (left side of plot)--CartoPy is not correctly clipping, so you have long streaks of data plotting across the map. In areas with other data plotted, these streaks are covered. Where you have no data plotted (i.e. on land) the streaks show through.
One work-around is to adjust the origin of the projection, which can eliminate some of those lines. I've had some success with small adjustments (~1 degree), but the best would be to make it so that the left and right edges of the original domain of the data are the left and right edges of the plot. For this dataset the left edge is +73.5 longitude, so we want the origin to be that +180, which is -107.5 longitude:
import intake
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
url = ('https://raw.githubusercontent.com/NCAR/'
'intake-esm-datastore/master/catalogs/pangeo-cmip6.json')
col = intake.open_esm_datastore(url)
col_hist = col.search(variable_id='o2', table_id='Omon', experiment_id='historical')
dict_hist = col_hist.to_dataset_dict(zarr_kwargs={'consolidated': True})
models = list(dict_hist.keys())
model = models[5]
ds = dict_hist[model]
sub1 = ds.o2.sel(member_id=ds.member_id.values[0], time=ds.time.values[0])
sub2 = sub1.sel(lev=100, method='nearest')
ax = plt.axes(projection=ccrs.Robinson(central_longitude=-107.5))
q = sub2.plot(ax=ax, transform=ccrs.PlateCarree(), x='longitude', y='latitude',
vmin=0, vmax=0.4, cbar_kwargs={'shrink': 0.5})
ax.coastlines()
ax.set_global()
which gives me this image:
Ideally, CartoPy would handle this correctly, but right now there are lots of issues with this (like this one for example).
So the problem is that when I add a geometry from .shp file to the cartopy figure, there is an offset and I have no idea how to set the offset.
I am new to python so any help is appreciated.
picture here
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
#from cartopy.feature import GSHHSFeature
from cartopy.io.shapereader import Reader
canada_east = -63
canada_west = -123
canada_north = 75
canada_south = 37
standard_parallels = (49, 77)
central_longitude = -(91 + 52 / 60)
data = Reader('icitw_wgs84')
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1,
projection=ccrs.LambertConformal(central_longitude=central_longitude,
standard_parallels=standard_parallels))
ax.set_extent([-79.65, -79.1, 43.57, 43.87])
ax.add_feature(cfeature.LAKES.with_scale('10m'))
ax.add_feature(cfeature.LAND.with_scale('10m'))
ax.add_feature(cfeature.RIVERS.with_scale('10m'))
ax.add_geometries(data.geometries(), crs=ccrs.Geodetic(), edgecolor='k', facecolor='none')
I think what you are seeing is due to the low resolution land/lake data set. For maps of this scale you are probably better off using map tiles instead of the NaturalEarth land feature. There are several choices already available in cartopy, Stamen Terrain or Open Street Map might be good choices:
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.io.shapereader import Reader
from cartopy.io.img_tiles import StamenTerrain, OSM
standard_parallels = (49, 77)
central_longitude = -(91 + 52 / 60)
data = Reader('citygcs')
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1,
projection=ccrs.LambertConformal(central_longitude=central_longitude,
standard_parallels=standard_parallels))
ax.set_extent([-79.65, -79.1, 43.57, 43.87])
tiler = OSM()
ax.add_image(tiler, 10)
ax.add_geometries(data.geometries(), crs=ccrs.Geodetic(), edgecolor='k',
facecolor='none')
plt.show()
Or using StamenTerrain:
There may be further issues regarding referencing ellipse (I notice WGS84 in the shapefile name), there is a good reference here: https://scitools.org.uk/cartopy/docs/v0.16/gallery/effects_of_the_ellipse.html.
In future it would help if your code example is minimal and all data is available (I had to go and find a similar shapefile myself to reproduce), see here for a guide: https://stackoverflow.com/help/mcve.
I am trying to plot contours over the north pole, using cartopy. I have used add_cyclic_point and this has successfully filled in the gap at the prime meridian in pcolormesh, but the contours do not cross successfully, and instead wrap all the way around the globe to connect (but it seems not always?) My longitudes go from 0-360 and I have tried to switch to -180-180 but still get the same issue.
Here is my code:
import numpy as np
from netCDF4 import Dataset
import cartopy.crs as ccrs
import cartopy
from cartopy.util import add_cyclic_point as cycpt
import matplotlib.pyplot as plt
date = '2018_02_10'
pdatafile = Dataset(date+'_mslp.nc')
plat = np.array(pdatafile.variables['lat'])
plon = np.array(pdatafile.variables['lon'])
p = np.array(pdatafile.variables['slp'][0,:,:])
p_cyclic,lon_cyclic = cycpt(p,coord=plon)
lon_cyclic = np.ma.getdata(lon_cyclic)
plon2d,plat2d= np.meshgrid(lon_cyclic,plat)
p_cyclic = np.ma.getdata(p_cyclic)
g1000datafile = Dataset(date+'_1000mb_gph.nc')
g1lat = np.array(g1000datafile.variables['lat'])
g1lon = np.array(g1000datafile.variables['lon'])
g1000 = np.array(g1000datafile.variables['hgt'][0,0,:,:])
g1_cyclic,g1lon_cyclic = cycpt(g1000,coord=g1lon)
g1lon2d,g1lat2d= np.meshgrid(g1lon_cyclic,g1lat)
g1lon2d = np.ma.getdata(g1lon2d)
g1_cyclic = np.ma.getdata(g1_cyclic)
g500datafile = Dataset(date+'_500mb_gph.nc')
g5lat = np.array(g500datafile.variables['lat'])
g5lon = np.array(g500datafile.variables['lon'])
g500 = np.array(g500datafile.variables['hgt'][0,0,:,:])
g5_cyclic,g5lon_cyclic = cycpt(g500,coord=g5lon)
g5lon2d,g5lat2d= np.meshgrid(g5lon_cyclic,g5lat)
g5lon2d = np.ma.getdata(g5lon2d)
g5_cyclic = np.ma.getdata(g5_cyclic)
thickness = g5_cyclic - g1_cyclic
mslplevels=[960,970,980,990,1000,1010,1020,1030,1040,1050]
levels500hPa = [470,480,490,500,510,520,530,540,550,560]
ax = plt.axes(projection=ccrs.NorthPolarStereo(central_longitude=0))
ax.set_extent([-180, 180, 50, 90], crs=ccrs.PlateCarree())
plt.pcolormesh(plon2d,plat2d,thickness/10, transform=ccrs.PlateCarre(),cmap='inferno')
cbar=plt.colorbar()
cbar.set_label('ReTop (gpdam)')
cs=plt.contour(plon2d,plat2d,g5_cyclic/10,colors='w',transform=ccrs.PlateCarree(),\
levels=levels500hPa)
plt.clabel(cs,inline=1,fontsize=6,fmt='%3.0f')
ax.coastlines()
plt.show()
plt.close()
an example plot
import numpy as np
from netCDF4 import Dataset
import cartopy.crs as ccrs
from cartopy.util import add_cyclic_point as cycpt
import matplotlib.pyplot as plt
pdatafile = Dataset('X158.39.88.89.59.7.59.32.nc')
plat = np.array(pdatafile.variables['lat'])
plon = np.array(pdatafile.variables['lon'])
p = np.array(pdatafile.variables['slp'][0,:,:])
p_cyclic,lon_cyclic = cycpt(p,coord=plon)
lon_cyclic = np.ma.getdata(lon_cyclic)
p_cyclic = np.ma.getdata(p_cyclic)
plon2d,plat2d= np.meshgrid(lon_cyclic,plat)
ax = plt.axes(projection=ccrs.NorthPolarStereo(central_longitude=0))
ax.set_extent([-180, 180, 50, 90], crs=ccrs.PlateCarree())
plt.contour(plon2d,plat2d,g5_cyclic/10,colors='w',transform=ccrs.PlateCarree())
plt.clabel(cs,inline=1,fontsize=6,fmt='%3.0f')
ax.coastlines()
plt.show()
ftp://ftp.cdc.noaa.gov/Public/www/X158.39.88.89.59.7.59.32.nc
I suspect the problem is to do with contour labels, which are known not to work well in Cartopy (see https://github.com/SciTools/cartopy/issues/13 and https://github.com/SciTools/cartopy/issues/327). If you remove the labels the contours should render correctly.
I'm a cartopy developer and I'd like to see what I can do, but your code snippet is a little bit impenetrable. If I could access your data then it might not matter so much, but I can't, so I can't run it or debug it.
Can you cut down your script please to something self-contained or at least minimal, noiseless and clear. Thanks.
Also you have a typo in your plot call so your transform is PlateCarre instead of Platecarree. I don't know how much difference this will make but it's worth correcting.