Просмотр и просмотр с отображением виджета - PullRequest
1 голос
/ 10 июня 2019

Я собираю интерактивную панель, используя экосистему pyviz.Одной из особенностей панели инструментов является то, что базовые данные могут изменяться в зависимости от селектора виджета.Ниже приведен пример кода, показывающий проблему, с которой я столкнулся, когда появился ползунок виджета времени:

Версии пакета :
панель: 0.5.1
параметр: 1.9.0
holoviews: 1.12.3
geoviews: 1.6.2

Пример :

import xarray as xr
import panel as pn
import numpy as np
import param as pm
import holoviews as hv
import geoviews as gv
from matplotlib import cm
import geoviews.tile_sources as gts
from holoviews.operation.datashader import rasterize
from collections import OrderedDict as odict
from holoviews import opts
renderer = hv.renderer('bokeh')
pn.extension()

dset = xr.DataArray(np.random.random((100,100,100)),coords={'X':np.arange(100),'Y':np.arange(100),'T':np.arange(100)},dims=['X','Y','T']).to_dataset(name='test')
dset = gv.Dataset(dset, ['X', 'Y', 'T'], 'test').to(gv.QuadMesh, groupby='T').opts(cmap='viridis', colorbar=True, show_frame=False)

fields = odict([('test','test')])#odict([(v.get('label',k),k) for k,v in source.metadata['fields'].items()])
aggfns = odict([(f.capitalize(),f) for f in ['mean','std','min','max','Pixel Level']])#'count','sum','min','max','mean','var','std']])#,'None (Pixel Level)']])
cmaps  = odict([(n,cm.get_cmap(n)) for n in ['viridis','seismic','cool','PiYG']])
maps   = ['EsriImagery','EsriNatGeo', 'EsriTerrain', 'OSM']
bases  = odict([(name, gts.tile_sources[name].relabel(name)) for name in maps])
gopts  = hv.opts.WMTS(responsive=True, xaxis=None, yaxis=None, bgcolor='black', show_grid=False)


class Explorer_Test(pm.Parameterized):
    field = pm.Selector(fields)
    cmap = pm.Selector(cmaps)
    basemap = pm.Selector(bases)
    data_opacity = pm.Magnitude(1.00)
    map_opacity = pm.Magnitude(1.00)
    agg_fn_ = pm.Selector(aggfns,label='Aggregation**',default='mean')

    @pm.depends('field', 'agg_fn_')
    def aggregator(self):
        field = None if self.field == "counts" else self.field
        return self.agg_fn(field)

    @pm.depends('map_opacity', 'basemap')
    def tiles(self):
        return self.basemap.opts(gopts).opts(alpha=self.map_opacity)

    def viewable(self,**kwargs):
        rasterized = rasterize(dset, precompute=True).opts(colorbar=True, height=800, show_frame=False).apply.opts(cmap=self.param.cmap,alpha=self.param.data_opacity)
        return hv.DynamicMap(self.tiles)*rasterized

explorer_test = Explorer_Test(name="")

Когда я отображаю график как:

panel = pn.Row(pn.Param(explorer_test.param, expand_button=False),explorer_test.viewable())
panel.servable()

Появляется виджет времени: enter image description here

Принимая во внимание:

panel = pn.Row(pn.Param(explorer_test.param, expand_button=False),explorer_test.viewable)
panel.servable()

enter image description here

В первом примере, если я выбираю альтернативный набор данных (на основе виджета param.Selector - не показан в этом примере), он не перерисовывает изображение.Однако во втором примере изображение перерисовывается, но мне не хватает ползунка времени.

ОБНОВЛЕНИЕ - Решение

Вот обходной путь в соответствии с решениями Джеймса(Спасибо!).Этот пример включает в себя изменение набора данных и переменной (внутри каждого набора данных) и параметра времени.

import xarray as xr
import panel as pn
import numpy as np
import param as pm
import holoviews as hv
import geoviews as gv
from holoviews.operation.datashader import rasterize
from collections import OrderedDict as odict
renderer = hv.renderer('bokeh')
pn.extension()

#Define Example Datasets
dset1 = xr.merge([xr.DataArray(np.random.random((50,50,50)),coords={'X':np.arange(50),'Y':np.arange(50),'T':np.arange(50)},dims=['X','Y','T']).to_dataset(name='var1'),
                  xr.DataArray(np.random.random((50,50,10))*.1,coords={'X':np.arange(50),'Y':np.arange(50),'T':np.arange(10)},dims=['X','Y','T']).to_dataset(name='var2')])
