Salem¶
Salem is a small library to do geoscientific data processing and plotting. It extends xarray to add geolocalised subsetting, masking, and plotting operations to xarray’s DataArray and DataSet structures.
Warning
Salem is at an early development stage, and its API might change in the future. See Examples for a quick overview of Salem’s functionalities, and see also the Frequently Asked Questions for more information and a list of related tools.
Documentation¶
Examples¶
Subsetting and selecting data¶
Let’s open a WRF model output file:
In [1]: import salem
In [2]: from salem.utils import get_demo_file
In [3]: ds = salem.open_xr_dataset(get_demo_file('wrfout_d01.nc'))
Let’s take a time slice of the variable T2
for a start:
In [4]: t2 = ds.T2.isel(Time=2)
In [5]: t2.salem.quick_map()
Out[5]: <salem.graphics.Map at 0x7ff13ddc9908>

Although we are on a Lambert Conformal projection, it’s possible to subset the file using longitudes and latitudes:
In [6]: t2_sub = t2.salem.subset(corners=((77., 20.), (97., 35.)), crs=salem.wgs84)
In [7]: t2_sub.salem.quick_map()
Out[7]: <salem.graphics.Map at 0x7ff13da00ef0>

It’s also possible to use geometries or shapefiles to subset your data:
In [8]: shdf = salem.read_shapefile(get_demo_file('world_borders.shp'))
In [9]: shdf = shdf.loc[shdf['CNTRY_NAME'].isin(['Nepal', 'Bhutan'])] # GeoPandas' GeoDataFrame
In [10]: t2_sub = t2_sub.salem.subset(shape=shdf, margin=2) # add 2 grid points
In [11]: t2_sub.salem.quick_map()
Out[11]: <salem.graphics.Map at 0x7ff13dd8f518>

Based on the same principle, one can mask out the useless grid points:
In [12]: t2_roi = t2_sub.salem.roi(shape=shdf)
In [13]: t2_roi.salem.quick_map()
Out[13]: <salem.graphics.Map at 0x7ff13dfeb320>

Plotting¶
Maps can be pimped with topographical shading, points of interest, and more:
In [14]: smap = t2_roi.salem.get_map(data=t2_roi-273.15, cmap='RdYlBu_r', vmin=-14, vmax=18)
In [15]: _ = smap.set_topography(get_demo_file('himalaya.tif'))
In [16]: smap.set_shapefile(shape=shdf, color='grey', linewidth=3)
In [17]: smap.set_points(91.1, 29.6)
In [18]: smap.set_text(91.2, 29.7, 'Lhasa', fontsize=17)
In [19]: smap.visualize()

Maps are persistent, which is useful when you have many plots to do. Plotting further data on them is possible, as long as the geolocalisation information is shipped with the data (in that case, the DataArray’s attributes are lost in the conversion from Kelvins to degrees Celsius so we have to set it explicitly):
In [20]: smap.set_data(ds.T2.isel(Time=1)-273.15, crs=ds.salem.grid)
In [21]: smap.visualize(title='2m temp - large domain', cbar_title='C')

Reprojecting data¶
Salem can also transform data from one grid to another:
In [22]: dse = salem.open_xr_dataset(get_demo_file('era_interim_tibet.nc'))
In [23]: t2_era_reproj = ds.salem.transform(dse.t2m)
In [24]: assert t2_era_reproj.salem.grid == ds.salem.grid
In [25]: t2_era_reproj.isel(time=0).salem.quick_map()
Out[25]: <salem.graphics.Map at 0x7ff13d9e1b00>

In [26]: t2_era_reproj = ds.salem.transform(dse.t2m, interp='spline')
In [27]: t2_era_reproj.isel(time=0).salem.quick_map()
Out[27]: <salem.graphics.Map at 0x7ff13e309860>

