Python unstructured ICON triangles plot with vectors (python 3)#
Software requirements:
Python 3
Numpy
matplotlib
cartopy
xarray
Example script#
DKRZ_example_ICON_triangles_uas_vas_quiver.py
#!/usr/bin/env python
# coding: utf-8
'''
DKRZ example
Draw sub-area of ICON data and add vectors
Content
- ICON model data
- variable 'tas', 'uas', 'vas'
- use cell vertices
- add colorbar
- use gadm36_DEU shapefile to draw state lines
- draw location of Marburg
-------------------------------------------------------------------------------
2021 copyright DKRZ licensed under CC BY-NC-SA 4.0 <br>
(https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)
-------------------------------------------------------------------------------'''
import time, os
import xarray as xr
import numpy as np
import numpy.ma as ma
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.tri as tri
from matplotlib.collections import PolyCollection
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import cartopy.io.shapereader as shpreader
def main():
plt.switch_backend('agg')
t1 = time.time() #-- retrieve start time
print('')
#-- set color map
colormap = 'RdYlBu_r'
#-- set title string
title = 'ICON temperature data'
#-- define path, file and variable name
fname = '../../data/icon_atmo.nc'
varName = 'tas'
uName = 'uas'
vName = 'vas'
#-- open dataset
ds = xr.open_dataset(fname)
#-- get missing_value
try:
missing_value = ds[varName].encoding['missing_value']
except:
print('Warning: no missing_value/_FillValue defined!')
#-- get variable
var = ds[varName][0,:].values
var = var - 273.15
u = ds[uName][0,:].values
v = ds[vName][0,:].values
vec_units = ds[uName].units
#-- get coordinates and convert radians to degrees
clon = np.rad2deg(ds.clon.values)
clat = np.rad2deg(ds.clat.values)
clon_vertices = np.rad2deg(ds.clon_bnds.values)
clat_vertices = np.rad2deg(ds.clat_bnds.values)
ncells, nv = clon_vertices.shape[0], clon_vertices.shape[1]
#-- set contour levels, labels
varMin, varMax, varInt = 0., 6., 0.5
levels = np.arange(varMin, varMax+varInt, varInt)
nlevs = levels.size
labels = ['{:.2f}'.format(x) for x in levels]
#-- print information to stdout
print('')
print('Cells: %6d ' % clon.size)
print('Variable min/max: %6.2f ' % np.nanmin(var)+'/'+' %.2f' % np.nanmax(var))
print('Contour min/max: %6.2f ' % varMin+'/'+' %.2f' % varMax)
print('')
#-- set projection
projection = ccrs.PlateCarree()
#-- create figure and axes instances; we need subplots for plot and colorbar
fig, ax = plt.subplots(figsize=(12,11), subplot_kw=dict(projection=projection))
bg = [0.8, 0.8, 0.8, 1.0]
ax.set_facecolor(bg)
ax.set_extent([7.95, 10.05, 49.95, 52.05], crs=ccrs.PlateCarree())
#-- plot land areas at last to get rid of the contour lines at land
ax.coastlines(linewidth=0.5)
gl = ax.gridlines(draw_labels=True, linewidth=0.5, color='dimgray',
alpha=0.4, zorder=3)
gl.xlabel_style = {'size':7}
gl.ylabel_style = {'size':7}
gl.top_labels = False
gl.right_labels = False
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER
#-- plot the title string
plt.title(title, fontsize=16)
#-- define color map
cmap = plt.get_cmap(colormap, nlevs) #-- read the color map
cmaplist = [i for i in range(cmap.N)] #-- color bar indices
ncol = len(cmaplist) #-- number of colors
colors = np.ndarray([ncells,4], np.float32) #-- assign color array for triangles
#-- preset all colors elements to black
colors[:,0] = 0.8
colors[:,1] = 0.8
colors[:,2] = 0.8
colors[:,3] = 1.
print('levels: ',levels)
print('nlevs: %3d' %nlevs)
print('ncol: %3d' %ncol)
print('')
#-- set color index of all cells in between levels
for m in range(0,ncol-1):
vind = []
for i in range(0,ncells-2, 1):
if (var[i] >= levels[m] and var[i] < levels[m+1]):
colors[i,:] = cmap(cmaplist[m])
vind.append(i)
print('set colors: finished level %3d' % m , ' -- %5d ' % len(vind) , ' polygons considered')
del vind
colors[np.where(var < varMin),:] = cmap(cmaplist[0])
colors[np.where(var >= varMax),:] = cmap(cmaplist[ncol-1])
#-- create the triangles
clon_vertices = np.where(clon_vertices < -180., clon_vertices + 360., clon_vertices)
clon_vertices = np.where(clon_vertices > 180., clon_vertices - 360., clon_vertices)
triangles = np.zeros((ncells, nv, 2), np.float32)
for i in range(0, ncells, 1):
triangles[i,:,0] = np.array(clon_vertices[i,:])
triangles[i,:,1] = np.array(clat_vertices[i,:])
print('')
print('--> triangles done')
#-- create polygon/triangle collection
coll = PolyCollection(triangles, array=None,
fc=colors,
edgecolors='none',
linewidth=0.05,
transform=ccrs.Geodetic())
ax.add_collection(coll)
print('--> polygon collection done')
#-- vectors
vplot = ax.quiver(clon, clat, u, v,
width=0.003,
headwidth=4.,
headlength=5.,
units='xy',
color='black',
transform=ccrs.PlateCarree())
vec_ref = ax.quiverkey(vplot, 0.92, 0.84, 2,
r'$2 \frac{m}{s}$',
labelpos='E',
labelsep=0.05,
coordinates='figure')
#-- add States of Germany from shapefile
shpname = '../../data/gadm36_DEU_1.shp'
adm1_shapes = list(shpreader.Reader(shpname).geometries())
ax.add_geometries(adm1_shapes,
ccrs.PlateCarree(),
linewidth=1,
edgecolor='black',
facecolor='none',
alpha=0.5)
#-- mark location of Marburg
ax.plot(8.7667, 50.8167,
marker='.',
color='white',
markersize=12,
markeredgecolor='black',
transform=ccrs.Geodetic())
ax.text(8.8, 50.8167, 'Marburg',
fontsize=16,
fontweight='bold',
horizontalalignment='center',
verticalalignment='top',
transform=ccrs.Geodetic())
#-- add a color bar
cax = fig.add_axes([0.91, 0.165, 0.02, 0.65], autoscalex_on=True) #-- x,y,w,h
bounds = [0., 0.5, 0.75, 1., 1.5, 2., 3., 4., 5., 6.]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N, extend='both')
cbar = fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap),
cax=cax,
orientation='vertical',
ticks=levels,
boundaries=levels,
format='%3.1f')
#plt.setp(cbar.ax.get_xticklabels()[::2], visible=False)
cbar.set_label('[deg C]')
#-- add text 'missing = black'
ax.annotate('gray = missing',
xy=(.83, .08),
xycoords='figure fraction',
horizontalalignment='right',
verticalalignment='top',
fontsize=6)
#-- maximize and save the PNG file
plt.savefig('plot_ICON_tas_triangles_uas_vas_quiver.png', bbox_inches='tight',dpi=100)
#-- get wallclock time
t2 = time.time()
print('Wallclock time: %0.3f seconds' % (t2-t1))
print('')
if __name__ == '__main__':
main()
Result: