1. Helper Functions

  • Let's define a few helper functions to save and load images from a temporairy directory or url

In [1]:
# Function to get tmp image dir. If it does not exist, 
#  create it
def getTmpImgDir():
    from os import makedirs
    from os.path import exists, join
    tmp_img_dir = "tmp_img"
    if (not exists(tmp_img_dir)):
        makedirs(tmp_img_dir)
    return tmp_img_dir

#Function that saves the layer as an image
def saveLayerAsTmpImage(layer, inname):
    from os.path import join
    tmp_img_dir = getTmpImgDir()
    full_img_path = join(tmp_img_dir, inname)
    out = open(full_img_path, 'wb')
    out.write(layer.read())
    out.close()

# Function to load image
def loadTmpImage(image_name):
    from IPython.core.display import Image
    from os.path import join
    tmp_img_dir = getTmpImgDir()
    filename = join(tmp_img_dir, image_name)
    return Image(filename)

# Function to display image from a url
def loadRemoteImage(imgUrl):
    from IPython.core.display import Image
    return Image(url = imgUrl)

2. WMS and OWSLib

  • WMS is the Open Geospatial Consortium (OGC) standard interface for requesting georeferenced images through HTTP.
  • OWSLib is part of geopython, a GitHub organization comprised of Python projects related to geospatial.
  • OWSLib is a Python package for client programming with OGC Web Services (OWS) developed by Tom Kralidis.
  • OWSLib supports several OGC standards: WFS, WCS, SOS...and of course WMS 1.1.1. More.
  • Does not come installed with canopy but is available in the community packages.
  • Installation with enpkg:
    • enpkg OWSLib
    • current version (07/09/2013) --> 0.4.0-1

3. Getting some information about the service

  • We will use OWSLib package and in particular the owslib.wms module.
  • Within the TDS context, if WMS is enabled and set up in the catalogs, each dataset has a WMS url.

In [2]:
from owslib.wms import WebMapService
#We just need a WMS url from one TDS dataset...
serverurl ='http://thredds.ucar.edu/thredds/wms/grib/NCEP/RAP/CONUS_13km/Best'
wms = WebMapService( serverurl, version='1.1.1')

The WebMapService object gets all the information available about the service through a GetCapabilities request:


In [3]:
#This is general information, common to all datasets in a TDS server
operations =[ op.name for op in  wms.operations ]
print 'Available operations: ' 
print operations 

print 'General information (common to all datasets):'
print wms.identification.type
print wms.identification.abstract
print wms.identification.keywords
print wms.identification.version
print wms.identification.title


Available operations: 
['GetCapabilities', 'GetMap', 'GetFeatureInfo']
General information (common to all datasets):
OGC:WMS
Scientific Data
['meteorology', 'atmosphere', 'climate', 'ocean', 'earth science']
1.1.1
THREDDS Data Server
  • Bounding boxes, styles and dimensions are specific to each layer.
  • Each variable in a dataset translates into a layer in the WMS service.
  • Besides, the server creates virtual layers if it founds vector components in CF-1 or Grib conventions.

In [4]:
#Listing all available layers...
layers = list(wms.contents)
for l in layers:
    print 'Layer title: '+wms[l].title +', name:'+wms[l].name


