AJbotic
AJbotic

Reputation: 85

Dynamically link a Span and a Slider in a python bokeh plot

I am trying to create plots in python using bokeh that allow dynamic visualization of data in bins. It's worth knowing that I am relatively new to python, very new to bokeh, and I know ZERO javascript. I have consulted this:

Link a Span or Cursor in between plots with Bokeh in Python

and this:

http://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html

but am having trouble implementing the necessary parts of each. Here is my code prior to adding the requested capabilities:

from bokeh.layouts import column, widgetbox
from bokeh.models.widgets import Slider
from bokeh.models import Span, CustomJS

output_file('Raw_Spectra_and_Spillover_Data.html')

# widgets for bin setup
Pix1_LowLow = Slider(start = self.StartDAC, end = self.EndDAC, value = 129, step = 1, title = 'Pixel-1 - Low Bin - Low Thresh')
Pix1_LowHigh = Slider(start = self.StartDAC, end = self.EndDAC, value = 204, step = 1, title = 'Pixel-1 - Low Bin - High Thresh')
Pix1_HighLow = Slider(start = self.StartDAC, end = self.EndDAC, value = 218, step = 1, title = 'Pixel-1 - High Bin - Low Thresh')
Pix1_HighHigh = Slider(start = self.StartDAC, end = self.EndDAC, value = 500, step = 1, title = 'Pixel-1 - High Bin - High Thresh')

plot1spect = figure(width=700, height=250, title='pixel-1 Spectrum')
plot1spect.line(self.SpectDACvals1[0], self.SpectrumData1[0], line_width=2)
plot1spect_LowLowSpan = Span(location=Pix1_LowLow.value, dimension = 'height')
plot1spect_LowHighSpan = Span(location=Pix1_LowHigh.value, dimension = 'height')
plot1spect_HighLowSpan = Span(location=Pix1_HighLow.value, dimension = 'height')
plot1spect_HighHighSpan = Span(location=Pix1_HighHigh.value, dimension = 'height')
plot1spect.renderers.extend([plot1spect_LowLowSpan, plot1spect_LowHighSpan, plot1spect_HighLowSpan, plot1spect_HighHighSpan])

plot1spill = figure(width=700, height=250, title='pixel-1 Spillover')
plot1spill.line(self.SpillDACvals1[0], self.SpillData1[0], line_width=2)
plot1spill_LowLowSpan = Span(location=Pix1_LowLow.value, dimension = 'height')
plot1spill_LowHighSpan = Span(location=Pix1_LowHigh.value, dimension = 'height')
plot1spill_HighLowSpan = Span(location=Pix1_HighLow.value, dimension = 'height')
plot1spill_HighHighSpan = Span(location=Pix1_HighHigh.value, dimension = 'height')
plot1spill.renderers.extend([plot1spill_LowLowSpan, plot1spill_LowHighSpan, plot1spill_HighLowSpan, plot1spill_HighHighSpan])

show(row(plot1spect,plot1spill, widgetbox(Pix1_LowLow, Pix1_LowHigh, Pix1_HighLow, Pix1_HighHigh)))

This code gives me this:

Bokeh plot of code above.

If someone can show me how get Pix1_LowLow slider to dynamically control the location of plot1spect_LowLowSpan, then I can extend the technique to the other sliders and spans. Many thanks in advance!

python 3.5.2 - bokeh 12.0

Upvotes: 6

Views: 2883

Answers (2)

bigreddot
bigreddot

Reputation: 34568

Here is a minimal complete example. Note that the recommended way to add annotations like Span is with plot.add_layout as shown below:

from bokeh.layouts import row, widgetbox
from bokeh.models import Slider, Span, CustomJS
from bokeh.plotting import figure, output_file, show

slider = Slider(start=0, end=10, value=3, step=0.1, title='Slider')

plot = figure(width=700, height=250, x_range=(0,10), y_range=(-1, 1))
span = Span(location=slider.value, dimension='height')
plot.add_layout(span)

callback = CustomJS(args=dict(span=span), code="""
    span.location = cb_obj.value
""")
slider.js_on_change('value', callback)

output_file('span_slider.html')

show(row(plot, widgetbox(slider)))

Upvotes: 6

AJbotic
AJbotic

Reputation: 85

