Working with Projections in Diana

This document aims to show how to work with projections in Diana from Python scripts and from within the ipython notebook.

Installation

To get access to the Python modules that expose Diana's plotting features, you need to install the python-diana package from the local package repository. Either use the package manager to do this, or enter the following in a terminal:

apt-get install python-diana

Some examples can also be found in the python-diana-examples package.

Importing Modules

You can use Diana's functionality from Python by importing the bdiana and plotcommands modules from the metno package. If you are using an old version of ipython (earlier than version 1.0) then it is also useful to import the embed function from the metno.ipython_extensions module. The pyproj module is used to describe projections in a way that Diana understands. We also import the datetime module so that we can pass a time to Diana without needing to obtain one from a data file.


In [1]:
from metno import bdiana, metlibs, plotcommands
from metno.ipython_extensions import embed
import datetime, pyproj

Initialisation and Setup

The bdiana module contains the BDiana class. This provides a convenient interface to Diana's functions and also wraps several initialisation steps into one object. To start using Diana, we simply create an instance of this class and load a setup file that describes where various resources are located.


In [2]:
b = bdiana.BDiana()
b.setup("/etc/diana/diana.setup-COMMON")

To start with, we create a simple geographic projection.


In [3]:
p = pyproj.Proj(proj="latlong", datum="WGS84")
x1, y1 = p(-180, -90)
x2, y2 = p(180, 90)

We create a plot command to describe the map.


In [4]:
m = plotcommands.Map(map="Gshhs-Auto", backcolour="white", land="on")
m.setOption("land.colour", "flesh")
m.setOption("lat", "on")
m.setOption("lon", "on")

We define an area using the above projection by setting the proj4string option and defining a view with the rectangle option.


In [5]:
a = plotcommands.Area(proj4string = p.srs, rectangle = [x1, x2, y1, y2])

Then we set the plot commands, use the current time and plot the image.


In [6]:
b.setPlotCommands([a.text(), m.text()])
b.setPlotTime(datetime.datetime.now())
embed(b.plotImage(500, 250))

Adjusting the Projection

Let's try another projection. The list of projections supported by the pyproj module are defined by the underlying PROJ.4 library. A list of projections can be found at http://www.remotesensing.org/geotiff/proj_list/. We will try the orthographic projection.


In [7]:
p = pyproj.Proj(proj="ortho", datum="WGS84")
x1, y1 = p(-180, -90)
x2, y2 = p(180, 90)

We create an Area plot command using the projection by setting the proj4string option, and we define a view rectangle with the rectangle option. The new plot shows the new projection.


In [8]:
a = plotcommands.Area(proj4string = p.srs, rectangle = [x1, x2, y1, y2])

b.setPlotCommands([a.text(), m.text()])
b.setPlotTime(datetime.datetime.now())
embed(b.plotImage(250, 250))

By default, this projection is centered on the zero latitude and zero longitude. We can modify this by adding PROJ.4 options to the Proj object when we create it. Since we are specifying the visible area using latitude and longitude coordinates, the values we use for this must be reasonable for the projection in use. Typically, these will be equidistant from the coordinates passed to Proj.


In [9]:
p = pyproj.Proj(proj="ortho", datum="WGS84", lat_0=60, lon_0=15)
x1, y1 = p(-10, 35)
x2, y2 = p(40, 85)

Regenerating the plot from the plot commands shows the new projection.


In [10]:
a = plotcommands.Area(proj4string = p.srs, rectangle = [x1, x2, y1, y2])

b.setPlotCommands([a.text(), m.text()])
b.setPlotTime(datetime.datetime.now())
embed(b.plotImage(250, 250))

Zooming

The rectangle option is used to limit the view to a particular area of the projection. Once the values used for this have been defined by the projection, we can adjust them to define the exact area we need.


In [11]:
cx = (x1 + x2)/2
cy = (y1 + y2)/2
w = x2 - x1
h = y2 - y1
zoomed_rectangle = [cx - w/4, cx + w/4, cy - h/4, cy + h/4]

In [12]:
a = plotcommands.Area(proj4string = p.srs, rectangle = zoomed_rectangle)

b.setPlotCommands([a.text(), m.text()])
b.setPlotTime(datetime.datetime.now())
embed(b.plotImage(250, 250))

Note that the size of the image we create tends to reflect the size of the area we want to display. Diana does not stretch plots to fit the output, but instead scales the output to ensure that the smallest edge of the plot is fully visible.


In [13]:
embed(b.plotImage(500, 250))

This can be confusing if you assumed that the edges of the image coincide with particular locations shown in the plot. If the rectangle's aspect ratio does not match the aspect ratio of the output, any assumptions like this do not apply.