Saturday, 31 August 2019

interactive scatter highlight in bokeh

I am trying to visualise sensor output in relation to its path.
I plot path as scatter in one figure and some range of signal amplitude in the second figure. I need to visualise (highlight) a path point at which the particular reading was taken.

I started using bokeh as a backend and in general, got very good results with visualisations I need. But I am stuck on this particular interaction.

I would like to have some marker like a vertical line anchored in the middle of the figure. When I move/scroll the amplitude plot (the bottom one), I would like to highlight the point on the path plot where the reading closest to the marker line was taken.

The example code:
(I would like to anchor the marker line and add interaction between the red dot and the vertical line taking an index of the signal, which is not implemented.)

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(tools=self.TOOLS, 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(tools=self.TOOLS, 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



from interactive scatter highlight in bokeh

No comments:

Post a Comment