Y-axis not updating after altering children

Hi all,

I have a script that displays several plots side by side. The plots are on different scales, so I have a toggle that changes them from using the same y_range to an auto updating y_range. There are also different version of the plots, which replace the initial plots via another toggle.

All of this works initially, but the y_range stops auto updating after changing the plots >1 time.

I.e. 1) the y-axis toggle works, 2) you change plots, 3) the y-axis toggle works, 4) you change plots, 5) the y-axis toggle no longer works.

There aren’t any messages when it stops working, so I’m not sure if this is a bug or if my method is just bad. I’d really appreciate it if anyone could help me out with this.

I’ve included a minimal working script below that highlights the problem.

Thanks

Python: 3.6.4
Bokeh: 1.2.0
OS: Windows 10 / Ubuntu 16.04
Browser: Chrome 76.0.3809.132 (Official Build) (64-bit)

import numpy as np
import pandas as pd

from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.layouts import row, column
from bokeh.models.widgets import Toggle
from bokeh.models import ColumnDataSource


def initialize_data(n):

    x = np.arange(10)

    return ColumnDataSource(pd.DataFrame({
        'x': x,
        'y': x*n
    }))


def initialize_figures(d1, d2, ymax):

    p1 = figure(sizing_mode='scale_width', tools='', toolbar_location=None, plot_width=4, plot_height=3)
    p1.circle('x', 'y', source=d1, color='red', size=15)
    p1.circle('x', 'y', source=ymax, color='black', size=15)

    p2 = figure(sizing_mode='scale_width', tools='', toolbar_location=None, plot_width=4, plot_height=3)
    p2.circle('x', 'y', source=d2, color='blue', size=15)
    p2.circle('x', 'y', source=ymax, color='black', size=15)

    return row(p1, p2)


def change_plots(self):
    r1.children, r2.children = r2.children, r1.children


def change_y_axis(self):

    global N

    ymax1.patch({'y': [(0, ymax1.data['y'][0] / N)]})
    ymax2.patch({'y': [(0, ymax2.data['y'][0] / N)]})

    N = 1/N


N = 1000

d11 = initialize_data(1)
d12 = initialize_data(2)

d21 = initialize_data(1)
d22 = initialize_data(.5)

ymax1 = ColumnDataSource({'x': [0], 'y': [max(d11.data['y'].max(), d12.data['y'].max())]})
ymax2 = ColumnDataSource({'x': [0], 'y': [max(d21.data['y'].max(), d22.data['y'].max())]})

r1 = initialize_figures(d11, d12, ymax1)
r2 = initialize_figures(d21, d22, ymax2)

toggle1 = Toggle(label='change plots', height=30, width=500, sizing_mode='scale_width')
toggle1.on_click(change_plots)

toggle2 = Toggle(label='change y-axis', height=30, width=500, sizing_mode='scale_width')
toggle2.on_click(change_y_axis)

toggles = row(toggle1, toggle2, sizing_mode='scale_width')

c = column(toggles, r1, sizing_mode='scale_width')

curdoc().add_root(c)

Hi Evan_Nowak!

I see it’s been a while since you posted-- were you able to figure this one out? I tried out your example, and I do see that the y-axis toggle doesn’t seem to do anything after the second hit on the “change plots” button.

I’m curious about your method of setting the y-axis length, using a ColumnDataSource patch rather than setting the y_range property on the figure? Can you explain a little more about your intent here?

Hi Carolyn,

Thanks for replying. I wasn’t able to figure it out, but I did work around it. I initially did it this way because it easily integrated into my app at the time, but I ended up changing it to use the y_range property as you mentioned (I actually posted a different question about that as well when I was making the switch).

1 Like