使用显示小部件查看与可见 [英] View vs. Viewable with displaying widget

查看:95
本文介绍了使用显示小部件查看与可见的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am putting together an interactive dashboard using the pyviz ecosystem. One feature of the dashboard is that the underlying data may change based on a widget selector. Below is an example code showing the issue I have with getting the time widget slider to appear:

软件包版本:
面板:0.5.1
参数:1.9.0
holoviews:1.12.3
地理位置:1.6.2

Package Versions:
panel: 0.5.1
param: 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()

时间窗口小部件出现:

The time widget appears:

位置:

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

在第一个示例中,如果我选择备用数据集(基于param.Selector小部件-在此示例中未显示),则不会重绘图像.但是,在第二个示例中,图像被重绘,但是我缺少时间滑块.

In the first example, if I select an alternative dataset (based on a param.Selector widget - not shown in this example) it does not redraw the image. However, in the 2nd example, the image is redrawn, but I am missing the time slider.

更新-解决方案

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

Here is the workaround as per James' solutions (thanks!). This example includes changing the dataset and the variable (within each dataset) and the time parameter.

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()

干杯!

推荐答案

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

This code looks like it's derived from my http://datashader.org/dashboard.html example. In my example, the output from the viewable() method is already fully dynamic, and does not ever need to be regenerated, being already linked internally to all the widgets and controls that affect how it appears. Whereas if you pass viewable as a method name to Panel (rather than result of calling that method), you're asking Panel to call viewable() for you whenever it determines that the result from an initial call becomes stale. This simple re-run-the-method approach is appropriate for very simple cases of all-or-nothing computation, but not really useful here when the objects are already dynamic themselves and where specific controls are tied to specific aspects of the plot. (Why you also don't get a time widget in that case I'm not sure; it's not a recommended usage, but I would have thought it should still work in giving you a widget.)

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

Anyway, I don't think you should be trying to get the second case above to work, only the first one. And there the problem isn't the lack of the slider, it sounds like it's that you're trying to get the plot to be responsive to changes in your data source. Luckily, that case is already illustrated in the example in http://datashader.org/dashboard.html ; there rasterize dynamically wraps a method that returns the appropriate column of the data to show. You should be able to adapt that approach to make it dynamically reflect the state of some other widget that lets the user select the dataset.

这篇关于使用显示小部件查看与可见的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