散景中的交互式散点图

时间:2019-08-26 17:14:34

标签: python bokeh

我正在尝试可视化传感器输出相对于其路径的变化。
我在一个图中绘制路径为散点图,在第二个图中绘制信号幅度的某个范围。我需要可视化(突出显示)获取特定读数的路径点。

我开始使用bokeh作为后端,并且总体上,我需要的可视化效果非常好。但是我被这种特殊的互动所困扰。

我想在图的中间锚定一些标记,例如垂直线。当我移动/滚动幅度图(底部)时,我想突出显示路径图上最接近标记线的点。

示例代码:
(我想锚定标记线,并在红点和垂直线之间添加交互,以获取信号索引,但未实现。)

import numpy as np
import pandas as pd
from bokeh.io import output_file
from bokeh.models import ColumnDataSource, HoverTool, Span
from bokeh.plotting import figure, show
from bokeh.layouts import gridplot

output_file('interactive_path_sig.html', title="interactive path")

class InteractivePath():
    def __init__(self):
        x = np.arange(0, 1000, 0.5)
        self.df = pd.DataFrame({"x": x,
                                "y": np.sin(x),
                                "z": np.cos(x)})
        self.source = ColumnDataSource(self.df)

    def plot_path(self):
        plt = figure(title = "Sensor Path")
        plt.scatter(x="x", y="y",source=self.source, 
                    line_color=None, size = 6)
        # TODO implement interaction instead of hard coded index
        index=500    # this is where I think I need to create working callback
        print("x={}, y={}".format(self.df['x'][index], self.df['y'][index]))
        plt.circle(x=self.df['x'][index], y=self.df['y'][index], 
                   fill_color="red", size=15)
        hover = HoverTool()
        hover.tooltips=[("index", "@index"), ("senosr","@z")]
        plt.add_tools(hover)
        return plt

    def plot_signal(self):
        plt = figure(x_range=(450, 550), title="Signal Amplitude")
        plt.line(x="index", y="z", source=self.source, line_color="black", line_width=2)
        # TODO implement interaction instead of hard coded index
        index = 500  # I think this needs emit some singal to other plot
        vline = Span(location=index, dimension='height', line_color='red', line_width=3)
        plt.renderers.extend([vline])
        return plt

    def get_grid(self):
        """ place visualisation in a grid and display"""
        grid = gridplot([[self.plot_path()], [self.plot_signal()]], 
                 sizing_mode='stretch_both',)
        return grid

    def vis_main(self):
        """ use all visualisations"""
        show(self.get_grid())

if __name__=="__main__":
    vis = InteractivePath()
    vis.vis_main()

enter image description here enter image description here

1 个答案:

答案 0 :(得分:3)

一些指针:

  • 我想您会希望使用相同的方法来绘制这两个图,因为columndatasource在它们之间是公用的,并且如果它们在同一范围内,则可以在它们之间设置CustomJS行为。
  • 您正在使用的index已存在于您的self.df中,一旦您将其放置在绘图上,它就更易于与之交互,因为您可以使用JS绘图行为来处理它,而不用返回到python变量并重新加载数据。
  • 与其为您的“突出显示”点绘制一个新的字形,不如考虑使用内置的“悬停”或“选定”功能。例如,hover_color='red'可以代替绘制并移动另一类字形。如果您希望保持静态选择状态,以便在屏幕快照中无需鼠标即可生成精美的报告,请使用selected的内置ColumnDataSource属性定义回调。

我可以用一些更具体的示例发布一些实际的代码块,但是如果这些要点对于您的实际用例来说是很难的,那么它将为您提供解决方案。


编辑:

所以我使用一种类方法非常接近-问题是能够从第一种方法编辑第二个图,而不是对ColumnDataSource本身的实际更改。

def plot_it(self):
    self.plot_signal = figure(x_range=(450, 550), y_range=(-1, 1), title='signal')
    self.plot_signal.line(x='index', y='z', source=self.source)
    self.plot_signal.segment(x0=500, y0=-2, x1=500, y1=2, source=self.source)

    self.plot_path = figure(title='sensor')
    self.plot_path.scatter(x='x', y='y', source=self.source, hover_color='red')

    jscode='''
    var data = source.data;
    var plot_signal = plot_signal;
    var index = cb_data.index['1d'].indices;
    var xmin = 0;
    var xmax = 0;
    if (index > 0) {
        xmin = index[0] - 50;
        xmax = index[0] + 50;
        plot_signal.x_range.end = xmax;
        plot_signal.x_range.start = xmin;
        plot_signal.change.emit();
    }

    hover_callback = CustomJS(args=dict(source=self.source, plot_signal=self.plot_signal), code=jscode)
    hover.tooltips = [('index', '@index'), ('sensor', '@z')]
    self.plot_path.add_tools(hover)

def get_grid(self):
    self.plot_it()
    grid = gridplot([[self.plot_path], [self.plot_signal]])
    return grid

除了移动线段外,其他所有操作均应执行。我找不到添加plot_signal.SOMEOBJECT.x0.x1的句段命名约定,但是就像使用if (index > 0)一样,它将被添加到index[0]块中。我删除了一些样式选项,因为我正在从另一台计算机上转录。

moving a line segment上的这个问题可能会为您提供细分JSON对象的语法。