Reputation: 25
I'm working with the following xarray.Dataset
trying to replicate the following example from the holoviews website (https://holoviews.org/gallery/demos/bokeh/box_draw_roi_editor.html#demos-bokeh-gallery-box-draw-roi-editor):
holoviews 1.13.2
numpy 1.16.4
xarray 0.14.1
<xarray.Dataset>
Dimensions: (time: 1589, x: 50, y: 50)
Coordinates:
* x (x) float64 4.067e+05 4.067e+05 4.068e+05 ... 4.081e+05 4.082e+05
* y (y) float64 -1.309e+06 -1.309e+06 ... -1.311e+06 -1.311e+06
* time (time) datetime64[ns] 1988-01-04T00:33:06.940187 ... 2019-08-22T00:45:24.121949944
Data variables:
evi (time, y, x) float32 ...
polys = hv.Polygons([])
box_stream = streams.BoxEdit(source=polys)
def roi_curves(data):
if not data or not any(len(d) for d in data.values()):
return hv.NdOverlay({0: hv.Curve([], 'time', 'evi')})
curves = {}
data = zip(data['x0'], data['x1'], data['y0'], data['y1'])
for i, (x0, x1, y0, y1) in enumerate(data):
selection = hv_ds.select(x=(x0, x1), y=(y0, y1))
curves[i] = hv.Curve(selection.aggregate('time', np.mean))
return hv.NdOverlay(curves)
hlines = hv.HoloMap({i: hv.VLine(i) for i in range(2000)}, 'time')
dmap = hv.DynamicMap(roi_curves, streams=[box_stream])
(im * polys + dmap ).opts(
opts.Curve(width=400, framewise=True),
opts.Polygons(fill_alpha=0.2, line_color='white'),
opts.VLine(color='black'))
The problem arises when I use (im * polys + dmap * hlines)
instead of (im * polys + dmap)
The result from using (im * polys + dmap)
is close to what the website has but is missing the vertical black line that represents the time
dimension.
When I use (im * polys + dmap * hlines)
, as shown in the holoviews example, i get: TypeError: invalid type promotion
, and the console prints the following:
...
~\Anaconda3\lib\site-packages\panel\pane\holoviews.py in widgets_from_dimensions(cls, object, widget_types, widgets_type)
395 if vals:
396 if all(isnumeric(v) or isinstance(v, datetime_types) for v in vals) and len(vals) > 1:
--> 397 vals = sorted(vals)
398 labels = [unicode(dim.pprint_value(v)) for v in vals]
399 options = OrderedDict(zip(labels, vals))
TypeError: invalid type promotion
:Layout
.DynamicMap.I :DynamicMap [time]
.DynamicMap.II :DynamicMap [time]
I think that the problem is in the definition of hlines
, therefore I've tried changing range(2000)
for many other values including the length of the time
dimension in im
and hv_ds
but the error is very cryptic and I dont know how to debug this.
Question: how do I plot the vertical line that represents the time
dimension as show in the Holoviews example??
Upvotes: 1
Views: 233
Reputation: 4080
As you rightly figured out the issue here are the integer values of the VLine HoloMap. The easiest way to get the correct values is use the .apply
method on the stack of images which builds a pipeline and allows you to get the current time value from the image. Some other modifications are also needed to get it to work with datetimes, e.g. we have to declare an empty dataset so it initializes with the correct dtypes. Here's my attempt:
import numpy as np
import pandas as pd
import xarray as xr
from holoviews import opts
# Create fake dataset
coords={'x': np.arange(50), 'y': np.arange(50),
'time': np.array([1514764800000000000+86400000000000*i for i in range(1589)]).astype('datetime64[ns]')}
evi = xr.DataArray(np.random.rand(50, 50, 1589), coords=coords, dims=['x', 'y', 'time'], name='evi')
hv_ds = hv.Dataset(evi)
# Create stack of images grouped by time
im = hv_ds.to(hv.Image, ['x', 'y'], dynamic=True)
polys = hv.Polygons([])
box_stream = hv.streams.BoxEdit(source=polys)
# Declare an empty DataFrame to declare the types
empty = pd.DataFrame({'time': np.array([], dtype='datetime64[ns]'), 'evi': []})
def roi_curves(data):
if not data or not any(len(d) for d in data.values()):
return hv.NdOverlay({0: hv.Curve(empty, 'time', 'evi')})
curves = {}
data = zip(data['x0'], data['x1'], data['y0'], data['y1'])
for i, (x0, x1, y0, y1) in enumerate(data):
selection = hv_ds.select(x=(x0, x1), y=(y0, y1))
curves[i] = hv.Curve(selection.aggregate('time', np.mean))
return hv.NdOverlay(curves)
# Generate VLines by getting time value from the image frames
def vline(frame):
return hv.VLine(frame.data.time.values)
vlines = im.apply(vline)
dmap = hv.DynamicMap(roi_curves, streams=[box_stream])
(im * polys + dmap * vlines ).opts(
opts.Curve(width=400, framewise=True),
opts.Polygons(fill_alpha=0.2, line_color='white'),
opts.VLine(color='black'))
Upvotes: 1