Frequently Asked Questions¶
Is your library mature for production code?¶
Not really. The API is not always as clever as I wish it would, and it will probably change in the future. Salem is well tested though, at least for the cases I encounter in my daily work.
What others tools should I know about?¶
The python atmospheric sciences community is a bit spread between iris and xarray for N-Dimensional data handling. I find that xarray is very intuitive to learn thanks to its strong interaction with pandas.
Here are some tools that share functionalities with Salem:
- cartopy is the reference tool for plotting on maps. Salem provides a way to plot with cartopy in addition to Salem’s homegrowm graphics. (see Graphics)
- Salem provides useful reprojection tools (see Map transformations). The transformation routines are quite fast (we use pyproj for the map transformations and scipy for the interpolation) but they are all done on memory (i.e. not adapted for large datasets). For large reprojection workflows you might want to have a look at cartopy and pyresample.
- regionmask provides similar tools as salem’s region-of-interest functionalities if you are woking with shapefiles. regionmask seems a bit more general than Salem, but I’m not sure if it works with any map projection as Salem does.
- In the future, I hope that pangeo-data will overtake most of the functionalities I need. But this is not going to happen tomorrow...
Several libraries are available to meteorologists and climatologists, but I don’t think they share much functionality with Salem: for example MetPy, windspharm, xgcm, aospy, and all the ones I forgot to mention.
Why developing Salem?¶
As an atmospheric scientist, I hate to have to take care about projections and maps. Salem was created to hide all these concerns. By the time I started, it seemed a good idea to provide map transformation tools without depending on GDAL (thanks to conda-forge GDAL is now much easier to install). It is still possible to do reprojection work in Salem using scipy and pyproj alone.
Furthermore, I use the atmospheric model WRF quite often in my work. Its output files are absolutely not compliant with the CF conventions. To my knowledge, there is no tool to plot and manipulate WRF data with Python, and Salem will be further developed with this model in mind.
What’s this ”.salem_cache” directory in my home folder?¶
At the first import, Salem will create a hidden directory called
.salem_cache
in your home folder. It will be used to download Salem’s
demo files and standard shapefiles. This directory is also used by
joblib to store the result of slow operations such as reading and
transforming shapefiles, or downloading google maps from the internet. The
cache should not become too large, but if it does: simply delete it.
What’s New¶
v0.2.1 (07 February 2017)¶
Minor release containing a couple of enhancements and deprecations, but mostly fixes for bugs and for the recent xarray and matplotlib upgrades.
Deprecations¶
- the
corner
,ul_corner
, andll_corner
kwargs to grid initialisation have been deprecated in favor of the more explicitx0y0
. - the Grid attribue
order
is now calledorigin
, and can have the values"lower-left"
or"upper-left"
salem.open_xr_dataset
now succeeds if and only if the grid is understood by salem. This makes more sense, as unexpected errors should not be silently ignored
Enhancements¶
- new
open_mf_wrf_dataset()
function - new
deacc
method added to DataArrayAccessors By SiMaria <https://github.com/SiMaria> - new
Map.transform()
method to make over-plotting easier (experimental) - new all_touched argument added to
Grid.region_of_interest()
to pass through torasterio.features.rasterize
, tweaking how grid cells are included in the region of interest. By Daniel Rothenberg - new
lookup_transform()
projection transform Grid
objects now have a decent__repr__
- new serialization methods for grid:
to_dict
,from_dict
,to_json
,from_json
.
Bug fixes¶
grid.transform()
now works with non-numpy array typetransform_geopandas()
won’t do inplace operation per default anymore- fixed bugs to prepare for upcoming xarray v0.9.0
setup.py
makes cleaner version strings for development versions (like xarray’s)- joblib’s caching directory is now “environment dependant” in order to avoid conda/not conda mismatches, and avoid other black-magic curses related to caching.
- fixed a bug with opening geo_em files using xarray or open_wrf_dataset
- various bug fixes and enhancements to the graphics (including the relocation of testing baseline images to the demo repo)
v0.2.0 (08 November 2016)¶
Salem is now released under a 3-clause BSD license.
Enhancements¶
- New
wrf_zlevel()
andwrf_plevel()
functions for vertical interpolation - Salem can now plot on cartopy’s maps thanks to a new
proj_to_cartopy()
function. - Doc improvements
- New diagnostic variable: ‘WS’
v0.1.1 (27 October 2016)¶
Enhancements¶
- Some doc improvements
- New
ds
keyword to the accessorssubset()
androi()
methods
Bug fixes¶
- Natural Earth file lr (low-res) now shipped with sample-data, mr and hr can still be downloaded if needed
- Remove use to deprecated
rasterio.drivers()
- GeoNetCDF files without time variable should now open without error
v0.1.0 (22 October 2016)¶
Big refactoring (PR15), partly backwards incompatible (mostly renaming). Improved xarray accessors, WRF tools, merged Cleo into the codebase, added a first draft of documentation.
v0.0.9 (22 October 2016)¶
Initial release.
Installation¶
Salem is a pure python package, but it has several non-trivial dependencies.
Required dependencies¶
Optional dependencies¶
Because not using them is a bad idea¶
For vector and raster operations¶
(rasterio and geopandas both require GDAL)
For plotting¶
- matplotlib: required for Graphics
- pillow: required for salem.Map
- descartes: for paths and patches on maps
- motionless: for google static maps
Instructions¶
The very best (unique?) way to install Salem without too much hassle is to install its dependencies with conda and conda-forge:
conda config --add channels conda-forge
conda install <package-name>
Currently, Salem can only be installed via pip:
pip install salem
If you want to install the latest master:
pip install git+https://github.com/fmaussion/salem.git
Warning
At the first import, Salem will create a hidden directory called
.salem_cache
in your home folder. It will be used to download Salem’s
demo files and standard shapefiles. This directory is also used by
joblib to store the result of slow operations such as reading and
transforming shapefiles, or downloading google maps from the internet. The
cache should not become too large, but if it does: simply delete it.
Xarray accessors¶
One of the main purposes of Salem is to add georeferencing tools to
xarray ‘s data structures. These tools can be accessed via a special
.salem
attribute, available for both xarray.DataArray and
xarray.Dataset objects after a simple import salem
in your code.
Initializing the accessor¶
Automated projection parsing¶
Salem will try to understand in which projection your Dataset or DataArray is defined. For example, with a platte carree (or lon/lat) projection, Salem will know what to do based on the coordinates’ names:
In [1]: import numpy as np
In [2]: import xarray as xr
In [3]: import salem
In [4]: da = xr.DataArray(np.arange(20).reshape(4, 5), dims=['lat', 'lon'],
...: coords={'lat':np.linspace(0, 30, 4),
...: 'lon':np.linspace(-20, 20, 5)})
...:
In [5]: da.salem # the accessor is an object
Out[5]: <salem.sio.DataArrayAccessor at 0x7ff13d7b7fd0>
In [6]: da.salem.quick_map();

