Воспроизведение примера Holoviews box_draw_roi_editor с набором данных XArray - PullRequest
1 голос
/ 09 апреля 2020

Я работаю со следующим xarray.Dataset, пытающимся скопировать следующий пример с веб-сайта holoviews (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'))

Проблема возникает, когда я использую (im * polys + dmap * hlines) вместо (im * polys + dmap) Результат использования (im * polys + dmap) близок к тому, что есть на сайте, но отсутствует вертикальная черная линия, которая представляет time размерность.

Когда я использую (im * polys + dmap * hlines), как показано в примере holoviews, я получаю: TypeError: invalid type promotion, и консоль печатает следующее:

...
~\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]

Я думаю проблема заключается в определении hlines, поэтому я пытался изменить range(2000) для многих других значений, включая длину измерения time в im и hv_ds, но ошибка очень криптовая c, и я не знаю, как это отладить.

Вопрос: как построить вертикальную линию, представляющую измерение time, как показано в примере Holoviews ??

1 Ответ

1 голос
/ 09 апреля 2020

Как вы правильно поняли, проблема заключается в целочисленных значениях VLine HoloMap. Самый простой способ получить правильные значения - использовать метод .apply для стека изображений, который создает конвейер и позволяет получить текущее значение времени из изображения. Некоторые другие модификации также необходимы, чтобы заставить его работать с datetime, например, мы должны объявить пустой набор данных, чтобы он инициализировался с правильными dtypes. Вот моя попытка:

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'))
...