dset2 = xr.DataArray(np.random.random((50,50,20))*10,coords={'X':np.arange(50)/2.,'Y':np.arange(50)/3.,'T':np.arange(20)},dims=['X','Y','T']).to_dataset(name='var1')
data_dict = {'dset1':dset1,'dset2':dset2}                 

#Plot Datasets
class sel_dset_var():
    def dset1_var1():
        return rasterize(gv.Dataset(dset1.var1, ['X', 'Y', 'T'], 'test1').to(gv.QuadMesh, groupby='T')()).opts(cmap='viridis',colorbar=True, height=200, show_frame=False)
    def dset1_var2():
        return rasterize(gv.Dataset(dset1.var2, ['X', 'Y', 'T'], 'test1').to(gv.QuadMesh, groupby='T')()).opts(cmap='viridis',colorbar=True, height=200, show_frame=False)
    def dset2_var1():
        return rasterize(gv.Dataset(dset2.var1, ['X', 'Y', 'T'], 'test1').to(gv.QuadMesh, groupby='T')()).opts(cmap='viridis',colorbar=True, height=200, show_frame=False)

#Dashboard
class Explorer_Test(pm.Parameterized):
    dset = pm.Selector(odict([('Dataset1','dset1'),('Dataset2','dset2')]),default='dset1')
    varss = pm.Selector(list(dset1.data_vars),default=list(dset1.data_vars)[0])
    time1 = pm.Selector(dset1.var1.coords['T'].values,default=dset1.var1.coords['T'].values[0])

    @pm.depends('dset',watch=True)
    def update_var(self):
        self.param['varss'].objects = list(data_dict[self.dset].data_vars)
        self.param.set_param(varss=list(data_dict[self.dset].data_vars)[0])

    @pm.depends('dset',watch=True)
    def update_var(self):
        self.param['varss'].objects = list(data_dict[self.dset].data_vars)
        self.param.set_param(varss=list(data_dict[self.dset].data_vars)[0])

    def elem(self):
        return getattr(sel_dset_var,self.dset+'_'+self.varss)()

    @pm.depends('varss','dset',watch=True)
    def update_time(self):
        self.param['time1'].objects =data_dict[self.dset][self.varss].dropna(dim='T').coords['T'].values
        self.param.set_param(time1=data_dict[self.dset][self.varss].dropna(dim='T').coords['T'].values[0])

    def elem_yr(self):
        return getattr(self.elem(),'select')(T=self.time1)


    def viewable(self,**kwargs):
        return self.elem_yr

explorer_test = Explorer_Test(name="")
panel = pn.Row(pn.Param(explorer_test.param, expand_button=False),explorer_test.viewable())
panel.servable()

enter image description here

Приветствия!

1 Ответ

0 голосов
/ 10 июня 2019

Этот код выглядит, как будто он получен из моего http://datashader.org/dashboard.html примера. В моем примере выходные данные метода viewable() уже полностью динамичны и не нуждаются в регенерации, поскольку уже связаны внутренне со всеми виджетами и элементами управления, влияющими на его внешний вид. Принимая во внимание, что если вы передаете viewable в качестве имени метода в Panel (а не результат вызова этого метода), вы просите Panel вызывать viewable() для вас всякий раз, когда он определяет, что результат начального звонок становится устаревшим. Этот простой подход повторного запуска метода подходит для очень простых случаев вычисления «все или ничего», но не очень полезен здесь, когда объекты уже сами по себе являются динамическими и когда конкретные элементы управления связаны с конкретными аспектами графика. (Почему вы также не получаете виджет времени в этом случае, я не уверен; это не рекомендуемое использование, но я бы подумал, что оно все равно должно работать для предоставления вам виджета.)

В любом случае, я не думаю, что вы должны пытаться заставить работать второй вышеупомянутый случай, только первый. И проблема не в отсутствии ползунка, а в том, что вы пытаетесь заставить график реагировать на изменения в источнике данных. К счастью, этот случай уже проиллюстрирован в примере в http://datashader.org/dashboard.html; rasterize динамически переносит метод, который возвращает соответствующий столбец данных для отображения. Вы должны иметь возможность адаптировать этот подход, чтобы он динамически отражал состояние какого-либо другого виджета, который позволяет пользователю выбирать набор данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...