在 Holoviews 中结合 Pointdraw 和 Sample
Combining Pointdraw and Sample in Holoviews
我正在尝试结合 Holoviews' Pointdraw functionality with its Sample functionality (I couldn't find a specific page, but it is shown in action here 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))
对于我们正在绘制的奇怪函数,我深表歉意,我无法立即想出一个简单的函数。
根据你的例子,我还不太清楚你将用这些点做什么,但我确实有一些关于更好地构建代码的建议。
一般来说,从几个单独的 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,您可以将其与其他流组合。
我正在尝试结合 Holoviews' Pointdraw functionality with its Sample functionality (I couldn't find a specific page, but it is shown in action here http://holoviews.org/gallery/demos/bokeh/mandelbrot_section.html)
具体来说,我想要两个具有交互性的子图。左图显示了颜色图,右图显示了颜色图的样本(线切割)。这是通过 .sample
实现的。在这个右边的图中,我想要可以绘制、移动和删除的点,通常使用 pointdraw
完成。然后我还想在完成移动后访问它们的坐标,这在遵循文档中的示例时是可能的。
现在,按照上面的示例,我已经让这两个独立工作了。但是当以我的方式组合时,这会导致一个看起来像这样的情节:
生成上面的代码:
%%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))
对于我们正在绘制的奇怪函数,我深表歉意,我无法立即想出一个简单的函数。
根据你的例子,我还不太清楚你将用这些点做什么,但我确实有一些关于更好地构建代码的建议。
一般来说,从几个单独的 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,您可以将其与其他流组合。