Twin axis synchronization

Hi! I am trying to solve a problem with axis synchronization in Bokeh.

The following code snippet produces an interactive chart with twin axes, bar chart and line chart on the same figure. Bar chart is on the left axes and line chart on the right axes.

The first slider called “Bar” multiplies the values for the bar chart by slider’s value. The other slider called ‘Line’ does the same for the line chart.

I explicitly specified how ranges of both axis should behave in callback function. When I use the ‘Line’ slider both axis range changes. IT

Could you please help?

from bokeh.models import LinearAxis, Range1d

from bokeh.io import curdoc

from bokeh.models import Slider, ColumnDataSource, WidgetBox

from bokeh.plotting import figure, output_file, show

from os.path import dirname, join

import numpy as np

import sqlite3 as sql

from bokeh.plotting import figure

from bokeh.layouts import layout, widgetbox

from bokeh.models import ColumnDataSource, HoverTool, Div

from bokeh.models.widgets import Slider, Select, TextInput

from bokeh.io import curdoc

import numpy as np

from bokeh.layouts import row

from bokeh.layouts import widgetbox

from bokeh.models.widgets import Slider

sources

source_bar = ColumnDataSource({‘x’:[1,2,3], ‘y’:[1,3,1]})

source_line = ColumnDataSource({‘x’:[1,2,3], ‘y’:[1,2,3]})

figure

p1 = figure(plot_height=600, plot_width=700, title="", toolbar_location=None)

bar

p1.vbar(source = source_bar, x = ‘x’, top = ‘y’, width = 0.5)

line

p1.extra_y_ranges = {“line”: Range1d(0, 10)}

p1.add_layout(LinearAxis(y_range_name=“line”), ‘right’)

p1.line(x=‘x’, y=‘y’, color=“blue”, line_width = 5, source = source_line, y_range_name=“line”)

slider = Slider(start=0, end=10, value=1, step=.1, title=“Bar”)

slider2 = Slider(start=0, end=10, value=1, step=.1, title=“Line”)

Add callback to widgets

def callback(attr, old, new):

source_bar.data = {‘x’:[1,2,3], ‘y’:[x * slider.value for x in [1,3,1]]}

source_line.data = {‘x’:[1,2,3], ‘y’:[x * slider2.value for x in [1,2,3]]}

p1.y_range.start = 0

p1.y_range.end = np.max(source_bar.data[‘y’])

print(p1.y_range.start, p1.y_range.end)

p1.extra_y_ranges[‘line’].start = np.min(source_line.data[‘y’])

p1.extra_y_ranges[‘line’].end = np.max(source_line.data[‘y’])

slider.on_change(‘value’, callback)

slider2.on_change(‘value’, callback)

layout = row(p1, widgetbox(slider, slider2))

curdoc().add_root(layout)

``

The default range for figures is an auto-ranging DataRange1d. I would expect that setting start/end on it explicitly, would override the auto-ranging behavior, but there are *lots* of potential interactions between ranges, auto-ranges, bounds, data following, interactive tools, and update events. I can easily believe there are bugs with less common scenarios like this one. Overriding the default DataRange1d with a plain Range1d seems to yield better behavior. This is one way to do that:

  p1 = figure(plot_height=600, plot_width=700, title="", toolbar_location=None, y_range=(0,3))

Thanks,

Bryan

···

On Feb 16, 2018, at 07:33, dark980 <[email protected]> wrote:

Hi! I am trying to solve a problem with axis synchronization in Bokeh.

The following code snippet produces an interactive chart with twin axes, bar chart and line chart on the same figure. Bar chart is on the left axes and line chart on the right axes.

The first slider called "Bar" multiplies the values for the bar chart by slider's value. The other slider called 'Line' does the same for the line chart.

I explicitly specified how ranges of both axis should behave in callback function. When I use the 'Line' slider both axis range changes. IT

Could you please help?

from bokeh.models import LinearAxis, Range1d
from bokeh.io import curdoc
from bokeh.models import Slider, ColumnDataSource, WidgetBox
from bokeh.plotting import figure, output_file, show
from os.path import dirname, join
import numpy as np
import sqlite3 as sql
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox
from bokeh.models import ColumnDataSource, HoverTool, Div
from bokeh.models.widgets import Slider, Select, TextInput
from bokeh.io import curdoc
import numpy as np
from bokeh.layouts import row
from bokeh.layouts import widgetbox
from bokeh.models.widgets import Slider

# sources
source_bar = ColumnDataSource({'x':[1,2,3], 'y':[1,3,1]})
source_line = ColumnDataSource({'x':[1,2,3], 'y':[1,2,3]})

# figure
p1 = figure(plot_height=600, plot_width=700, title="", toolbar_location=None)

# bar
p1.vbar(source = source_bar, x = 'x', top = 'y', width = 0.5)

