我正在尝试创建一个包含两个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
当我从面板小部件中选择一个变量时,我想更新地图: 我尝试将其作为动态地图进行操作,如下所示:
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完成此操作的最佳方法是什么?
如果有用的话,这里是我的full attempt Jupyter Notebook。
答案 0 :(得分:3)
由于每个选定变量的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)
这里是full notebook。
答案 1 :(得分:0)
因此,这里有一个长答案和一个简短答案。让我们从一个简短的答案开始,即无需为数据变量创建自定义选择小部件,因为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')
您将获得一个DynamicMap,可让您选择非空间尺寸和数据变量,现在您可以将其嵌入到面板中,而无需进行其他工作。如果这就是您所关心的全部,请在此处停止,因为我们将要深入了解一些内部信息,以期更好地理解。
让我们假设一分钟,hvPlot不允许在数据变量之间进行选择,那么我们该怎么办?因此,您必须知道的主要事情是HoloViews允许链接DynamicMap,但不允许嵌套它们。这可能会有点困难,但是我们将把问题分解成多个步骤,然后看看如何实现我们想要的。那么,什么事件链会给我们带来阴谋呢?
如您所知,hvPlot为我们执行了步骤2和3.。因此,我们如何在步骤2和3之前注入步骤1。将来,我们计划增加对将面板小部件直接传递到hvPlot中的支持。意味着您将能够一步一步完成所有操作。由于panel仍然是一个非常新的项目,我将在我们的API最终使该过程变得微不足道的过程中指出,但是现在我们必须坚持相对冗长的解决方法。在这种情况下,我们必须重新安排操作顺序:
因此,我们首先选择所有数据变量,然后跳过光栅化:
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小部件,应用groupby并被栅格化,现在我们可以将其嵌入面板中。上面@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')