Hi,
I created a bokeh dashboard and face issues in setting the sizing_mode in the layout.
When I select sizing_mode=‘fixed’, the tabs alignment is stacked when I use more than 3 tabs.
Actually I want the widgetbox sizing_mode=‘fixed’ and the figure width=‘scale_width’, so that the tabs are all aligned in a row.
How do I do that?
Currently the relevant part of the code looks like this:
tabs = Tabs(tabs=[tab1, tab2, tab3, tab4, tab5])
layout = layout([[desc],
[inputs, tabs ],],sizing_mode=‘scale_width’)
For a full reproducible example, see below.
Thank you!
from os.path import dirname, join
from bokeh.models.widgets import Slider,CheckboxGroup,DataTable,MultiSelect,TableColumn
import numpy as np
import pandas.io.sql as psql
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,DataTable
from bokeh.io import curdoc
from bokeh.sampledata.movies_data import movie_path
from bokeh.models.widgets import Panel, Tabs
from bokeh.layouts import row
conn = sql.connect(movie_path)
query = open(join(dirname(__file__), 'query.sql')).read()
movies = psql.read_sql(query, conn)
movies["color"] = np.where(movies["Oscars"] > 0, "orange", "grey")
movies["alpha"] = np.where(movies["Oscars"] > 0, 0.9, 0.25)
movies.fillna(0, inplace=True) # just replace missing values with zero
movies["revenue"] = movies.BoxOffice.apply(lambda x: '{:,d}'.format(int(x)))
with open(join(dirname(__file__), "razzies-clean.csv")) as f:
razzies = f.read().splitlines()
movies.loc[movies.imdbID.isin(razzies), "color"] = "purple"
movies.loc[movies.imdbID.isin(razzies), "alpha"] = 0.9
axis_map = {
"Tomato Meter": "Meter",
"Numeric Rating": "numericRating",
"Number of Reviews": "Reviews",
"Box Office (dollars)": "BoxOffice",
"Length (minutes)": "Runtime",
"Year": "Year",
}
desc = Div(text=open(join(dirname(__file__), "description.html")).read(), width=800)
# Create Input controls
reviews = Slider(title="Minimum number of reviews", value=80, start=10, end=300, step=10)
min_year = Slider(title="Year released", start=1940, end=2014, value=1970, step=1)
max_year = Slider(title="End Year released", start=1940, end=2014, value=2014, step=1)
oscars = Slider(title="Minimum number of Oscar wins", start=0, end=4, value=0, step=1)
boxoffice = Slider(title="Dollars at Box Office (millions)", start=0, end=800, value=0, step=1)
genre = Select(title="Genre", value="All",
options=open(join(dirname(__file__), 'genres.txt')).read().split())
director = TextInput(title="Director name contains")
cast = TextInput(title="Cast names contains")
x_axis = Select(title="X Axis", options=sorted(axis_map.keys()), value="Tomato Meter")
y_axis = Select(title="Y Axis", options=sorted(axis_map.keys()), value="Number of Reviews")
# Create Column Data Source that will be used by the plot
source = ColumnDataSource(data=dict(x=[], y=[], color=[], title=[], year=[], revenue=[], alpha=[]))
columns = [
TableColumn(field="name", title="Name"),
TableColumn(field="x", title="X"),
TableColumn(field="y", title="Y"),
]
hover = HoverTool(tooltips=[
("Title", "@title"),
("Year", "@year"),
("$", "@revenue")
])
# Create Figures and tables
p = figure(plot_height=600, plot_width=700, title="", toolbar_location=None, tools=[hover])
p.circle(x="x", y="y", source=source, size=7, color="color", line_color=None, fill_alpha="alpha")
# p2 = figure(plot_height=600, plot_width=700, title="", toolbar_location=None, tools=[hover])
# p2.line(x="x", y="y", source=source, legend="lineplot",line_color="tomato", line_dash="dotdash")
# p2.circle(x="x", y="y", source=source, size=7, color="color", line_color=None, fill_alpha="alpha")
w4 = DataTable(source=source, columns=columns, height=280)
w5 = DataTable(source=source, columns=columns, height=280)
w6 = DataTable(source=source, columns=columns, height=280)
w7 = DataTable(source=source, columns=columns, height=280)
w8 = DataTable(source=source, columns=columns, height=280)
# initiate reactive functions
def select_movies():
genre_val = genre.value
director_val = director.value.strip()
cast_val = cast.value.strip()
selected = movies[
(movies.Reviews >= reviews.value) &
(movies.BoxOffice >= (boxoffice.value * 1e6)) &
(movies.Year >= min_year.value) &
(movies.Year <= max_year.value) &
(movies.Oscars >= oscars.value)
]
if (genre_val != "All"):
selected = selected[selected.Genre.str.contains(genre_val)==True]
if (director_val != ""):
selected = selected[selected.Director.str.contains(director_val)==True]
if (cast_val != ""):
selected = selected[selected.Cast.str.contains(cast_val)==True]
return selected
def update():
df = select_movies()
x_name = axis_map[x_axis.value]
y_name = axis_map[y_axis.value]
p.xaxis.axis_label = x_axis.value
p.yaxis.axis_label = y_axis.value
p.title.text = "%d movies selected" % len(df)
source.data = dict(
x=df[x_name],
y=df[y_name],
color=df["color"],
title=df["Title"],
year=df["Year"],
revenue=df["revenue"],
alpha=df["alpha"],
)
controls = [reviews, boxoffice, genre, min_year, max_year, oscars, director, cast, x_axis, y_axis]
for control in controls:
control.on_change('value', lambda attr, old, new: update())
sizing_mode = 'fixed' # 'scale_width' also looks nice with this example
inputs = widgetbox(*controls, sizing_mode=sizing_mode)
# layout for tabs
l1 = layout([[p],
[w4], ], sizing_mode=sizing_mode)
# l2 = layout([[inputs2,w5], ], sizing_mode=sizing_mode)
tab1 = Panel(child=l1, title="summary tab")
tab2 = Panel(child=w5, title="Goal 1")
tab3 = Panel(child=w6, title="Goal 2")
tab4 = Panel(child=w7, title="Goal 3")
tab5 = Panel(child=w8, title="Goal 4")
tabs = Tabs(tabs=[tab1, tab2, tab3, tab4, tab5])
layout = layout([[desc],
[inputs, tabs ],],sizing_mode=sizing_mode)
# 'scale_width'
update() # initial load of the data
curdoc().add_root(layout)
curdoc().title = "Movies"