# line
p1.extra_y_ranges = {"line": Range1d(0, 10)}
p1.add_layout(LinearAxis(y_range_name="line"), 'right')
p1.line(x='x', y='y', color="blue", line_width = 5, source = source_line, y_range_name="line")

slider = Slider(start=0, end=10, value=1, step=.1, title="Bar")
slider2 = Slider(start=0, end=10, value=1, step=.1, title="Line")

# Add callback to widgets
def callback(attr, old, new):
    source_bar.data = {'x':[1,2,3], 'y':[x * slider.value for x in [1,3,1]]}
    source_line.data = {'x':[1,2,3], 'y':[x * slider2.value for x in [1,2,3]]}
    p1.y_range.start = 0
    p1.y_range.end = np.max(source_bar.data['y'])
    print(p1.y_range.start, p1.y_range.end)
    p1.extra_y_ranges['line'].start = np.min(source_line.data['y'])
    p1.extra_y_ranges['line'].end = np.max(source_line.data['y'])
    
slider.on_change('value', callback)
slider2.on_change('value', callback)

layout = row(p1, widgetbox(slider, slider2))
curdoc().add_root(layout)

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/58edf498-cb81-48f1-8389-df5d3de1746f%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.

Thanks a lot! It seems to me that this change has solved the problem.

···

суббота, 17 февраля 2018 г., 1:53:52 UTC+3 пользователь Bryan Van de ven написал:

The default range for figures is an auto-ranging DataRange1d. I would expect that setting start/end on it explicitly, would override the auto-ranging behavior, but there are lots of potential interactions between ranges, auto-ranges, bounds, data following, interactive tools, and update events. I can easily believe there are bugs with less common scenarios like this one. Overriding the default DataRange1d with a plain Range1d seems to yield better behavior. This is one way to do that:

    p1 = figure(plot_height=600, plot_width=700, title="", toolbar_location=None, y_range=(0,3))

Thanks,

Bryan

On Feb 16, 2018, at 07:33, dark980 [email protected] wrote:

Hi! I am trying to solve a problem with axis synchronization in Bokeh.

The following code snippet produces an interactive chart with twin axes, bar chart and line chart on the same figure. Bar chart is on the left axes and line chart on the right axes.

The first slider called “Bar” multiplies the values for the bar chart by slider’s value. The other slider called ‘Line’ does the same for the line chart.

I explicitly specified how ranges of both axis should behave in callback function. When I use the ‘Line’ slider both axis range changes. IT

Could you please help?

from bokeh.models import LinearAxis, Range1d

from bokeh.io import curdoc

from bokeh.models import Slider, ColumnDataSource, WidgetBox

from bokeh.plotting import figure, output_file, show

from os.path import dirname, join

import numpy as np

import sqlite3 as sql

from bokeh.plotting import figure

from bokeh.layouts import layout, widgetbox

from bokeh.models import ColumnDataSource, HoverTool, Div

from bokeh.models.widgets import Slider, Select, TextInput

from bokeh.io import curdoc

import numpy as np

from bokeh.layouts import row

from bokeh.layouts import widgetbox

from bokeh.models.widgets import Slider

sources

source_bar = ColumnDataSource({‘x’:[1,2,3], ‘y’:[1,3,1]})

source_line = ColumnDataSource({‘x’:[1,2,3], ‘y’:[1,2,3]})

figure

p1 = figure(plot_height=600, plot_width=700, title=“”, toolbar_location=None)

bar

p1.vbar(source = source_bar, x = ‘x’, top = ‘y’, width = 0.5)

line

p1.extra_y_ranges = {“line”: Range1d(0, 10)}

p1.add_layout(LinearAxis(y_range_name=“line”), ‘right’)

p1.line(x=‘x’, y=‘y’, color=“blue”, line_width = 5, source = source_line, y_range_name=“line”)

slider = Slider(start=0, end=10, value=1, step=.1, title=“Bar”)

slider2 = Slider(start=0, end=10, value=1, step=.1, title=“Line”)

Add callback to widgets

def callback(attr, old, new):

source_bar.data = {'x':[1,2,3], 'y':[x * slider.value for x in [1,3,1]]}
source_line.data = {'x':[1,2,3], 'y':[x * slider2.value for x in [1,2,3]]}
p1.y_range.start = 0
p1.y_range.end = np.max(source_bar.data['y'])
print(p1.y_range.start, p1.y_range.end)
p1.extra_y_ranges['line'].start = np.min(source_line.data['y'])
p1.extra_y_ranges['line'].end = np.max(source_line.data['y'])

slider.on_change(‘value’, callback)

slider2.on_change(‘value’, callback)

layout = row(p1, widgetbox(slider, slider2))

curdoc().add_root(layout)


You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/58edf498-cb81-48f1-8389-df5d3de1746f%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.