While the above should work with a majority of climate datasets (such as atmospheric reanalyses or GCM output), certain NetCDF files will have a more exotic map projection requiring a dedicated parsing. There are conventions to formalise these things in the NetCDF data model, but Salem doesn’t understand them yet (my impression is that they aren’t widely used anyways).
Currently, Salem can deal with:
- platte carree (or lon/lat) projections
- WRF projections (see WRF tools)
- for geotiff files only: any projection that rasterio can understand
- virually any projection provided explicitly by the user
The logic for deciding upon the projection of a Dataset or DataArray is
located in grid_from_dataset()
. If the automated parsing
doesn’t work, the salem
accessor won’t work either. In that case, you’ll
have to provide your own Custom projection to the data.
From geotiffs¶
Salem uses rasterio to open and parse geotiff files:
In [7]: fpath = salem.get_demo_file('himalaya.tif')
In [8]: ds = salem.open_xr_dataset(fpath)
In [9]: hmap = ds.salem.get_map(cmap='topo')
In [10]: hmap.set_data(ds['data'])
In [11]: hmap.visualize();

Custom projection¶
Alternatively, Salem will understand any projection supported by pyproj. The proj info has to be provided as attribute:
In [12]: dutm = xr.DataArray(np.arange(20).reshape(4, 5), dims=['y', 'x'],
....: coords={'y': np.arange(3, 7)*2e5,
....: 'x': np.arange(1, 6)*2e5})
....:
In [13]: psrs = 'epsg:32630' # http://spatialreference.org/ref/epsg/wgs-84-utm-zone-30n/
In [14]: dutm.attrs['pyproj_srs'] = psrs
In [15]: dutm.salem.quick_map(interp='linear');

