首页 > 解决方案 > 在 Holoviews 中结合 Pointdraw 和 Sample

问题描述

我正在尝试将 Holoviews 的Pointdraw功能与其示例功能相结合(我找不到特定页面,但它在此处显示为实际操作http://holoviews.org/gallery/demos/bokeh/mandelbrot_section.html

具体来说,我想要两个具有交互性的子图。左侧显示颜色图,右侧显示颜色图的示例(线切)。这是通过.sample. 在这个正确的情节中,我希望有可以绘制、移动和删除的点,通常使用pointdraw. 然后,我还想在完成移动后访问它们的坐标,这在遵循文档中的示例时是可能的。

现在,按照上面的例子,我已经让这两个独立工作了。但是当以我所拥有的方式组合时,这会产生一个看起来像这样的图: 在此处输入图像描述 它具有我正在寻找的元素,除了无法与之交互的点。这在某种程度上与 Holoviews 的流有关,但我不知道如何解决它。有人可以帮忙吗?

生成上述代码的代码:

%%opts Points (color='color' size=10) [tools=['hover'] width=400 height=400] 
%%opts Layout [shared_datasource=True] Table (editable=True)

import param
import numpy as np
import holoviews as hv
hv.extension('bokeh', 'matplotlib')
from holoviews import streams

def lorentzian(x, x0, gamma):
    return 1/np.pi*1/2*gamma/((x-x0)**2+(1/2*gamma)**2)

xs = np.arange(0,4*np.pi,0.05)
ys = np.arange(0,4*np.pi,0.05)
data = hv.OrderedDict({'x': [2., 2., 2.], 'y': [0.5, 0.4, 0.2], 'color': ['red', 'green', 'blue']})

z = lorentzian(xs.reshape(len(xs),1),2*np.sin(ys.reshape(1,len(ys)))+5,1) + lorentzian(xs.reshape(len(xs),1),-2*np.sin(ys.reshape(1,len(ys)))+5,1)

def dispersions(f0):
    points = hv.Points(data, vdims=['color']).redim.range(x=(xs[0], xs[-1]), y=(np.min(z), np.max(z)))
    point_stream = streams.PointDraw(data=points.columns(), source=points, empty_value='black')
    image = hv.Image(z, bounds=(xs[0], ys[0], xs[-1], ys[-1]))
    return image* hv.VLine(x=f0) + image.sample(x=f0)*points

dmap = hv.DynamicMap(dispersions, kdims=['f0'])
dmap.redim.range(f0=(0,10)).redim.step(f0=(0.1))

对于我们正在绘制的奇怪函数,我深表歉意,我无法立即想出一个简单的函数。

标签: pythonholoviews

解决方案


根据您的示例,我还不太清楚您将如何处理这些点,但我确实有一些关于更好地构建代码的建议。

一般来说,从几个单独的 DynamicMap 中组合绘图总是比创建一个可以完成所有工作的单个 DynamicMap 更好。它不仅更具可组合性,而且您还可以获得单个对象的句柄,从而允许您设置流以侦听每个组件的更改,最重要的是它更有效,只有需要更新的图才会更新。在您的示例中,我将代码拆分如下​​:

def lorentzian(x, x0, gamma):
    return 1/np.pi*1/2*gamma/((x-x0)**2+(1/2*gamma)**2)

xs = np.arange(0,4*np.pi,0.05)
ys = np.arange(0,4*np.pi,0.05)
data = hv.OrderedDict({'x': [2., 2., 2.], 'y': [0.5, 0.4, 0.2], 'color': ['red', 'green', 'blue']})

points = hv.Points(data, vdims=['color']).redim.range(x=(xs[0], xs[-1]), y=(np.min(z), np.max(z)))
image = hv.Image(z, bounds=(xs[0], ys[0], xs[-1], ys[-1]))

z = lorentzian(xs.reshape(len(xs),1),2*np.sin(ys.reshape(1,len(ys)))+5,1) + lorentzian(xs.reshape(len(xs),1),-2*np.sin(ys.reshape(1,len(ys)))+5,1)
taps = []

def vline(f0):
    return hv.VLine(x=f0)

def sample(f0):
    return image.sample(x=f0)

dim = hv.Dimension('f0', step=0.1, range=(0,10))
vline_dmap = hv.DynamicMap(vline, kdims=[dim])
sample_dmap = hv.DynamicMap(sample, kdims=[dim])
point_stream = streams.PointDraw(data=points.columns(), source=points, empty_value='black')

(image * vline_dmap + sample_dmap * points)

由于图像和点本身不是动态的,因此没有理由将它们放在 DynamicMap 中,并且 VLine 和采样曲线很容易被拆分出来。PointDraw 流还没有做任何事情,但您现在可以将其设置为另一个 DynamicMap,您可以将其与其余部分组合。


推荐阅读