Взаимодействие Panel / Hvplot при изменении переменной - PullRequest
0 голосов
/ 19 февраля 2019

Я пытаюсь создать панель мониторинга с двумя объектами holoviews: объект panel pn.widgets.Select, содержащий список переменных xarray, и объект hvplot , который принимает выбранный объект.переменная на входе, например:

def hvmesh(var=None):
    mesh = ds[var].hvplot.quadmesh(x='x', y='y', rasterize=True, crs=crs, 
       width=600, height=400, groupby=list(ds[var].dims[:-2]), cmap='jet')
    return mesh

Вот как выглядит пример сетки для конкретной переменной (с измерением времени и высоты): enter image description here

Мне бы хотелось обновить карту, когда я выбираю переменную из виджета панели: enter image description here Я пытался сделать это как динамическую карту, например:

from holoviews.streams import Params
import holoviews as hv

var_stream = Params(var_select, ['value'], rename={'value': 'var'})

mesh = hv.DynamicMap(hvmesh, streams=[var_stream])

но когда я пытаюсь отобразить карту, я получаю:

Exception: Nesting a DynamicMap inside a DynamicMap is not supported.

Казалось бы, обычно нужно выбрать переменную для hvplot из виджета панели.Каков наилучший способ сделать это с помощью pyviz ?

Если это полезно, вот моя полная попытка Jupyter Notebook .

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Поскольку groupby изменяется с каждой выбранной переменной, список переменных не может быть передан в hvplot.Поэтому одним из решений является воссоздание графика каждый раз, когда выбирается новая переменная.Это работает:

import holoviews as hv
from holoviews.streams import Params

def plot(var=None, tiles=None):
    var = var or var_select.value
    tiles = tiles or map_select.value
    mesh = ds[var].hvplot.quadmesh(x='x', y='y', rasterize=True, crs=crs, title=var,
                                   width=600, height=400, groupby=list(ds[var].dims[:-2]), 
                                   cmap='jet')
    return mesh.opts(alpha=0.7) * tiles

def on_var_select(event):
    var = event.obj.value
    col[-1] = plot(var=var)

def on_map_select(event):
    tiles = event.obj.value
    col[-1] = plot(tiles=tiles)

var_select.param.watch(on_var_select, parameter_names=['value']);
map_select.param.watch(on_map_select, parameter_names=['value']);

col = pn.Column(var_select, map_select, plot(var_select.value) * tiles)

производство: enter image description here

Вот полный блокнот .

0 голосов
/ 19 февраля 2019

Так что здесь есть длинный ответ и короткий ответ.Давайте начнем с короткого ответа, который заключается в том, что нет необходимости создавать пользовательский виджет выбора для переменной данных, поскольку hvPlot позволяет автоматически выбирать между несколькими переменными данных, поэтому, если вы измените его на следующее:

rasterized_mesh = ds[time_vars].hvplot.quadmesh(
    x='x', y='y', z=time_vars[::-1], crs=crs, width=600, height=400, 
    groupby=list(ds[var].dims[:-2]), rasterize=True, cmap='jet')

enter image description here

Вы получите DynamicMap, который позволяет выбирать непространственные измерения и переменную данных, и теперь вы можете встраивать их в свою панель, не требуя дополнительной работы.Если это все, что вас волнует , остановитесь здесь , так как мы собираемся войти в некоторые из внутренних органов, чтобы, как мы надеемся, обеспечить лучшее понимание.

Допустим, в течение минуты hvPlot не позволял выбиратьмежду переменными данных, что мы будем делать тогда?Итак, главное, что вам нужно знать, это то, что HoloViews позволяет создавать цепочки DynamicMaps, но не позволяет их вкладывать.Это может быть немного сложно обернуть голову, но мы разберем проблему на несколько этапов, а затем посмотрим, как мы можем достичь того, чего хотим.Так что же представляет собой цепочка событий, которая дала бы нам наш график?

  1. Выберите переменную данных
  2. Примените групповую обработку над непространственными измерениями
  3. Применить растеризациюк каждому QuadMesh

Как вы знаете, hvPlot заботится о шагах 2. и 3. для нас, так как мы можем внедрить шаг 1. до 2. и 3. В будущем мы планируем добавить поддержкудля передачи виджетов панели непосредственно в hvPlot, что означает, что вы сможете сделать все это за один шаг.Поскольку панель все еще является очень новым проектом, я покажу, как наши API в конечном итоге сделают этот процесс тривиальным, но сейчас нам придется придерживаться относительно многословного обходного пути.В этом случае мы должны изменить порядок операций:

  1. Применить групповую обработку по непространственным измерениям
  2. Выбрать переменную данных
  3. Применить растеризацию к каждомуQuadMesh

Для начала мы выбираем все переменные данных и пропускаем растеризацию:

meshes = ds[time_vars].hvplot.quadmesh(
    x='x', y='y', z=time_vars, crs=crs, width=600, height=400, 
    groupby=list(ds[var].dims[:-2]))

Теперь, когда у нас есть DynamicMap, который содержит все данныемы могли бы хотеть показать, что мы можем применить следующие операции.Здесь мы воспользуемся утилитой hv.util.Dynamic, которую можно использовать для цепочки операций над DynamicMap при вводе потоковых значений.В частности, на этом шаге мы создаем поток из виджета var_select, который будет использоваться для переиндексации QuadMesh внутри наших сеток DynamicMap:

def select_var(obj, var):
    return obj.clone(vdims=[var])

var_stream = Params(var_select, ['value'], rename={'value': 'var'})
var_mesh = hv.util.Dynamic(meshes, operation=select_var, streams=[var_select])

# Note starting in hv 1.12 you'll be able to replace this with
# var_mesh = meshes.map(select_var, streams=[var_select])

# And once param 2.0 is out we intend to support
# var_mesh = meshes.map(select_var, var=var_select.param.value)

Теперь у нас есть DynamicMap, который реагирует на измененияв виджете, но еще не растеризовали его, поэтому мы можем применить операцию rasterize вручную:

rasterized_mesh = rasterize(var_mesh).opts(cmap='jet', width=600, height=400)

Теперь у нас есть DynamicMap, который связан с виджетом Selection, применяет групповую передачу и растеризуется, чтоТеперь мы можем встроить в панель.Другой подход, на который ссылается @jbednar выше, состоит в том, чтобы сделать все это за один шаг, сделав вызов hvPlot не динамическим и сделав выбор уровня времени и высоты вручную.Я не буду подробно останавливаться на этом, но это также правильный (хотя и менее эффективный) подход.

Как я уже говорил выше, в конечном итоге мы также намереваемся сделать все параметры hvPlot динамическими,это означает, что вы сможете сделать что-то подобное, чтобы связать значение виджета с аргументом ключевого слова hvPlot:

ds[time_vars].hvplot.quadmesh(
    x='x', y='y', z=var_select.param.value, rasterize=True, crs=crs,
    width=600, height=400, groupby=list(ds[var].dims[:-2]), cmap='jet')
...