使用显示小部件查看视图与可见视图

时间:2019-06-10 16:57:08

标签: python panel holoviews geoviews pyviz

我正在使用pyviz生态系统构建一个交互式仪表板。仪表板的一个功能是基础数据可以基于小部件选择器进行更改。下面是一个示例代码,显示我在显示时间小部件滑块时遇到的问题:

软件包版本
面板:0.5.1
参数:1.9.0
holoviews:1.12.3
地理位置: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小部件-在此示例中未显示),则不会重绘图像。但是,在第二个示例中,图像被重绘,但是我缺少时间滑块。

更新-解决方案

根据James的解决方案,这是解决方法(谢谢!)。此示例包括更改数据集和变量(在每个数据集中)和时间参数。

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 :(得分:0)

此代码看起来像是从我的http://datashader.org/dashboard.html示例中派生的。在我的示例中,viewable()方法的输出已经是完全动态的,并且不需要重新生成,它已经在内部链接到影响其外观的所有小部件和控件。而如果您将viewable作为方法名称传递给Panel(而不是调用该方法的结果),则您是在要求Panel确定是否需要调用viewable()时为您调用初始调用的结果将过时。这种简单的重新运行方法适用于非常简单的全有或全无的计算情况,但是当对象本身已经是动态的并且特定控件与图的特定方面相关联时,在此情况下并没有真正的用处。 (为什么我不确定这种情况下为什么还没有时间窗口小部件;这不是推荐的用法,但我认为它在为您提供窗口小部件时仍然可以使用。)

无论如何,我认为您不应该尝试使上面的第二种情况起作用,而只有第一种情况起作用。那里的问题不是缺少滑块,这听起来像是您正在尝试使绘图对数据源的更改做出响应。幸运的是,在http://datashader.org/dashboard.html的示例中已经说明了这种情况。 rasterize动态包装了一个方法,该方法返回要显示的数据的适当列。您应该能够采用这种方法,使其动态反映其他一些允许用户选择数据集的小部件的状态。