hvplot
demo on ocean model data¶hvplot is a high-level plotting API for pandas, dask, streamz and xarray built on HoloViews. I learned about it in James Bednar's pyviz talk at SciPy 2018 and I've been using it since. It's a young project, but super useful.
The great thing is you can just replace .plot()
with .hvplot()
on xarray
and pandas
objects and get interactive plots in your browser.
It can be installed from the conda-forge channel: conda install -c conda-forge hvplot
import xarray as xr
Let's open some global wave forecast data using an OPeNDAP link from Unidata's THREDDS server
url = 'http://thredds.ucar.edu/thredds/dodsC/grib/FNMOC/WW3/Global_1p0deg/Best'
ds = xr.open_dataset(url)
ds
<xarray.Dataset> Dimensions: (lat: 181, lon: 360, time: 215, time1: 153, time2: 279) Coordinates: * lat (lat) float32 -90.00001 -89.00001 ... 89.99999 * lon (lon) float32 0.0 1.0 2.0 3.0 ... 357.0 358.0 359.0 * time (time) datetime64[ns] 2019-01-14 ... 2019-02-21 reftime (time) datetime64[ns] ... * time1 (time1) datetime64[ns] 2019-01-14 ... 2019-02-21 reftime1 (time1) datetime64[ns] ... * time2 (time2) datetime64[ns] 2019-01-14 ... 2019-02-21 reftime2 (time2) datetime64[ns] ... Data variables: LatLon_Projection int32 ... swl_wav_dir_surface (time2, lat, lon) float32 ... sig_wav_ht_surface (time2, lat, lon) float32 ... wnd_wav_dir_surface (time1, lat, lon) float32 ... wnd_wav_ht_surface (time1, lat, lon) float32 ... wnd_wav_per_surface (time2, lat, lon) float32 ... swl_wav_ht_surface (time2, lat, lon) float32 ... swl_wav_per_surface (time2, lat, lon) float32 ... pr_wav_dir_surface (time2, lat, lon) float32 ... pr_wav_per_surface (time2, lat, lon) float32 ... scdy_wav_dir_surface (time2, lat, lon) float32 ... scdy_wav_per_surface (time2, lat, lon) float32 ... max_wav_ht_surface (time2, lat, lon) float32 ... wcap_prbl_surface (time1, lat, lon) float32 ... peak_wav_dir_surface (time1, lat, lon) float32 ... peak_wav_per_surface (time, lat, lon) float32 ... Attributes: Originating_or_generating_Center: Fleet Numerical Meteorology and Oce... Originating_or_generating_Subcenter: 0 GRIB_table_version: 0,3 Generating_process_or_model: Wave Watch 3rd Revision Global file_format: GRIB-1 Conventions: CF-1.6 history: Read using CDM IOSP GribCollection v3 featureType: GRID _CoordSysBuilder: ucar.nc2.dataset.conv.CF1Convention
Let's look at significant wave height
var = 'sig_wav_ht_surface'
ds[var]
<xarray.DataArray 'sig_wav_ht_surface' (time2: 279, lat: 181, lon: 360)> [18179640 values with dtype=float32] Coordinates: * lat (lat) float32 -90.00001 -89.00001 -88.00001 ... 88.99999 89.99999 * lon (lon) float32 0.0 1.0 2.0 3.0 4.0 ... 356.0 357.0 358.0 359.0 * time2 (time2) datetime64[ns] 2019-01-14 ... 2019-02-21 reftime2 (time2) datetime64[ns] ... Attributes: long_name: ocean wave forecasting A fictitious wave with a he... units: m description: ocean wave forecasting A fictitious wave with a he... grid_mapping: LatLon_Projection Grib_Variable_Id: VAR_58-0-3-100_L1 Grib1_Center: 58 Grib1_Subcenter: 0 Grib1_TableVersion: 3 Grib1_Parameter: 100 Grib1_Parameter_Name: sig_wav_ht Grib1_Level_Type: 1 Grib1_Level_Desc: Ground or water surface
For this dataset, the time dimension is sometimes time
, sometimes time1
or time2
, so determine it here:
ds[var].dims
('time2', 'lat', 'lon')
time_dim = ds[var].dims[0]
hvplot
currently has a known issue that is gets confused by extra time variables, so drop the associated reftime
variable:
ds = ds.drop('ref'+time_dim)
Now we are ready to try hvplot
:
import hvplot.xarray
We tell hvplot
to group on time so that the time dimension appears on a slider (otherwise we get a histogram of all data):
ds[var].hvplot(groupby=time_dim)
We can customize the plot via additional parameters, and because there is not yet a way to set the aspect ratio, set the size and width by eye to get a better aspect ratio:
ds[var].hvplot(groupby=time_dim, clim=(0,5), label=var, rasterize=True, width=700, height=400, cmap='viridis')
Now let's extract a time series at a specified location using xarray's selection by coordinate variable:
lon = 302.5
lat = 25.23
label = f'{var} at lon: {lon}, lat: {lat}'
d1d = ds[var].sel(lon=lon, lat=lat, method='nearest')
type(d1d)
xarray.core.dataarray.DataArray
Using hvplot
on this 1D DataArray
does the right thing:
d1d.hvplot()
Note that hvplot
also works with pandas
:
import hvplot.pandas
df = d1d.to_pandas()
df.hvplot()