I have a complicated layout that I’m having a hard time figuring out the correct sizing modes to use. The layout I want is:
- Larger plot on the left, as big as possible
- Tabs layout on the right, takes up about 1/4 the horizontal space
- There is one panel with a few plots, and another with some widgets
Here is the code:
# filename: main.py
import numpy as np
from bokeh.layouts import column, layout
from bokeh.models import Slider
from bokeh.plotting import figure
from bokeh.models.widgets import Panel, Tabs
from bokeh.io import curdoc
tools = 'pan'
def make_main_plot(sizing_mode, width, height):
# Define Bollinger Bands.
upperband = np.random.randint(100, 150 + 1, size=100)
lowerband = upperband - 100
x_data = np.arange(1, 101)
# Bollinger shading glyph:
band_x = np.append(x_data, x_data[::-1])
band_y = np.append(lowerband, upperband[::-1])
p = figure(x_axis_type='datetime', tools=tools)
p.patch(band_x, band_y, color='#7570B3', fill_alpha=0.2)
p.title.text = 'Bollinger Bands'
p.title_location = 'left'
p.title.align = 'left'
p.grid.grid_line_alpha = 0.4
p.sizing_mode = sizing_mode
p.plot_width = width
p.plot_height = height
return p
def make_sliders(sizing_mode, width, height):
kwargs = dict(
start=0,
end=10,
value=3,
step=1,
sizing_mode=sizing_mode,
width=width,
height=height,
)
amp_slider = Slider(title="Amplitude", **kwargs)
freq_slider = Slider(title="Frequency", **kwargs)
phase_slider = Slider(title="Phase", **kwargs)
offset_slider = Slider(title="Offset", **kwargs)
widgets = column(
amp_slider,
freq_slider,
phase_slider,
offset_slider,
sizing_mode=sizing_mode,
width=width,
height=height,
)
return widgets
def make_scatters(sizing_mode, width, height):
N = 100
x = np.linspace(0, 4 * np.pi, N)
y1 = np.sin(x)
y2 = np.cos(x)
s1 = figure(tools=tools)
s1.circle(x, y1, color="navy", size=8, alpha=0.5)
s2 = figure(tools=tools, x_range=s1.x_range, y_range=s1.y_range)
s2.circle(x, y2, color="firebrick", size=8, alpha=0.5)
s1.plot_height = height // 2
s2.plot_height = height // 2
s1.plot_width = width
s2.plot_width = width
s = column(s1, s2, sizing_mode=sizing_mode, width=width, height=height)
return s
# sizing values
overall_mode = 'stretch_both'
tabs_w = 400
tabs_h = 700
tabs_mode = 'fixed'
main_w = 700
main_h = 700
main_mode = 'stretch_both'
sliders_w = tabs_w - 10
sliders_h = tabs_h // 10
sliders_mode = 'scale_width'
scatters_w = tabs_w
scatters_h = tabs_h - 10
scatters_mode = 'scale_height'
# make plots
main_plot = make_main_plot(main_mode, main_w, main_h)
sliders = make_sliders(sliders_mode, sliders_w, sliders_h)
scatters = make_scatters(scatters_mode, scatters_w, scatters_h)
# create layout
scatter_tab = Panel(child=scatters, title='Scatter')
inputs_tab = Panel(child=sliders, title='Inputs')
tabs = Tabs(
tabs=[scatter_tab, inputs_tab],
sizing_mode=tabs_mode,
width=tabs_w,
height=tabs_h,
)
page_layout = layout(
[[main_plot, tabs]],
sizing_mode=overall_mode
)
curdoc().add_root(page_layout)
curdoc().title = "Layout Testing"
This is run using bokeh serve.
With the width/height/mode settings in the example I get adaptive resizing for the width, but not the height. Is this possible or do I need to turn to custom CSS to get the layout I want?