Thanks to @bigreddot for providing the answer. This is the code that implemented my solution specifically... Now how to do this programmatically for 128 data files... hmmmm..

    from bokeh.layouts import row, widgetbox
    from bokeh.models import Span, CustomJS, Slider

    output_file('Raw_Spectra_and_Spillover_Data.html')

    # widgets for bin setup
    Pix1_LowLow = Slider(start = self.StartDAC, end = self.EndDAC, value = 129, step = 1, title = 'Pixel-1 - Low Bin - Low Thresh')
    Pix1_LowHigh = Slider(start = self.StartDAC, end = self.EndDAC, value = 204, step = 1, title = 'Pixel-1 - Low Bin - High Thresh')
    Pix1_HighLow = Slider(start = self.StartDAC, end = self.EndDAC, value = 218, step = 1, title = 'Pixel-1 - High Bin - Low Thresh')
    Pix1_HighHigh = Slider(start = self.StartDAC, end = self.EndDAC, value = 500, step = 1, title = 'Pixel-1 - High Bin - High Thresh')

    plot1spect = figure(width=700, height=250, title='pixel-1 Spectrum')
    plot1spect.line(self.SpectDACvals1[0], self.SpectrumData1[0], line_width=2)
    plot1spect_LowLowSpan = Span(location=Pix1_LowLow.value, dimension = 'height')
    plot1spect.add_layout(plot1spect_LowLowSpan)
    plot1spect_LowHighSpan = Span(location=Pix1_LowHigh.value, dimension = 'height')
    plot1spect.add_layout(plot1spect_LowHighSpan)
    plot1spect_HighLowSpan = Span(location=Pix1_HighLow.value, dimension = 'height')
    plot1spect.add_layout(plot1spect_HighLowSpan)
    plot1spect_HighHighSpan = Span(location=Pix1_HighHigh.value, dimension = 'height')
    plot1spect.add_layout(plot1spect_HighHighSpan)
    #plot1spect.renderers.extend([plot1spect_LowLowSpan, plot1spect_LowHighSpan, plot1spect_HighLowSpan, plot1spect_HighHighSpan])

    plot1spill = figure(width=700, height=250, title='pixel-1 Spillover')
    plot1spill.line(self.SpillDACvals1[0], self.SpillData1[0], line_width=2)
    plot1spill_LowLowSpan = Span(location=Pix1_LowLow.value, dimension = 'height')
    plot1spill.add_layout(plot1spill_LowLowSpan)
    plot1spill_LowHighSpan = Span(location=Pix1_LowHigh.value, dimension = 'height')
    plot1spill.add_layout(plot1spill_LowHighSpan)
    plot1spill_HighLowSpan = Span(location=Pix1_HighLow.value, dimension = 'height')
    plot1spill.add_layout(plot1spill_HighLowSpan)
    plot1spill_HighHighSpan = Span(location=Pix1_HighHigh.value, dimension = 'height')
    plot1spill.add_layout(plot1spill_HighHighSpan)
    #plot1spill.renderers.extend([plot1spill_LowLowSpan, plot1spill_LowHighSpan, plot1spill_HighLowSpan, plot1spill_HighHighSpan])

    Pix1_LowLow.callback = CustomJS(args=dict(span1 = plot1spect_LowLowSpan,
                                              span2 = plot1spill_LowLowSpan,
                                              slider = Pix1_LowLow),
                                              code = """span1.location = slider.value; span2.location = slider.value""")
    Pix1_LowHigh.callback = CustomJS(args=dict(span1 = plot1spect_LowHighSpan,
                                               span2 = plot1spill_LowHighSpan,
                                               slider = Pix1_LowHigh),
                                               code = """span1.location = slider.value; span2.location = slider.value""")
    Pix1_HighLow.callback = CustomJS(args=dict(span1 = plot1spect_HighLowSpan,
                                               span2 = plot1spill_HighLowSpan,
                                               slider = Pix1_HighLow),
                                               code = """span1.location = slider.value; span2.location = slider.value""")
    Pix1_HighHigh.callback = CustomJS(args=dict(span1 = plot1spect_HighHighSpan,
                                                span2 = plot1spill_HighHighSpan,
                                                slider = Pix1_HighHigh),
                                                code = """span1.location = slider.value; span2.location = slider.value""")

Here is a repeat of the plots, but now each slider manipulates the respective span in both plots...

enter image description here

Upvotes: 0

Related Questions