Project Pythia Logo Pangeo Logo

Gulf Stream Currents


Overview

An example that uses ipyleaflet to reproduce style of visualization used in the New York Times article In the Atlantic Ocean, Subtle Shifts Hint at Dramatic Dangers (March 2, 20121).

  1. Open an Intake catalogue reference Sea Surface Height data

  2. Make a geographic map of the data using ipyleaflet

Prerequisites

Concepts

Importance

Notes

Xarray

Helpful

Dask

Helpful

Intake

Helpful

ipyleaflet

Helpful

  • Time to learn: 15 minutes

Imports


from ipyleaflet import Map, TileLayer, basemaps
from ipyleaflet.velocity import Velocity
from intake import open_catalog

Load Data

The Copernicus Monitoring Environment Marine Service (CMEMS) is a large repository of ocean products including in-situ observations, satellite based remote sensing data, and numerical model output.

We want to look at altimeter satellite data to show the Sea Level Anomalies (SLA) for the global ocean. The particular data product is called Global Ocean Gridded L4 Sea Surface Heights and Derived Variables Reprocessed (1993-Ongoing) (SEALEVEL_GLO_PHY_L4_MY_008_047).

This dataset is available as an analysis-ready on the Pangeo Cloud Data Catalog

cat = open_catalog("https://raw.githubusercontent.com/pangeo-data/pangeo-datastore/master/intake-catalogs/ocean.yaml")
cat["sea_surface_height"]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[2], line 2
      1 cat = open_catalog("https://raw.githubusercontent.com/pangeo-data/pangeo-datastore/master/intake-catalogs/ocean.yaml")
----> 2 cat["sea_surface_height"]

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/base.py:472, in Catalog.__getitem__(self, key)
    463 """Return a catalog entry by name.
    464 
    465 Can also use attribute syntax, like ``cat.entry_name``, or
   (...)
    468 cat['name1', 'name2']
    469 """
    470 if not isinstance(key, list) and key in self:
    471     # triggers reload_on_change
--> 472     s = self._get_entry(key)
    473     if s.container == "catalog":
    474         s.name = key

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/utils.py:43, in reload_on_change.<locals>.wrapper(self, *args, **kwargs)
     40 @functools.wraps(f)
     41 def wrapper(self, *args, **kwargs):
     42     self.reload()
---> 43     return f(self, *args, **kwargs)

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/base.py:355, in Catalog._get_entry(self, name)
    353 ups = [up for name, up in self.user_parameters.items() if name not in up_names]
    354 entry._user_parameters = ups + (entry._user_parameters or [])
--> 355 return entry()

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/entry.py:60, in CatalogEntry.__call__(self, persist, **kwargs)
     58 def __call__(self, persist=None, **kwargs):
     59     """Instantiate DataSource with given user arguments"""
---> 60     s = self.get(**kwargs)
     61     s._entry = self
     62     s._passed_kwargs = list(kwargs)

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/local.py:313, in LocalCatalogEntry.get(self, **user_parameters)
    310     return self._default_source
    312 plugin, open_args = self._create_open_args(user_parameters)
--> 313 data_source = plugin(**open_args)
    314 data_source.catalog_object = self._catalog
    315 data_source.name = self.name

TypeError: ZarrArraySource.__init__() got an unexpected keyword argument 'consolidated'

This dataset is marked “requester pays” which means we have do an addtional step if we are not already on Pangeo Hub on the Google Cloud Platform.

Working with requester pays data

Several of the datasets within the Pangeo cloud data catalog are contained in requester pays storage buckets. This means that a user requesting data must provide their own billing project (created and authenticated through Google Cloud Platform) to be billed for the charges associated with accessing a dataset. To set up an GCP billing project and use it for authentication in applications:

  • Create a project on GCP; if this is the first time using GCP, a prompt will appear to choose a Google account to link to all GCP-related activities.

  • Create a Cloud Billing account associated with the project and enable billing for the project through this account.

  • Using Google Cloud IAM, add the Service Usage Consumer role to your account, which enables it to make billed requests on the behalf of the project. Through command line, install the Google Cloud SDK; this can be done using conda:

    conda install -c conda-forge google-cloud-sdk

  • Initialize the gcloud command line interface, logging into the account used to create the aforementioned project and selecting it as the default project; this will allow the project to be used for requester pays access through the command line:

    
    