Layer title: Planetary Boundary Layer Height @ Ground or water surface, name:Planetary_Boundary_Layer_Height_surface
Layer title: U-Component Storm Motion @ Specified height level above ground layer, name:U-Component_Storm_Motion_height_above_ground_layer
Layer title: Convective available potential energy @ Level at specified pressure difference from ground to level layer, name:Convective_available_potential_energy_pressure_difference_layer
Layer title: Geopotential height @ Level of 0°C isotherm, name:Geopotential_height_zeroDegC_isotherm
Layer title: V-Component Storm Motion @ Specified height level above ground layer, name:V-Component_Storm_Motion_height_above_ground_layer
Layer title: Temperature @ Tropopause, name:Temperature_tropopause
Layer title: Pressure @ Level of 0°C isotherm, name:Pressure_zeroDegC_isotherm
Layer title: Categorical Snow @ Ground or water surface, name:Categorical_Snow_surface
Layer title: Pressure @ Tropopause, name:Pressure_tropopause
Layer title: Geopotential height @ Convective cloud top level, name:Geopotential_height_convective_cloud_top
Layer title: Precipitable water @ Entire atmosphere layer, name:Precipitable_water_entire_atmosphere
Layer title: Relative humidity @ Specified height level above ground, name:Relative_humidity_height_above_ground
Layer title: Geopotential height @ Cloud base level, name:Geopotential_height_cloud_base
Layer title: Temperature @ Level at specified pressure difference from ground to level layer, name:Temperature_pressure_difference_layer
Layer title: wind @ Tropopause, name:wind @ Tropopause
Layer title: Best (4 layer) Lifted Index @ Level at specified pressure difference from ground to level layer, name:Best_4_layer_Lifted_Index_pressure_difference_layer
Layer title: Convective available potential energy @ Ground or water surface, name:Convective_available_potential_energy_surface
Layer title: u-component of wind @ Maximum wind level, name:u-component_of_wind_maximum_wind
Layer title: Convective inhibition @ Level at specified pressure difference from ground to level layer, name:Convective_inhibition_pressure_difference_layer
Layer title: Convective inhibition @ Ground or water surface, name:Convective_inhibition_surface
Layer title: Relative humidity @ Isobaric surface, name:Relative_humidity_isobaric
Layer title: Geopotential height @ Isobaric surface, name:Geopotential_height_isobaric
Layer title: Composite reflectivity @ Entire atmosphere layer, name:Composite_reflectivity_entire_atmosphere
Layer title: v-component of wind @ Tropopause, name:v-component_of_wind_tropopause
Layer title: Precipitation rate @ Ground or water surface, name:Precipitation_rate_surface
Layer title: Snow depth @ Ground or water surface, name:Snow_depth_surface
Layer title: u-component of wind @ Level at specified pressure difference from ground to level layer, name:u-component_of_wind_pressure_difference_layer
Layer title: wind @ Level at specified pressure difference from ground to level layer, name:wind @ Level at specified pressure difference from ground to level layer
Layer title: v-component of wind @ Specified height level above ground, name:v-component_of_wind_height_above_ground
Layer title: Vertical velocity (pressure) @ Isobaric surface, name:Vertical_velocity_pressure_isobaric
Layer title: Relative humidity @ Level of 0°C isotherm, name:Relative_humidity_zeroDegC_isotherm
Layer title: Convective precipitation (Mixed_intervals Accumulation) @ Ground or water surface, name:Convective_precipitation_surface_Mixed_intervals_Accumulation
Layer title: Categorical Ice Pellets @ Ground or water surface, name:Categorical_Ice_Pellets_surface
Layer title: wind @ Specified height level above ground, name:wind @ Specified height level above ground
Layer title: Large-scale precipitation (non-convective) (Mixed_intervals Accumulation) @ Ground or water surface, name:Large-scale_precipitation_non-convective_surface_Mixed_intervals_Accumulation
Layer title: v-component of wind @ Level at specified pressure difference from ground to level layer, name:v-component_of_wind_pressure_difference_layer
Layer title: MSLP (MAPS System Reduction) @ Mean sea level, name:MSLP_MAPS_System_Reduction_msl
Layer title: u-component of wind @ Tropopause, name:u-component_of_wind_tropopause
Layer title: Pressure @ Ground or water surface, name:Pressure_surface
Layer title: v-component of wind @ Isobaric surface, name:v-component_of_wind_isobaric
Layer title: Categorical Freezing Rain @ Ground or water surface, name:Categorical_Freezing_Rain_surface
Layer title: u-component of wind @ Isobaric surface, name:u-component_of_wind_isobaric
Layer title: Geopotential height @ Equilibrium level, name:Geopotential_height_equilibrium
Layer title: Water equivalent of accumulated snow depth (Mixed_intervals Accumulation) @ Ground or water surface, name:Water_equivalent_of_accumulated_snow_depth_surface_Mixed_intervals_Accumulation
Layer title: wind @ Isobaric surface, name:wind @ Isobaric surface
Layer title: v-component of wind @ Maximum wind level, name:v-component_of_wind_maximum_wind
Layer title: Pressure @ Maximum wind level, name:Pressure_maximum_wind
Layer title: Wind speed (gust) @ Ground or water surface, name:Wind_speed_gust_surface
Layer title: Surface Lifted Index @ Isobaric surface layer, name:Surface_Lifted_Index_isobaric_layer
Layer title: Relative humidity @ Level at specified pressure difference from ground to level layer, name:Relative_humidity_pressure_difference_layer
Layer title: Storm relative helicity @ Specified height level above ground layer, name:Storm_relative_helicity_height_above_ground_layer
Layer title: Visibility @ Ground or water surface, name:Visibility_surface
Layer title: u-component of wind @ Specified height level above ground, name:u-component_of_wind_height_above_ground
Layer title: Temperature @ Specified height level above ground, name:Temperature_height_above_ground
Layer title: Categorical Rain @ Ground or water surface, name:Categorical_Rain_surface
Layer title: Geopotential height @ Level of cloud tops, name:Geopotential_height_cloud_tops
Layer title: wind @ Maximum wind level, name:wind @ Maximum wind level
Layer title: Temperature @ Isobaric surface, name:Temperature_isobaric

4. Getting the basic information we need to perform a GetMap request

  • All the information clients need is available in the capabilities document, which is stored in the WebMapService object.
  • TDS-WMS only supports GetMap requests on one layer (variable).
  • We need to choose our layer, bounding box, spatial reference system (SRS), size and format of the image.

In [5]:
#Values common to all GetMap requests: formats and http methods:
print wms.getOperationByName('GetMap').formatOptions
print wms.getOperationByName('GetMap').methods

#Let's choose: 'wind @ Isobaric surface' (the value in the parameter must be name of the layer)
wind = wms['wind @ Isobaric surface']

#What is its bounding box?
print wind.boundingBox

#available CRS
print wind.crsOptions
# --> NOT ALL THE AVAILABLE CRS OPTIONS ARE LISTED


['image/png', 'image/png;mode=32bit', 'image/gif', 'image/jpeg', 'application/vnd.google-earth.kmz']
[{'url': 'http://thredds.ucar.edu/thredds/wms/grib/NCEP/RAP/CONUS_13km/Best', 'type': 'Get'}]
(-139.9699067110668, 16.20865486388938, -57.26853740515435, 55.51675688158025, 'EPSG:4326')
['EPSG:3857', 'EPSG:32761', 'EPSG:4326', 'EPSG:32661', 'EPSG:41001', 'CRS:84', 'EPSG:3409', 'EPSG:3408', 'EPSG:27700']

In [6]:
#let's get the image...    
img_wind = wms.getmap( layers=[wind.name], #only takes one layer
                  srs='EPSG:4326',
                  bbox=(wind.boundingBox[0],wind.boundingBox[1], wind.boundingBox[2], wind.boundingBox[3]),
                  size=(512, 512),
                  format='image/png'
)

#Save it..
saveLayerAsTmpImage(img_wind, 'test_wind.png')

#Display the image we've just saved...
loadTmpImage('test_wind.png')


Out[6]:

5. More on GetMap requests

  • Handling time and vertical dimensions
  • Changing styles
  • Changing the spatial reference system (SRS)

Handling time and vertical dimensions

  • Getting available times for a layer:

In [7]:
#Times are available in the timepositions property of the layer
times= [time.strip() for time in wind.timepositions]
print times