Using the accessor¶
The accessor’s methods are available trough the .salem
attribute.
Keeping track of attributes¶
Some datasets carry their georeferencing information in global attributes (WRF
model output files for example). This makes it possible for Salem to
determine the data’s map projection. From the variables alone,
however, this is not possible. This is the reason why it is recommended to
use the open_xr_dataset()
and
open_wrf_dataset()
function, which add
an attribute to the variables automatically:
In [16]: dsw = salem.open_xr_dataset(salem.get_demo_file('wrfout_d01.nc'))
In [17]: dsw.T2.pyproj_srs
Out[17]: '+units=m +proj=lcc +lat_1=29.040000915527344 +lat_2=29.040000915527344 +lat_0=29.039997100830078 +lon_0=89.80000305175781 +x_0=0 +y_0=0 +a=6370000 +b=6370000'
Unfortunately, the DataArray attributes are lost when doing operations on them. It is the task of the user to keep track of this attribute:
In [18]: dsw.T2.mean(dim='Time', keep_attrs=True).salem # triggers an error without keep_attrs
Out[18]: <salem.sio.DataArrayAccessor at 0x7ff13c5de470>
Reprojecting data¶
You can reproject a Dataset onto another one with the
transform()
function:
In [19]: dse = salem.open_xr_dataset(salem.get_demo_file('era_interim_tibet.nc'))
In [20]: dsr = ds.salem.transform(dse)
In [21]: dsr
Out[21]:
<xarray.Dataset>
Dimensions: (time: 4, x: 1875, y: 877)
Coordinates:
* y (y) float64 31.54 31.53 31.52 31.52 31.51 31.5 31.49 31.48 ...
* time (time) datetime64[ns] 2012-06-01 2012-06-01T06:00:00 ...
* x (x) float64 78.32 78.33 78.33 78.34 78.35 78.36 78.37 78.38 ...
Data variables:
t2m (time, y, x) float64 278.6 278.6 278.6 278.6 278.6 278.6 278.6 ...
Attributes:
pyproj_srs: +units=m +init=epsg:4326
In [22]: dsr.t2m.mean(dim='time').salem.quick_map();

Currently, salem implements, the neirest neighbor (default), linear, and spline interpolation methods:
In [23]: dsr = ds.salem.transform(dse, interp='spline')
In [24]: dsr.t2m.mean(dim='time').salem.quick_map();

The accessor’s map transformation machinery is handled by the
Grid
class internally. See Map transformations for more information.
Subsetting data¶
The subset()
function allows you to subset
your datasets according to (georeferenced) vector or raster data, for example
based on shapely geometries
(e.g. polygons), other grids, or shapefiles:
In [25]: shdf = salem.read_shapefile(salem.get_demo_file('world_borders.shp'))
In [26]: shdf = shdf.loc[shdf['CNTRY_NAME'] == 'Nepal'] # remove other countries
In [27]: dsr = dsr.salem.subset(shape=shdf, margin=10)
In [28]: dsr.t2m.mean(dim='time').salem.quick_map();

Graphics¶
Two options are offered to you when plotting geolocalised data on maps:
you can use cartopy , or you can use salem’s Map
object.
Plotting with cartopy¶
Plotting on maps using xarray and cartopy is extremely convenient.
With salem you can keep your usual plotting workflow, even with more exotic map projections:
In [1]: import matplotlib.pyplot as plt
In [2]: import cartopy
In [3]: from salem import open_wrf_dataset, get_demo_file
In [4]: ds = open_wrf_dataset(get_demo_file('wrfout_d01.nc'))
In [5]: ax = plt.axes(projection=cartopy.crs.Orthographic(70, 30))
In [6]: ax.set_global();
In [7]: ds.T2C.isel(time=1).plot.contourf(ax=ax, transform=ds.salem.cartopy());
In [8]: ax.coastlines();