gcloud init```

  • Finally, use gcloud to establish application default credentials; this will allow the project to be used for requester pays access through applications:

    gcloud auth application-default login

ds  = cat["sea_surface_height"].to_dask()
ds
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[3], line 1
----> 1 ds  = cat["sea_surface_height"].to_dask()
      2 ds

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/base.py:472, in Catalog.__getitem__(self, key)
    463 """Return a catalog entry by name.
    464 
    465 Can also use attribute syntax, like ``cat.entry_name``, or
   (...)
    468 cat['name1', 'name2']
    469 """
    470 if not isinstance(key, list) and key in self:
    471     # triggers reload_on_change
--> 472     s = self._get_entry(key)
    473     if s.container == "catalog":
    474         s.name = key

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/utils.py:43, in reload_on_change.<locals>.wrapper(self, *args, **kwargs)
     40 @functools.wraps(f)
     41 def wrapper(self, *args, **kwargs):
     42     self.reload()
---> 43     return f(self, *args, **kwargs)

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/base.py:355, in Catalog._get_entry(self, name)
    353 ups = [up for name, up in self.user_parameters.items() if name not in up_names]
    354 entry._user_parameters = ups + (entry._user_parameters or [])
--> 355 return entry()

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/entry.py:60, in CatalogEntry.__call__(self, persist, **kwargs)
     58 def __call__(self, persist=None, **kwargs):
     59     """Instantiate DataSource with given user arguments"""
---> 60     s = self.get(**kwargs)
     61     s._entry = self
     62     s._passed_kwargs = list(kwargs)

File ~/miniconda3/envs/po-cookbook-dev/lib/python3.10/site-packages/intake/catalog/local.py:313, in LocalCatalogEntry.get(self, **user_parameters)
    310     return self._default_source
    312 plugin, open_args = self._create_open_args(user_parameters)
--> 313 data_source = plugin(**open_args)
    314 data_source.catalog_object = self._catalog
    315 data_source.name = self.name

TypeError: ZarrArraySource.__init__() got an unexpected keyword argument 'consolidated'

Make a Map

center = [35, -50]
zoom = 4
m = Map(center=center, zoom=zoom, interpolation='nearest', basemap=basemaps.Gaode.Satellite)

display_options = {
    'velocityType': 'Global Wind',
    'displayPosition': 'bottomleft',
    'displayEmptyString': 'No wind data'
}

wind = Velocity(
    data=ds.isel(time=-1), 
    zonal_speed='ugos', meridional_speed='vgos', 
    latitude_dimension='latitude', longitude_dimension='longitude', 
    velocity_scale=0.2, max_velocity=1, 
    display_options=display_options
)

m.add_layer(wind)

m
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[4], line 12
      3 m = Map(center=center, zoom=zoom, interpolation='nearest', basemap=basemaps.Gaode.Satellite)
      5 display_options = {
      6     'velocityType': 'Global Wind',
      7     'displayPosition': 'bottomleft',
      8     'displayEmptyString': 'No wind data'
      9 }
     11 wind = Velocity(
---> 12     data=ds.isel(time=-1), 
     13     zonal_speed='ugos', meridional_speed='vgos', 
     14     latitude_dimension='latitude', longitude_dimension='longitude', 
     15     velocity_scale=0.2, max_velocity=1, 
     16     display_options=display_options
     17 )
     19 m.add_layer(wind)
     21 m

NameError: name 'ds' is not defined

Summary

In this example we loaded sea level data from an analysis-ready cloud based dataset and made a visualization of that data using mapping library.

Resources and references