['2014-08-29T00:00:00.000Z', '2014-08-29T01:00:00.000Z', '2014-08-29T02:00:00.000Z', '2014-08-29T03:00:00.000Z', '2014-08-29T04:00:00.000Z', '2014-08-29T05:00:00.000Z', '2014-08-29T06:00:00.000Z', '2014-08-29T07:00:00.000Z', '2014-08-29T08:00:00.000Z', '2014-08-29T09:00:00.000Z', '2014-08-29T10:00:00.000Z', '2014-08-29T11:00:00.000Z', '2014-08-29T12:00:00.000Z', '2014-08-29T13:00:00.000Z', '2014-08-29T14:00:00.000Z', '2014-08-29T15:00:00.000Z', '2014-08-29T16:00:00.000Z', '2014-08-29T17:00:00.000Z', '2014-08-29T18:00:00.000Z', '2014-08-29T19:00:00.000Z', '2014-08-29T20:00:00.000Z', '2014-08-29T21:00:00.000Z', '2014-08-29T22:00:00.000Z', '2014-08-29T23:00:00.000Z', '2014-08-30T00:00:00.000Z', '2014-08-30T01:00:00.000Z', '2014-08-30T02:00:00.000Z', '2014-08-30T03:00:00.000Z', '2014-08-30T04:00:00.000Z', '2014-08-30T05:00:00.000Z', '2014-08-30T06:00:00.000Z', '2014-08-30T07:00:00.000Z', '2014-08-30T08:00:00.000Z', '2014-08-30T09:00:00.000Z', '2014-08-30T10:00:00.000Z', '2014-08-30T11:00:00.000Z', '2014-08-30T12:00:00.000Z', '2014-08-30T13:00:00.000Z', '2014-08-30T14:00:00.000Z', '2014-08-30T15:00:00.000Z', '2014-08-30T16:00:00.000Z', '2014-08-30T17:00:00.000Z', '2014-08-30T18:00:00.000Z', '2014-08-30T19:00:00.000Z', '2014-08-30T20:00:00.000Z', '2014-08-30T21:00:00.000Z', '2014-08-30T22:00:00.000Z', '2014-08-30T23:00:00.000Z', '2014-08-31T00:00:00.000Z', '2014-08-31T01:00:00.000Z', '2014-08-31T02:00:00.000Z', '2014-08-31T03:00:00.000Z', '2014-08-31T04:00:00.000Z', '2014-08-31T05:00:00.000Z', '2014-08-31T06:00:00.000Z', '2014-08-31T07:00:00.000Z', '2014-08-31T08:00:00.000Z', '2014-08-31T09:00:00.000Z', '2014-08-31T10:00:00.000Z', '2014-08-31T11:00:00.000Z', '2014-08-31T12:00:00.000Z', '2014-08-31T13:00:00.000Z', '2014-08-31T14:00:00.000Z', '2014-08-31T15:00:00.000Z', '2014-08-31T16:00:00.000Z', '2014-08-31T17:00:00.000Z', '2014-08-31T18:00:00.000Z', '2014-08-31T19:00:00.000Z', '2014-08-31T20:00:00.000Z', '2014-08-31T21:00:00.000Z', '2014-08-31T22:00:00.000Z', '2014-08-31T23:00:00.000Z', '2014-09-01T00:00:00.000Z', '2014-09-01T01:00:00.000Z', '2014-09-01T02:00:00.000Z', '2014-09-01T03:00:00.000Z', '2014-09-01T04:00:00.000Z', '2014-09-01T05:00:00.000Z', '2014-09-01T06:00:00.000Z', '2014-09-01T07:00:00.000Z', '2014-09-01T08:00:00.000Z', '2014-09-01T09:00:00.000Z', '2014-09-01T10:00:00.000Z', '2014-09-01T11:00:00.000Z', '2014-09-01T12:00:00.000Z', '2014-09-01T13:00:00.000Z', '2014-09-01T14:00:00.000Z', '2014-09-01T15:00:00.000Z', '2014-09-01T16:00:00.000Z', '2014-09-01T17:00:00.000Z', '2014-09-01T18:00:00.000Z', '2014-09-01T19:00:00.000Z', '2014-09-01T20:00:00.000Z', '2014-09-01T21:00:00.000Z', '2014-09-01T22:00:00.000Z', '2014-09-01T23:00:00.000Z', '2014-09-02T00:00:00.000Z', '2014-09-02T01:00:00.000Z', '2014-09-02T02:00:00.000Z', '2014-09-02T03:00:00.000Z', '2014-09-02T04:00:00.000Z', '2014-09-02T05:00:00.000Z', '2014-09-02T06:00:00.000Z', '2014-09-02T07:00:00.000Z', '2014-09-02T08:00:00.000Z', '2014-09-02T09:00:00.000Z', '2014-09-02T10:00:00.000Z', '2014-09-02T11:00:00.000Z', '2014-09-02T12:00:00.000Z', '2014-09-02T13:00:00.000Z', '2014-09-02T14:00:00.000Z', '2014-09-02T15:00:00.000Z', '2014-09-02T16:00:00.000Z', '2014-09-02T17:00:00.000Z', '2014-09-02T18:00:00.000Z', '2014-09-02T19:00:00.000Z', '2014-09-02T20:00:00.000Z', '2014-09-02T21:00:00.000Z', '2014-09-02T22:00:00.000Z', '2014-09-02T23:00:00.000Z', '2014-09-03T00:00:00.000Z', '2014-09-03T01:00:00.000Z', '2014-09-03T02:00:00.000Z', '2014-09-03T03:00:00.000Z', '2014-09-03T04:00:00.000Z', '2014-09-03T05:00:00.000Z', '2014-09-03T06:00:00.000Z', '2014-09-03T07:00:00.000Z', '2014-09-03T08:00:00.000Z', '2014-09-03T09:00:00.000Z', '2014-09-03T10:00:00.000Z', '2014-09-03T11:00:00.000Z', '2014-09-03T12:00:00.000Z', '2014-09-03T13:00:00.000Z', '2014-09-03T14:00:00.000Z', '2014-09-03T15:00:00.000Z', '2014-09-03T16:00:00.000Z', '2014-09-03T17:00:00.000Z', '2014-09-03T18:00:00.000Z', '2014-09-03T19:00:00.000Z', '2014-09-03T20:00:00.000Z', '2014-09-03T21:00:00.000Z', '2014-09-03T22:00:00.000Z', '2014-09-03T23:00:00.000Z', '2014-09-04T00:00:00.000Z', '2014-09-04T01:00:00.000Z', '2014-09-04T02:00:00.000Z', '2014-09-04T03:00:00.000Z', '2014-09-04T04:00:00.000Z', '2014-09-04T05:00:00.000Z', '2014-09-04T06:00:00.000Z', '2014-09-04T07:00:00.000Z', '2014-09-04T08:00:00.000Z', '2014-09-04T09:00:00.000Z', '2014-09-04T10:00:00.000Z', '2014-09-04T11:00:00.000Z', '2014-09-04T12:00:00.000Z', '2014-09-04T13:00:00.000Z', '2014-09-04T14:00:00.000Z', '2014-09-04T15:00:00.000Z', '2014-09-04T16:00:00.000Z', '2014-09-04T17:00:00.000Z', '2014-09-04T18:00:00.000Z', '2014-09-04T19:00:00.000Z', '2014-09-04T20:00:00.000Z', '2014-09-04T21:00:00.000Z', '2014-09-04T22:00:00.000Z', '2014-09-04T23:00:00.000Z', '2014-09-05T00:00:00.000Z', '2014-09-05T01:00:00.000Z', '2014-09-05T02:00:00.000Z', '2014-09-05T03:00:00.000Z', '2014-09-05T04:00:00.000Z', '2014-09-05T05:00:00.000Z', '2014-09-05T06:00:00.000Z', '2014-09-05T07:00:00.000Z', '2014-09-05T08:00:00.000Z', '2014-09-05T09:00:00.000Z', '2014-09-05T10:00:00.000Z', '2014-09-05T11:00:00.000Z', '2014-09-05T12:00:00.000Z', '2014-09-05T13:00:00.000Z', '2014-09-05T14:00:00.000Z', '2014-09-05T15:00:00.000Z', '2014-09-05T16:00:00.000Z', '2014-09-05T17:00:00.000Z', '2014-09-05T18:00:00.000Z', '2014-09-05T19:00:00.000Z', '2014-09-05T20:00:00.000Z', '2014-09-05T21:00:00.000Z', '2014-09-05T22:00:00.000Z', '2014-09-05T23:00:00.000Z', '2014-09-06T00:00:00.000Z', '2014-09-06T01:00:00.000Z', '2014-09-06T02:00:00.000Z', '2014-09-06T03:00:00.000Z', '2014-09-06T04:00:00.000Z', '2014-09-06T05:00:00.000Z', '2014-09-06T06:00:00.000Z', '2014-09-06T07:00:00.000Z', '2014-09-06T08:00:00.000Z', '2014-09-06T09:00:00.000Z', '2014-09-06T10:00:00.000Z', '2014-09-06T11:00:00.000Z', '2014-09-06T12:00:00.000Z', '2014-09-06T13:00:00.000Z', '2014-09-06T14:00:00.000Z', '2014-09-06T15:00:00.000Z', '2014-09-06T16:00:00.000Z', '2014-09-06T17:00:00.000Z', '2014-09-06T18:00:00.000Z', '2014-09-06T19:00:00.000Z', '2014-09-06T20:00:00.000Z', '2014-09-06T21:00:00.000Z', '2014-09-06T22:00:00.000Z', '2014-09-06T23:00:00.000Z', '2014-09-07T00:00:00.000Z', '2014-09-07T01:00:00.000Z', '2014-09-07T02:00:00.000Z', '2014-09-07T03:00:00.000Z', '2014-09-07T04:00:00.000Z', '2014-09-07T05:00:00.000Z', '2014-09-07T06:00:00.000Z', '2014-09-07T07:00:00.000Z', '2014-09-07T08:00:00.000Z', '2014-09-07T09:00:00.000Z', '2014-09-07T10:00:00.000Z', '2014-09-07T11:00:00.000Z', '2014-09-07T12:00:00.000Z', '2014-09-07T13:00:00.000Z', '2014-09-07T14:00:00.000Z', '2014-09-07T15:00:00.000Z', '2014-09-07T16:00:00.000Z', '2014-09-07T17:00:00.000Z', '2014-09-07T18:00:00.000Z', '2014-09-07T19:00:00.000Z', '2014-09-07T20:00:00.000Z', '2014-09-07T21:00:00.000Z', '2014-09-07T22:00:00.000Z', '2014-09-07T23:00:00.000Z', '2014-09-08T00:00:00.000Z', '2014-09-08T01:00:00.000Z', '2014-09-08T02:00:00.000Z', '2014-09-08T03:00:00.000Z', '2014-09-08T04:00:00.000Z', '2014-09-08T05:00:00.000Z', '2014-09-08T06:00:00.000Z', '2014-09-08T07:00:00.000Z', '2014-09-08T08:00:00.000Z', '2014-09-08T09:00:00.000Z', '2014-09-08T10:00:00.000Z', '2014-09-08T11:00:00.000Z', '2014-09-08T12:00:00.000Z', '2014-09-08T13:00:00.000Z', '2014-09-08T14:00:00.000Z', '2014-09-08T15:00:00.000Z', '2014-09-08T16:00:00.000Z', '2014-09-08T17:00:00.000Z', '2014-09-08T18:00:00.000Z', '2014-09-08T19:00:00.000Z', '2014-09-08T20:00:00.000Z', '2014-09-08T21:00:00.000Z', '2014-09-08T22:00:00.000Z', '2014-09-08T23:00:00.000Z', '2014-09-09T00:00:00.000Z', '2014-09-09T01:00:00.000Z', '2014-09-09T02:00:00.000Z', '2014-09-09T03:00:00.000Z', '2014-09-09T04:00:00.000Z', '2014-09-09T05:00:00.000Z', '2014-09-09T06:00:00.000Z', '2014-09-09T07:00:00.000Z', '2014-09-09T08:00:00.000Z', '2014-09-09T09:00:00.000Z', '2014-09-09T10:00:00.000Z', '2014-09-09T11:00:00.000Z', '2014-09-09T12:00:00.000Z', '2014-09-09T13:00:00.000Z', '2014-09-09T14:00:00.000Z', '2014-09-09T15:00:00.000Z', '2014-09-09T16:00:00.000Z', '2014-09-09T17:00:00.000Z', '2014-09-09T18:00:00.000Z', '2014-09-09T19:00:00.000Z', '2014-09-09T20:00:00.000Z', '2014-09-09T21:00:00.000Z', '2014-09-09T22:00:00.000Z', '2014-09-09T23:00:00.000Z', '2014-09-10T00:00:00.000Z', '2014-09-10T01:00:00.000Z', '2014-09-10T02:00:00.000Z', '2014-09-10T03:00:00.000Z', '2014-09-10T04:00:00.000Z', '2014-09-10T05:00:00.000Z', '2014-09-10T06:00:00.000Z', '2014-09-10T07:00:00.000Z', '2014-09-10T08:00:00.000Z', '2014-09-10T09:00:00.000Z', '2014-09-10T10:00:00.000Z', '2014-09-10T11:00:00.000Z', '2014-09-10T12:00:00.000Z', '2014-09-10T13:00:00.000Z', '2014-09-10T14:00:00.000Z', '2014-09-10T15:00:00.000Z', '2014-09-10T16:00:00.000Z', '2014-09-10T17:00:00.000Z', '2014-09-10T18:00:00.000Z', '2014-09-10T19:00:00.000Z', '2014-09-10T20:00:00.000Z', '2014-09-10T21:00:00.000Z', '2014-09-10T22:00:00.000Z', '2014-09-10T23:00:00.000Z', '2014-09-11T00:00:00.000Z', '2014-09-11T01:00:00.000Z', '2014-09-11T02:00:00.000Z', '2014-09-11T03:00:00.000Z', '2014-09-11T04:00:00.000Z', '2014-09-11T05:00:00.000Z', '2014-09-11T06:00:00.000Z', '2014-09-11T07:00:00.000Z', '2014-09-11T08:00:00.000Z', '2014-09-11T09:00:00.000Z', '2014-09-11T10:00:00.000Z', '2014-09-11T11:00:00.000Z', '2014-09-11T12:00:00.000Z', '2014-09-11T13:00:00.000Z', '2014-09-11T14:00:00.000Z', '2014-09-11T15:00:00.000Z', '2014-09-11T16:00:00.000Z', '2014-09-11T17:00:00.000Z', '2014-09-11T18:00:00.000Z', '2014-09-11T19:00:00.000Z', '2014-09-11T20:00:00.000Z', '2014-09-11T21:00:00.000Z', '2014-09-11T22:00:00.000Z', '2014-09-11T23:00:00.000Z', '2014-09-12T00:00:00.000Z', '2014-09-12T01:00:00.000Z', '2014-09-12T02:00:00.000Z', '2014-09-12T03:00:00.000Z', '2014-09-12T04:00:00.000Z', '2014-09-12T05:00:00.000Z', '2014-09-12T06:00:00.000Z', '2014-09-12T07:00:00.000Z', '2014-09-12T08:00:00.000Z', '2014-09-12T09:00:00.000Z', '2014-09-12T10:00:00.000Z', '2014-09-12T11:00:00.000Z', '2014-09-12T12:00:00.000Z', '2014-09-12T13:00:00.000Z', '2014-09-12T14:00:00.000Z', '2014-09-12T15:00:00.000Z', '2014-09-12T16:00:00.000Z', '2014-09-12T17:00:00.000Z', '2014-09-12T18:00:00.000Z', '2014-09-12T19:00:00.000Z', '2014-09-12T20:00:00.000Z', '2014-09-12T21:00:00.000Z', '2014-09-12T22:00:00.000Z', '2014-09-12T23:00:00.000Z', '2014-09-13T00:00:00.000Z', '2014-09-13T01:00:00.000Z', '2014-09-13T02:00:00.000Z', '2014-09-13T03:00:00.000Z', '2014-09-13T04:00:00.000Z', '2014-09-13T05:00:00.000Z', '2014-09-13T06:00:00.000Z', '2014-09-13T07:00:00.000Z', '2014-09-13T08:00:00.000Z', '2014-09-13T09:00:00.000Z', '2014-09-13T10:00:00.000Z']

