Search code examples
pythonmatplotlibpython-xarraycartopy

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:

correct spatial map of temperature changes

But this happens when I instead perform the time average from 0 to 131:

incorrect spatial map of temperature changes

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!


Solution

  • 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()