You can also use the salem accessor to initialise the plot’s map projection:
In [9]: proj = ds.salem.cartopy()
In [10]: ax = plt.axes(projection=proj)
In [11]: ax.coastlines();
In [12]: ax.add_feature(cartopy.feature.BORDERS, linestyle=':');
In [13]: ax.set_extent(ds.salem.grid.extent, crs=proj);

Plotting with salem¶
Salem comes with a homegrown plotting tool. It is less flexible than cartopy, but it was created to overcome some of cartopy’s limitations (e.g. the impossibility to add tick labels to lambert conformal maps), and to make nice looking regional maps:
In [14]: ds.T2C.isel(time=1).salem.quick_map()
Out[14]: <salem.graphics.Map at 0x7ff13d6a3518>

Salem maps are different from cartopy’s in that they don’t change the matplotlib axes’ projection. The map background is always going to be a call to imshow(), with an image size decided at instanciation:
In [15]: from salem import mercator_grid, Map, open_xr_dataset
In [16]: grid = mercator_grid(center_ll=(10.76, 46.79), extent=(9e5, 4e5))
In [17]: grid.nx, grid.ny # size of the input grid
Out[17]: (1350, 600)
In [18]: smap = Map(grid, nx=500)
In [19]: smap.grid.nx, smap.grid.ny # size of the "image", and thus of the axes
Out[19]: (500, 222)
In [20]: smap.visualize(addcbar=False)

The map has it’s own grid, wich is used internally in order to transform the data that has to be plotted on it:
In [21]: ds = open_xr_dataset(get_demo_file('histalp_avg_1961-1990.nc'))
In [22]: smap.set_data(ds.prcp) # histalp is a lon/lat dataset
In [23]: smap.visualize()