In [8]:
#We can choose any of the available times and make a request for it with the parameter time
#If no time is provided the default in TDS is the closest available time to the current time
img_wind = wms.getmap( layers=[wind.name], 
                  srs='EPSG:4326',
                  bbox=(wind.boundingBox[0],wind.boundingBox[1], wind.boundingBox[2], wind.boundingBox[3]),
                  size=(600, 600),
                  format='image/png',
                  time= times[len(times)-1]
)

saveLayerAsTmpImage(img_wind, 'test_wind.png')
loadTmpImage('test_wind.png')


Out[8]:

In [9]:
#We can also specify a time interval to get an animated gif
#Format must be image/gif
img_wind = wms.getmap( layers=[wind.name], 
                  srs='EPSG:4326',
                  bbox=(wind.boundingBox[0],wind.boundingBox[1], wind.boundingBox[2], wind.boundingBox[3]),
                  size=(600, 600),
                  format='image/gif',
                  time= times[len(times)-4]+'/'+times[len(times)-1]
)

from IPython.core.display import Image
loadRemoteImage(img_wind.url)


Out[9]:
  • Getting the available vertical levels:
    OWSLib does not support vertical levels, meaning the layer objects do not have a property "elevations" with the vertical levels. So, we need a little extra work to get the available vertical levels for a layer

