Introductory TutorialΒΆ

The Iris cubes used in this notebook are publicly available in the SciTools/iris-sample-data repository. This notebook is based on the user story described in Issue #7 with the following image suggested for inspiration.

In [1]:
import datetime
import iris
import numpy as np
import holoviews as hv
import holocube as hc
from cartopy import crs
from cartopy import feature as cf
hv.notebook_extension()
HoloViewsJS successfully loaded in this cell.

Setting some notebook-wide options

Let's start by setting some normalization options (discussed below) and always enable colorbars for the elements we will be displaying:

In [2]:
iris.FUTURE.strict_grib_load = True
%opts Image {+framewise} [colorbar=True] Contours [colorbar=True] {+framewise} Curve [xrotation=60]

Note that it is easy to set global defaults for a project allowing any suitable settings can be made into a default on a per-element basis. Now lets specify the maximum number of frames we will be displaying:

In [3]:
%output max_frames=1000 

Loading our first cube

Here is the summary of the first cube containing some surface temperature data:

In [4]:
iris_cube = iris.load_cube(iris.sample_data_path('GloSea4', 'ensemble_001.pp'))
iris_cube.coord('latitude').guess_bounds()
iris_cube.coord('longitude').guess_bounds()
In [5]:
print iris_cube.summary()
surface_temperature / (K)           (time: 6; latitude: 145; longitude: 192)
     Dimension coordinates:
          time                           x            -               -
          latitude                       -            x               -
          longitude                      -            -               x
     Auxiliary coordinates:
          forecast_period                x            -               -
     Scalar coordinates:
          forecast_reference_time: 2011-07-18 00:00:00
     Attributes:
          STASH: m01s00i024
          source: Data from Met Office Unified Model
          um_version: 7.6
     Cell methods:
          mean: time (1 hour)

Now we can wrap this Iris cube in a HoloCube:

In [6]:
surface_temperature = hc.HoloCube(iris_cube)
surface_temperature
Out[6]:
:HoloCube   [time,longitude,latitude]   (surface_temperature)

A Simple example

Here is a simple example of viewing the surface_temperature cube over time with a single line of code. In HoloViews, this datastructure is a HoloMap of Image elements:

In [7]:
surface_temperature.to.image(['longitude', 'latitude'])
Out[7]:

You can drag the slider to view the surface temperature at different times. Here is how you can view the values of time in the cube via the HoloViews API:

In [8]:
surface_temperature.dimension_values('time')
Out[8]:
array([ 364860.,  364860.,  364860., ...,  368532.,  368532.,  368532.])

The times shown in the slider are long making the text rather small. We can use the fact that all times are recorded in the year 2011 on the 16th of each month to shorten these dates. Defining how all dates should be formatted as follows will help with readability:

In [9]:
hv.Dimension.type_formatters[datetime.datetime] = "%m/%y %Hh"

Now let us load a cube showing the pre-industrial air temperature:

In [10]:
air_temperature = hc.HoloCube(iris.load_cube(iris.sample_data_path('pre-industrial.pp')),
                             group='Pre-industrial air temperature')
air_temperature.data.coord('longitude').guess_bounds()
air_temperature.data.coord('latitude').guess_bounds()
air_temperature     # Use air_temperature.data.summary() to see the Iris summary (.data is the Iris cube)
Out[10]:
:HoloCube   [longitude,latitude]   (air_temperature)

Note that we have the air_temperature available over longitude and latitude but not the time dimensions. As a result, this cube is a single frame when visualized as a temperature map.

In [11]:
(surface_temperature.to.image(['longitude', 'latitude'])  + air_temperature.to.image(['longitude', 'latitude']))
Out[11]:

Next is a fairly involved example that plots data side-by-side in a Layout without using the + operator.

This shows how complex plots can be generated with little code and also demonstrates how different HoloViews elements can be combined together. In the following visualization, the curve is a sample of the surface_temperature at longitude and latitude (0,10):

In [12]:
%%opts Layout [fig_inches=(12,7)] Curve [aspect=2 xticks=4 xrotation=20] Points (color=2)
# Sample the surface_temperature at (0,10)
temp_curve = surface_temperature.to.curve('time', dynamic=True)[0, 10]
# Show surface_temperature and air_temperature with Point (0,10) marked
temp_maps = [cb.to.image(['longitude', 'latitude']) * hc.Points([(0,10)]) 
             for cb in [surface_temperature, air_temperature]]
# Show everything in a two column layout
hv.Layout(temp_maps + [temp_curve]).cols(2).display('all')
Out[12]:

Overlaying data and normalization

Lets view the surface temperatures together with the global coastline:

In [13]:
cf.COASTLINE.scale='1000m'
In [14]:
%%opts Image [projection=crs.Geostationary()] (cmap='Greens')
surface_temperature.to.image(['longitude', 'latitude']) * hc.GeoFeature(cf.COASTLINE)
Out[14]:

Notice that every frame uses the full dynamic range of the Greens color map. This is because normalization is set to +framewise at the top of the notebook which means every frame is normalized independently.

To control normalization, we need to decide on the normalization limits. Let's see the maximum temperature in the cube:

In [15]:
max_surface_temp = surface_temperature.data.data.max()
max_surface_temp
Out[15]:
317.33179
In [16]:
%%opts Image [projection=crs.Geostationary()] (cmap='Greens')
# Declare a humidity dimension with a range from 0 to 0.01
surface_temp_dim = hv.Dimension('surface_temperature', range=(300, max_surface_temp))
# Use it to declare the value dimension of a HoloCube
(hc.HoloCube(surface_temperature, vdims=[surface_temp_dim]).to.image(['longitude', 'latitude']) * hc.GeoFeature(cf.COASTLINE))
Out[16]:

By specifying the normalization range we can reveal different aspects of the data. In the example above we can see a warming effect over time as the dark green areas close to the bottom of the normalization range (200K) vanish. Values outside this range are clipped to the ends of the color map.

Lastly, here is a demo of a conversion from surface_temperature to Contours:

In [17]:
%%opts Contours [levels=10]
(surface_temperature.to.contours(['longitude', 'latitude']) * hc.GeoFeature(cf.COASTLINE))
Out[17]: