在Holoviews中结合Pointdraw和Sample

时间:2018-11-12 15:29:23

标签: python holoviews

我正在尝试将Holoviews的Pointdraw功能与其示例功能结合在一起(我找不到特定的页面,但在此处http://holoviews.org/gallery/demos/bokeh/mandelbrot_section.html中对此进行了展示)

具体来说,我想有两个具有交互性的子图。左侧的一个显示一个颜色图,右侧的一个显示颜色图的样本(线条)。这是通过.sample实现的。在这个右图中,我希望可以绘制,移动和删除点,通常使用pointdraw完成。然后,我还想在完成移动后访问它们的坐标,这可以按照文档中的示例进行操作。

现在,按照上面的示例,我让两个人独立工作。但是,当按照我的方式组合时,这将导致如下图所示: enter image description here 它具有我要寻找的元素,但不能与这些点交互。这在某种程度上与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))

我为我们正在绘制的怪异函数表示歉意,我无法立即提出一个简单的函数。

1 个答案:

答案 0 :(得分:3)

根据您的示例,我还不太清楚您将如何处理这些要点,但是我对如何更好地构建代码提出了一些建议。

通常,由多个单独的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,可以与其余部分组成。