In [10]:
#Next version of OWSLib will support this...
#elevations = [el.strip() for el in wind.elevations]
#print elevations

#In the meantime...
def find_elevations_for_layer(wms, layer_name):
    """
        parses the wms capabilities document searching
        the elevation dimension for the layer
    """
    #Get all the layers
    levels =None;
    layers = wms._capabilities.findall(".//Layer")
    layer_tag = None
    for el in layers:
        name = el.find("Name")
        if name is not None and name.text.strip() == layer_name:
            layer_tag = el
            break        

    if layer_tag is not None:
        elevation_tag = layer_tag.find("Extent[@name='elevation']")
        if elevation_tag is not None:
            levels = elevation_tag.text.strip().split(',')

    return levels;

elevations = find_elevations_for_layer(wms, wind.name)
print elevations


['10000.0', '12500.0', '15000.0', '17500.0', '20000.0', '22500.0', '25000.0', '27500.0', '30000.0', '32500.0', '35000.0', '37500.0', '40000.0', '42500.0', '45000.0', '47500.0', '50000.0', '52500.0', '55000.0', '57500.0', '60000.0', '62500.0', '65000.0', '67500.0', '70000.0', '72500.0', '75000.0', '77500.0', '80000.0', '82500.0', '85000.0', '87500.0', '90000.0', '92500.0', '95000.0', '97500.0', '100000.0']

