Setting the order of the tools in a grid plot

I’m creating a plot with two graphs and linked selecting. The tool list I pass in is:

‘box_select,box_zoom,wheel_zoom,pan,save,reset’,

but the tools are displayed in the order:
box select, box soom, pan, wheel zoom, save, reset

I’d rather have the two zooms next to each other. is there a way to specify the tool order?

There are two plots, each with the same set of tools in a gridplot so there is only one toolbar for both of them.

import random

from bokeh.io import output_notebook, show
from bokeh.plotting import figure
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.events import SelectionGeometry, Reset
from bokeh.layouts import column, gridplot, row
from bokeh.models.widgets import Button

from palettable.cartocolors.qualitative import Bold_8

import pandas as pd
import numpy as np

output_notebook()

# make some fake data 
# y and z are just random squiggles with some spacing between each set
# x is generated in small-to-large order to plot like a well-behaved line

y_df = pd.DataFrame(columns=[f"y{i}" for i in range(4)],
                      data = np.random.random_sample((10,4)))
for i, col in enumerate(y_df):
    y_df[col] += 2*i

z_df = pd.DataFrame(columns=[f"z{i}" for i in range(4)],
                      data = np.random.random_sample((10,4)))
for i, col in enumerate(z_df):
    z_df[col] += 2*i

starts = np.random.random_sample((4,)) * 3
steps = np.random.sample((4,)) * 1.5
x_df = pd.DataFrame(columns=[f"x{i}" for i in range(4)],
                      data = np.array([starts[i] + j * steps[i]
                                       for i in range(4)
                                       for j in range(10)]).reshape(4,10).T)

column_data = dict(
    xs=[x_df[col] for col in x_df.columns],
    ys=[y_df[col] for col in y_df.columns],
    zs=[z_df[col] for col in z_df.columns],
    colors=Bold_8.hex_colors[:4], 
)

s1 = ColumnDataSource(column_data)

common_plot_args = dict(
    plot_width=400, 
    plot_height=400, 
    tools = 'box_select,box_zoom,wheel_zoom,pan,save,reset',
)

xy_plot = figure(title="XY view", **common_plot_args)
xy_plot.xaxis.axis_label = "The mysterious X"
xy_plot.yaxis.axis_label = "The variable Y"

xz_plot = figure(title="XZ view", **common_plot_args)
xz_plot.xaxis.axis_label = "The mysterious X"
xz_plot.yaxis.axis_label = "The parameter Z"


common_multiline_args = dict(
    source=s1, 
    line_color="colors", 
    line_width=2,
    selection_color="black",
    selection_line_width=3,
    nonselection_alpha=.8,
    nonselection_line_width=1,
)

xy_plot.multi_line(xs="xs", ys="ys", **common_multiline_args)
xz_plot.multi_line(xs="xs", ys="zs", **common_multiline_args)

b = Button(label="Change the color!")
bothviews = gridplot([[xy_plot, xz_plot]], sizing_mode='stretch_both')
show(column(bothviews, b))

There’s not any simple way. Tools are grouped by gesture type (drag, tap, scroll, etc). A custom extension to toolbar could do it, but toolbar is one of the more complicated Bokeh models and extending it would not be trivial.

It just bugs me – because related functions grouping rather than related gestures seems more logical to me – but there are worse problems with my plots to fix. But I won’t spend time on this now. Thanks for the quick reply.

I don’t think this is the first time I’ve heard similarly so please feel free to open a GitHub to discuss it.