Refer to Recipes for more examples on how to use salem’s maps.
WRF tools¶
Let’s open a WRF model output file with xarray first:
In [1]: import xarray as xr
In [2]: from salem.utils import get_demo_file
In [3]: ds = xr.open_dataset(get_demo_file('wrfout_d01.nc'))
WRF files are a bit messy:
In [4]: ds
Out[4]:
<xarray.Dataset>
Dimensions: (Time: 3, bottom_top: 27, bottom_top_stag: 28, south_north: 150, south_north_stag: 151, west_east: 150, west_east_stag: 151)
Coordinates:
XLONG (Time, south_north, west_east) float32 70.7231 70.9749 71.2267 ...
XLONG_U (Time, south_north, west_east_stag) float32 70.5974 70.849 ...
XLAT_U (Time, south_north, west_east_stag) float32 7.76865 7.80933 ...
XLAT_V (Time, south_north_stag, west_east) float32 7.66444 7.70477 ...
XLONG_V (Time, south_north_stag, west_east) float32 70.7436 70.9951 ...
XLAT (Time, south_north, west_east) float32 7.78907 7.82944 7.86932 ...
Dimensions without coordinates: Time, bottom_top, bottom_top_stag, south_north, south_north_stag, west_east, west_east_stag
Data variables:
Times (Time) |S19 b'2008-10-26_12:00:00' b'2008-10-26_15:00:00' ...
T2 (Time, south_north, west_east) float32 301.977 302.008 302.047 ...
RAINC (Time, south_north, west_east) float32 0.0 0.0 0.0 0.0 0.0 0.0 ...
RAINNC (Time, south_north, west_east) float32 0.0 0.0 0.0 0.0 0.0 0.0 ...
U (Time, bottom_top, south_north, west_east_stag) float32 1.59375 ...
V (Time, bottom_top, south_north_stag, west_east) float32 -2.07031 ...
PH (Time, bottom_top_stag, south_north, west_east) float32 0.0 0.0 ...
PHB (Time, bottom_top_stag, south_north, west_east) float32 0.0 0.0 ...
Attributes:
note: Global attrs removed.
WRF files aren’t exactly CF compliant: you’ll need a special parser for the timestamp, the coordinate names are a bit exotic and do not correspond to the dimension names, they contain so-called staggered variables (and their correponding coordinates), etc.
Salem defines a special parser for these files:
In [5]: import salem
In [6]: ds = salem.open_wrf_dataset(get_demo_file('wrfout_d01.nc'))
This parser greatly simplifies the file structure:
In [7]: ds
Out[7]:
<xarray.Dataset>
Dimensions: (bottom_top: 27, south_north: 150, time: 3, west_east: 150)
Coordinates:
lon (south_north, west_east) float32 70.7231 70.9749 71.2267 ...
lat (south_north, west_east) float32 7.78907 7.82944 7.86932 ...
* time (time) datetime64[ns] 2008-10-26T12:00:00 ...
* west_east (west_east) float64 -2.235e+06 -2.205e+06 -2.175e+06 ...
* south_north (south_north) float64 -2.235e+06 -2.205e+06 -2.175e+06 ...
Dimensions without coordinates: bottom_top
Data variables:
T2 (time, south_north, west_east) float32 301.977 302.008 ...
RAINC (time, south_north, west_east) float32 0.0 0.0 0.0 0.0 0.0 ...
RAINNC (time, south_north, west_east) float32 0.0 0.0 0.0 0.0 0.0 ...
U (time, bottom_top, south_north, west_east) float32 1.73438 ...
V (time, bottom_top, south_north, west_east) float32 -2.125 ...
PH (time, bottom_top, south_north, west_east) float32 18.7031 ...
PHB (time, bottom_top, south_north, west_east) float32 277.504 ...
PRCP (time, south_north, west_east) float32 nan nan nan nan nan ...
Z (time, bottom_top, south_north, west_east) float32 30.1944 ...
T2C (time, south_north, west_east) float32 28.8266 28.8578 ...
GEOPOTENTIAL (time, bottom_top, south_north, west_east) float32 296.207 ...
WS (time, bottom_top, south_north, west_east) float32 2.74293 ...
PRCP_NC (time, south_north, west_east) float32 nan nan nan nan nan ...
PRCP_C (time, south_north, west_east) float32 nan nan nan nan nan ...
Attributes:
note: Global attrs removed.
pyproj_srs: +units=m +proj=lcc +lat_1=29.040000915527344 +lat_2=29.040000915527344 +lat_0=29.039997100830078 +lon_0=89.80000305175781 +x_0=0 +y_0=0 +a=6370000 +b=6370000
Note that some dimensions / coordinates have been renamed, new variables have been defined, and the staggered dimensions have disappeared.
Diagnostic variables¶
Salem adds a layer between xarray and the underlying NetCDF file. This layer computes new variables “on the fly” or, in the case of staggered variables, “unstaggers” them:
In [8]: ds.U
Out[8]:
<xarray.DataArray 'U' (time: 3, bottom_top: 27, south_north: 150, west_east: 150)>
[1822500 values with dtype=float32]
Coordinates:
lon (south_north, west_east) float32 70.7231 70.9749 71.2267 ...
lat (south_north, west_east) float32 7.78907 7.82944 7.86932 ...
* time (time) datetime64[ns] 2008-10-26T12:00:00 ...
* west_east (west_east) float64 -2.235e+06 -2.205e+06 -2.175e+06 ...
* south_north (south_north) float64 -2.235e+06 -2.205e+06 -2.175e+06 ...
Dimensions without coordinates: bottom_top
Attributes:
FieldType: 104
MemoryOrder: XYZ
description: x-wind component
units: m s-1
stagger: X
pyproj_srs: +units=m +proj=lcc +lat_1=29.040000915527344 +lat_2=29.040000915527344 +lat_0=29.039997100830078 +lon_0=89.80000305175781 +x_0=0 +y_0=0 +a=6370000 +b=6370000
This computation is done only on demand (just like a normal NetCDF variable), this new layer is therefore relatively cheap.
In addition to unstaggering, Salem adds a number of “diagnostic” variables
to the dataset. Some are convenient (like T2C
, temperature in Celsius
instead of Kelvins), but others are more complex (e.g. SLP
for sea-level
pressure, or PRCP
which computes step-wize total precipitation out of the
accumulated fields). For a list of diagnostic variables (and TODOs!), refer to
GH18.
In [9]: ds.PRCP.isel(time=-1).salem.quick_map(cmap='Purples', vmax=5)
Out[9]: <salem.graphics.Map at 0x7ff13d73c128>