In [11]:
#now we can change our vertical level with the parameter elevation
#If no elevation parameter is provided the default is the first vertical level in the dimension.
img_wind = wms.getmap( layers=['wind @ Isobaric surface'], #only takes one layer
                  srs='EPSG:4326',
                  bbox=(wind.boundingBox[0],wind.boundingBox[1], wind.boundingBox[2], wind.boundingBox[3]),
                  size=(600, 600),
                  format='image/png',
                  time= times[0],
                  elevation=elevations[len(elevations)-1 ]
)

saveLayerAsTmpImage(img_wind, 'test_wind.png')
loadTmpImage('test_wind.png')


Out[11]:

Changing styles

  • We can specify the style (any from the available styles for a layer) in the param styles

In [12]:
#available styles: 
#print wind.styles
#Change the style of our layer
img_wind = wms.getmap( layers=[wind.name], #only takes one layer
                  styles=['barb/rainbow'], #one style per layer    
                  srs='EPSG:4326',
                  bbox=(wind.boundingBox[0],wind.boundingBox[1], wind.boundingBox[2], wind.boundingBox[3]),
                  size=(600, 600),
                  format='image/png',
                  time= times[0]
)

saveLayerAsTmpImage(img_wind, 'test_wind_barb.png')
loadTmpImage('test_wind_barb.png')


Out[12]:

Changing the spatial reference system (SRS)

  • We can reproject to any of the available SRS.

In [13]:
#Reproject the bounding box to a global mercator (EPSG:3875, projection used by Google Maps, OSM...) using pyproj
from mpl_toolkits.basemap import pyproj
epsg = '3857'
psproj = pyproj.Proj(init="epsg:%s" % epsg)
xmin, ymin = psproj(wind.boundingBox[0], wind.boundingBox[1])
xmax, ymax = psproj(wind.boundingBox[2], wind.boundingBox[3])
img_wind = wms.getmap( layers=[wind.name],
                  srs='EPSG:'+ epsg,
                  bbox=(xmin, ymin, xmax, ymax),
                  size=(600, 600),
                  format='image/png',
                  time= times[0]
)

