Patrick Brockmann - LSCE
The motivation is to render variables read and computed from pyferret as slippy maps. This can be done directly from the memory without having to save them in netCDF files and expose them through a Thredds server to get a Web Map Service.
The tiles are generated by "workers" from a gunicorn server, a python WSGI HTTP server, and they use pyferret for the rendering. You can then use the classic ferret syntax to display your variable and apply if needed classic ferret dimension transformation (@min, @max, @var, ...) or any combinaison or operation on variables you may need in a fully pan-and-zoom environment.
Slippy maps avoid command-line typing and display loops and will help anyone on model analysis. Moreover, considering that nowdays models are becoming incredibily refined, sometimes with resolutions of 1/12°, the pan/zoom navigation is even more useful.
Usage: pyferretWMS.py [--width=400] [--height=400] [--size=value] [--center=[0,0]] [--zoom=1]
[--env=pyferretWMS.jnl] [--server] [--port=8000]
'cmd/qualifiers variable; cmd/qualifiers variable'
'cmd/qualifiers variable' is a classic ferret call (no space allowed except to
separate the variable from the command and its qualifiers). The semi-colon character ';'
is the separator between commands and will determine the number of maps to be drawn.
The qualifiers can include the title qualifier considering that the space character
is not allowed since used to distinguish the cmd/qualifiers and the variable(s).
For this, you can use the HTML code ' ' for the non-breaking space (without the ending semi-colon).
For example: 'shade/lev=20/title=Simulation A varA; shade/lev=20/title=Simulation B varB'
Options:
--version show program's version number and exit
-h, --help show this help message and exit
--width=WIDTH 200 < map width <= 600
--height=HEIGHT 200 < map height <= 600
--size=SIZE 200 < map height and width <= 600
--env=ENVSCRIPT ferret script to set the environment
(default=pyferretWMS.jnl). It contains datasets to open,
variables definition.
--center=CENTER Initial center of maps as [lat, lon] (default=[0,-40])
--zoom=ZOOM Initial zoom of maps (default=1)
--server Server only (default=False)
--port=PORT Server port number (default=8000)
./pyferretWMS.py 'shade/x=-180:180/y=-90:90/lev=20v/pal=mpl_PSU_inferno temp[k=@max]; shade/x=-180:180/y=-90:90/lev=(-inf)(0,140,5)(inf)/pal=mpl_Seq1_RdPu temp[k=@var]; shade/x=-180:180/y=-90:90/lev=(-inf)(30,40,0.5)(inf)/pal=mpl_PSU_viridis salt[k=1]'
Same as above with titles
./pyferretWMS.py 'shade/x=-180:180/y=-90:90/lev=20v/pal=mpl_PSU_inferno/title=Maximum temp[k=@max]; shade/x=-180:180/y=-90:90/lev=(-inf)(0,140,5)(inf)/pal=mpl_Seq1_RdPu/title=Temperature variance temp[k=@var]; shade/x=-180:180/y=-90:90/lev=(-inf)(30,40,0.5)(inf)/pal=mpl_PSU_viridis/title=Surface salinity salt[k=1]'
Using a NEMO configuration (curvilinear grid) focussed on the Mediterranean sea:
./pyferretWMS.py --zoom 3 --center [40,15] --width 500 --env MED8.jnl 'shade/lev=20v/pal=mpl_PSU_inferno/title=O2 O2, nav_lon, nav_lat; shade/lev=20v/pal=mpl_PSU_viridis/title=NO3 NO3, nav_lon, nav_lat'
Palettes used are available from: http://www.pmel.noaa.gov/maillists/tmap/ferret_users/fu_2015/msg00475.html or from https://github.com/PBrockmann/fast
conda install gunicorn
2022/02/02
Modifications for python3
Tested with pyferret 7.63, gunicorn 20.1.0, nwjs 0.60.0
Add a 3rd example with dynamic creation of maps
2017/01/23
Add a 3rd example with dynamic creation of maps
Add resizable properties to maps (page_03.html)
2016/11/25
2016/10/19
2016/10/18
2016/09/21
2016/18/10
Colorbars are now created from workers that can handle either a GetColorBar or a GetMap request.
2016/09/20
An environment script is loaded from the master process. All loaded datasets and defined variables are then available to the different workers. Depending on the number of commands separated by ; passed as argument, you can now get up to 4 synchronous maps with colorbars (keys) made from specified qualifiers.
2016/09/16
Slippy maps are now made from multiple workers. Problem: the dataset and variables if defined should be passed somehow to the workers. I haven't found yet how to inherit from the calling environment.
Also, how this should be called? From an external function? As a new command?
Speed for creating tiles is also an issue, especially when you work with a curvilinear grid that is quite large (1440x1021), even with several workers.
2016/09/09
You can now get slippy maps by a simple import pyferretWMS
and a call to pyferretWMS.slippyMap()
.
It is made possible because the gunicorn is now launched directly from python and not anymore from the command line.
All temporary files (png tiles and the html + package.json for the nw application)
are cleaned properly when exiting (either by closing the client application or by typing "CTRL+C" when launched from a python script).
Test it quicky from:
python pyferretWMS_test.py 'shade/lev=(-inf)(-10,30,1)(inf)/pal=mpl_PSU_plasma temp[k=@max]'
2016/09/06
First script with a gunicorn started from a shell. Only one worker.
Next steps:
Examples of calls:
./slippy_map.bash 'shade/lev=(-inf)(-10,30,1)(inf)/pal=mpl_PSU_viridis temp[k=@max]'
./slippy_map.bash 'shade/lev=(-inf)(30,40,1)(inf)/pal=mpl_PSU_inferno salt[k=1]'