Trouble plotting quivers from netcdf file - python

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!

Related

Set plt.colorbar range with python/cartopy

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)

Why does adding a legend in this cartopy projection figure significantly increase the execution time (and how can fix this)?

So I have written a script for making figures that worked alright (see mock-up example below). But when I add a legend to the figure, the execution time increases a lot. I don't really understand what is happening here, I would naively expect that simply adding a legend is not a complex thing.
I suspect this has something to do with the cartopy projection, since it works alright if I don't use this.
What is the problem here, and how can I avoid this?
Problematic code:
import numpy as np
import xarray as xr
import matplotlib
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
# Mockup dataset
num = 300
lat = np.linspace(-54,-59,num=num)
lon = np.linspace(-5,5, num=num)
data = np.outer(lat,lon)
ds = xr.DataArray(data=data,
dims=["lat", "lon"],
coords=dict(lon=lon, lat=lat))
# Map projection
map_proj = ccrs.SouthPolarStereo()
ax = plt.axes(projection=map_proj)
ax.gridlines(draw_labels=True)
ax.set_extent([-3,4,-58,-54])
# Plot image
ds.plot(cmap="gray",
add_colorbar=False,
transform=ccrs.PlateCarree(), # data projection
subplot_kws={'projection': map_proj}) # map projection
# Plot contours
cs = ds.plot.contour(transform=ccrs.PlateCarree())
# Make legend
proxy = [matplotlib.lines.Line2D([],[], c=pc.get_color()[0]) for pc in cs.collections]
labels = ["foo"] * len(cs.collections)
plt.legend(proxy, labels)
Code without cartopy projection:
import numpy as np
import xarray as xr
import matplotlib
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
# Mockup dataset
num = 300
lat = np.linspace(-54,-59,num=num)
lon = np.linspace(-5,5, num=num)
data = np.outer(lat,lon)
ds = xr.DataArray(data=data,
dims=["lat", "lon"],
coords=dict(lon=lon, lat=lat))
# Plot image
ds.plot(cmap="gray",
add_colorbar=False) # map projection
# Plot contours
cs = ds.plot.contour()
# Make legend
proxy = [matplotlib.lines.Line2D([],[], c=pc.get_color()[0]) for pc in cs.collections]
plt.legend(proxy, labels)
plt.legend(proxy, labels) defaults to loc='best' which uses an algorithm that can be slow if you have lots of data in your axes, and particularly slow if that data also has complicated transforms. Instead do ax.legend(proxy, labels, loc='upper right') manually. See https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.legend.html

Why can't I use cartopy to plot certain time averages of the same dataset?

I have a 3-dimensional xarray DataArray of changes in surface temperature with coordinates of time, lat and lon. I am visualizing the data using Cartopy. You can find the 125 MB file here.
While producing plots of time-averages over different periods, I've found that I'm unable to produce orthographic projections when including certain time steps, such as the 132nd (index 131) time. Here is a plot of the time average from 0 to 130:
But this happens when I instead perform the time average from 0 to 131:
Here is the code I used to produce the plots:
# import statements
import cartopy.crs as ccrs
import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
from cartopy.util import add_cyclic_point
%matplotlib inline
%config InlineBackend.figure_format = "jpg"
# read in data
ens_mean = xr.open_dataarray('temp_changes_ens_mean.nc')
# time average subset of data
to_plot = ens_mean.isel(time=slice(None,131)).mean(dim='time') # change 130 to 131 to break cartopy
# add cyclic point to avoid white lines
data = to_plot
lon = to_plot.coords['lon']
lon_idx = data.dims.index('lon')
wrap_data, wrap_lon = add_cyclic_point(data.values, coord=lon, axis=lon_idx)
# make an orthographic plot centered on north pole
fig = plt.figure(figsize=(4.5,3.5))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Orthographic(0, 90))
ax.coastlines()
im = ax.contourf(wrap_lon, to_plot.lat, wrap_data,
transform=ccrs.PlateCarree())
# add colorbar
cb = fig.colorbar(im,orientation='horizontal',shrink=0.5,pad=0.05)
cb.ax.tick_params(labelsize=8)
cb.set_label('ΔSAT (K)',fontsize=8)
plt.tight_layout(w_pad=0.05)
plt.show()
This occurs whether I add a cyclic point or not. I am able to make quick plots of the data using matplotlib or xarray's built-in plotting without error. I've already checked for NaN values in the data. Lastly, if I remove the transform argument in the contourf line, it is able to produce a coherent plot, which leads me to think it is the transformation step that produces this odd plot.
Thanks for the help!
You can use ax.set_global() method to reset the coordinate limits:
#!/usr/bin/env ipython
# --------------------------------------------
import cartopy.crs as ccrs
import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
from cartopy.util import add_cyclic_point
# --------------------------------------------------------------------------------------
#%matplotlib inline
#%config InlineBackend.figure_format = "jpg"
# read in data
ens_mean = xr.open_dataarray('temp_changes_ens_mean.nc')
# time average subset of data
to_plot = ens_mean.isel(time=slice(None,131)).mean(dim='time') # change 130 to 131 to break cartopy
# add cyclic point to avoid white lines
data = to_plot
lon = to_plot.coords['lon']
lon_idx = data.dims.index('lon')
wrap_data, wrap_lon = add_cyclic_point(data.values, coord=lon, axis=lon_idx)
# ------------------------------------------------------------------
# this is not working:
xlims = (np.min(ens_mean['lon']),np.max(ens_mean['lon']));
ylims = (np.min(ens_mean['lat']),np.max(ens_mean['lat']));
# ------------------------------------------------------------------
lon = to_plot.coords['lon']
# ====================================================================================
# make an orthographic plot centered on north pole
# Let us make a working/satisfying plot:
fig = plt.figure(figsize=(4.5,3.5))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Orthographic(0, 90))
ax.coastlines()
im = ax.contourf(wrap_lon, to_plot.lat, wrap_data,
transform=ccrs.PlateCarree())
# -----------------------------------------------------------
# add colorbar
cb = fig.colorbar(im,orientation='horizontal',shrink=0.5,pad=0.05)
cb.ax.tick_params(labelsize=8)
cb.set_label('ΔSAT (K)',fontsize=8)
plt.tight_layout(w_pad=0.05)
ax.set_global();
#ax.set_xlim(xlims);
#ax.set_ylim(ylims);
plt.show()

Visualizing netCDFs xarray

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

Avoid interpolation of data when plotting map using latitude and longitude instead of provided x-y coordinates

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).

Categories

Resources