saveLayerAsTmpImage(img_wind, 'test_wind_3857.png')
loadTmpImage('test_wind_3857.png')


Out[13]:

Cool, we already know how to make get map requests. Let's change our layer...


In [14]:
temp =wms['Temperature_isobaric']
img_temp = wms.getmap( layers=[temp.name], 
                  styles=['boxfill/rainbow'], 
                  srs='EPSG:4326',
                  bbox=(temp.boundingBox[0],temp.boundingBox[1], temp.boundingBox[2], temp.boundingBox[3]),
                  size=(600, 600),
                  format='image/png',
                  time= times[0]
)

saveLayerAsTmpImage(img_temp, 'test_temp.png')
loadTmpImage('test_temp.png')


Out[14]:

...well not that cool.

6. TDS-ncWMS styles and extensions

  • ncWMS/THREDDS provides some non-standard WMS parameters that allow clients some control on the styling.

  • Change the scale range:

    • Default is -50,50. Parameter colorscalerange allows us to use a different scale

In [15]:
img_temp = wms.getmap( layers=[temp.name], 
                  styles=['boxfill/rainbow'], 
                  srs='EPSG:4326',
                  bbox=(wind.boundingBox[0],wind.boundingBox[1], wind.boundingBox[2], wind.boundingBox[3]),
                  size=(600, 600),
                  format='image/png',
                  time= times[0],
                  colorscalerange='250,320'
)

saveLayerAsTmpImage(img_temp, 'test_temp.png')
loadTmpImage('test_temp.png')


Out[15]:
  • abovemaxcolor, belowmincolor params give us control on how we want the values out of range to be displayed.
  • valid values for those params are: extend (will use the highest/lowest value of the palette for values larger/smaller than the maximun/minimun), transparent and a color in 0xRRGGBB format

In [16]:
colorscalerange='290,310'

img_temp = wms.getmap( layers=[temp.name], 
                  styles=['boxfill/rainbow'], 
                  srs='EPSG:4326',
                  bbox=(wind.boundingBox[0],wind.boundingBox[1], wind.boundingBox[2], wind.boundingBox[3]),
                  size=(600, 600),
                  format='image/png',
                  time= times[0],
                  colorscalerange=colorscalerange,
                  abovemaxcolor='transparent',
                  belowmincolor='transparent'
)

saveLayerAsTmpImage(img_temp, 'test_temp.png')
loadTmpImage('test_temp.png')


Out[16]:

The GetLegendGraphic request gives us a legend for the map, but the request is not supported by OWSLib.


In [17]:
params ={'request': 'GetLegendGraphic',
         'colorbaronly':'False', #want the text in the legend
         'layer':temp.name,
         'colorscalerange':colorscalerange}

legendUrl=serverurl+'?REQUEST={request:s}&COLORBARONLY={colorbaronly:s}&LAYER={layer:s}&COLORSCALERANGE={colorscalerange:s}'.format(**params)

loadRemoteImage(legendUrl)


Out[17]:

7. WMS and basemap

We can use basemap to overlay the layer with a coastline...


In [18]:
import os
import urllib2
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnnotationBbox, OffsetImage
from matplotlib._png import read_png

%matplotlib inline

m = Basemap(llcrnrlon=temp.boundingBox[0], llcrnrlat=temp.boundingBox[1],
            urcrnrlon=temp.boundingBox[2], urcrnrlat=temp.boundingBox[3]+5.0,
            resolution='l',epsg=4326)

plt.figure(1, figsize=(16,12))
plt.title(temp.title +' '+times[0] )

m.wmsimage(serverurl,xpixels=600, ypixels=600, verbose=False,
        layers=[temp.name], 
        styles=['boxfill/rainbow'], 
        time= times[0],
        colorscalerange=colorscalerange,
        abovemaxcolor='extend',
        belowmincolor='transparent'
)

m.drawcoastlines(linewidth=0.25)

#Annotating the map with the legend
#Save the legend as image
cwd = os.getcwd()
legend = urllib2.urlopen(legendUrl)
saveLayerAsTmpImage(legend, 'legend_temp.png')

#read the image as an array
arr = read_png(os.path.join(getTmpImgDir(),'legend_temp.png'))
imagebox = OffsetImage(arr, zoom=0.7)
xy =[ temp.boundingBox[2], temp.boundingBox[1] ]

#Gets the current axis
ax = plt.gca()

#Creates the annotation
ab = AnnotationBbox(imagebox, xy,
                    xybox=(-46.,100.),
                    xycoords='data',
                    boxcoords="offset points",
                    pad=0.)

#Adds the legend image as an AnnotationBbox to the map
ax.add_artist(ab)

plt.show()


Exercise:

  • Get the vertical levels for the layer temp.
  • Change the request for getting the highest level.
  • Change the color scale range to appropriate values.