Skip to content

PBrockmann/wms-pyferret

Repository files navigation

Display synchronous slippy maps using Web Map Service (WMS) provided by pyferret

Patrick Brockmann - LSCE

DOI

Motivation

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

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 '&nbsp' for the non-breaking space (without the ending semi-colon).
For example: 'shade/lev=20/title=Simulation&nbspA varA; shade/lev=20/title=Simulation&nbspB 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)

Examples

  • Using the levitus climatology dataset: ./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]'

Screencast

  • 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&nbspvariance temp[k=@var]; shade/x=-180:180/y=-90:90/lev=(-inf)(30,40,0.5)(inf)/pal=mpl_PSU_viridis/title=Surface&nbspsalinity 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'

Capture

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

Requirements

conda install gunicorn

Installation notes

  • nw should be accessible from your $PATH environment variable
  • on Mac OS X: nwjs should be renamed nw and accessible with the $PATH environment variable (or changed in pyferretWMS.py)

Work based on

Releases notes


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
  • Add port number option (tag 0.9.6)
  • Add daemon file to set a service with pyferretWMS

2016/10/19
  • Add access to command when click on title map (tag 0.9.5)

2016/10/18
  • Add size option
  • Merge server mode as a new option (tag 0.9.4)
  • Colorbars are now created from workers that can handle either a GetColorBar or a GetMap request (tag 0.9.3)

2016/09/21
  • Colorbars are created by master process and added to the template html page
  • Add map center and zoom option
  • Change call to allow curvilinear grid plot (shade command with 3 arguments)
  • Resize zoom control buttons
  • Remove attribution display (for better visibility)

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:

  • Read variables and start the gunicorn server directly from pyferret (Custom Application).
  • Propose synchronous maps when 2 (or more) variables are requested to allow direct spatial intercomparison.

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]'