Vertical interpolation¶
The WRF vertical coordinates are eta-levels, which is not a very practical
coordinate for analysis or plotting. With the functions
wrf_zlevel()
and
wrf_plevel()
it is possible to interpolate the 3d
data at either altitude or pressure levels:
In [10]: ws_h = ds.isel(time=1).salem.wrf_zlevel('WS', levels=10000.)
In [11]: ws_h.salem.quick_map();

Note that currently, the interpolation is quite slow, see GH25. It’s probably wise to do it on single time slices or aggregated data, rather than huge data cubes.
Open multiple files¶
It is possible to open multiple WRF files at different time steps with
open_mf_wrf_dataset()
, which works like xarray’s
open_mfdataset . The only drawback of having multiple WRF time slices is
that “de-accumulated” variables such as PRCP
won’t be available.
For this purpose, you might want to use the deacc()
method.
Geogrid simulator¶
Salem provides a small tool which comes handy when defining new WRF domains. It parses the WPS configuration file (namelist.wps) and generates the grids and maps corresponding to each domain.
geogrid_simulator()
will search for the &geogrid
section of the
file and parse it:
In [12]: fpath = get_demo_file('namelist_mercator.wps')
In [13]: with open(fpath, 'r') as f: # this is just to show the file
....: print(f.read())
....:
&geogrid
parent_id = 1, 1, 2, 3,
parent_grid_ratio = 1, 3, 5, 5,
i_parent_start = 1, 28, 54, 40,
j_parent_start = 1, 24, 97, 50,
e_we = 211, 178, 101, 136,
e_sn = 131, 220, 141, 136,
dx = 30000,
dy = 30000,
map_proj = 'mercator',
ref_lat = -8.0,
ref_lon = -62.0,
truelat1 = -8.0,
/
In [14]: from salem import geogrid_simulator
In [15]: g, maps = geogrid_simulator(fpath)
In [16]: maps[0].set_rgb(natural_earth='lr') # add a background image
In [17]: maps[0].visualize(title='Domains 1 to 4')

Map transformations¶
Most of the georeferencing machinery for gridded datasets is
handled by the Grid
class: its capacity to handle
gridded datasets in a painless manner was one of the primary
motivations to develop Salem.
Grids¶
A point on earth can be defined unambiguously in two ways:
- DATUM (lon, lat, datum)
- longitudes and latitudes are angular coordinates of a point on an ellipsoid (often called “datum”)
- PROJ (x, y, projection)
- x (eastings) and y (northings) are cartesian coordinates of a point in a map projection (the unit of x, y is usually meter)
Salem adds a third coordinate reference system (crs) to this list:
- GRID (i, j, Grid)
- on a structured grid, the (x, y) coordinates are distant of a constant (dx, dy) step. The (x, y) coordinates are therefore equivalent to a new reference frame (i, j) proportional to the projection’s (x, y) frame.
Transformations between datums and projections is handled by several tools in the python ecosystem, for example GDAL or the more lightweight pyproj, which is the tool used by Salem internally [1].
The concept of Grid added by Salem is useful when transforming data between two structured datasets, or from an unstructured dataset to a structured one.
[1] | Most datasets nowadays are defined in the WGS 84 datum, therefore the concepts of datum and projection are often interchangeable: (lon, lat) coordinates are equivalent to cartesian (x, y) coordinates in the plate carree projection. |
A Grid
is defined by a projection, a reference point in
this projection, a grid spacing and a number of grid points:
In [1]: import numpy as np
In [2]: import salem
In [3]: from salem import wgs84
In [4]: grid = salem.Grid(nxny=(3, 2), dxdy=(1, 1), x0y0=(0.5, 0.5), proj=wgs84)
In [5]: x, y = grid.xy_coordinates
In [6]: x
Out[6]:
array([[ 0.5, 1.5, 2.5],
[ 0.5, 1.5, 2.5]])
In [7]: y