[bokeh] How to add layout to tabs

Hi,

Below is my modified code of the movies example app in the bokeh library.

I tried to add several tabs to it, but could not figure out how. The tabs that I added are highlighted in blue.

I want all tabs to look like the main page: widgets on the left, graph and table vertically aligned on the right.

How could I add a few tabs within this template?

Many Thanks & Regards,

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](http://bokeh.io) import curdoc
from bokeh.sampledata.movies_data import movie_path

from bokeh.embed import components
from bokeh.models.widgets import Panel, Tabs

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")
])

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")

w4 = DataTable(source=source, columns=columns, height=280)

tab1 = Panel(child=p, title="plot")
tab2 = Panel(child=w4, title="datatable")

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)

tabs = Tabs(tabs=[ tab1, tab2 ])

l = layout([
    [desc],
    [inputs, p],
    [w4],
], sizing_mode=sizing_mode)

update() # initial load of the data

curdoc().add_root(l)
curdoc().title = "Movies"

Hi, a couple of notes:

In the code below, you create a Tabs object, but then it never gets added to the document. It's also worth mentioning that the same plot cannot currently be added twice (e.g. the exact same plot object in two tabs or columns, etc.) I am not entirely sure about your goals but I did make this small re-arrangement to get a working Tabs:

  inputs = widgetbox(*controls, sizing_mode=sizing_mode)
        l = layout([ [desc], [inputs, p], ], sizing_mode=sizing_mode)

        # moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other
        tab1 = Panel(child=l, title="plot")
        tab2 = Panel(child=w4, title="datatable")
        tabs = Tabs(tabs=[ tab1, tab2 ])

        update() # initial load of the data

        # add tabs as a root
        curdoc().add_root(tabs)
        curdoc().title = "Movies"

Hopefully this helps some,

Thanks,

Bryan

···

On Jul 5, 2016, at 12:55 AM, 'Tina Wenzel' via Bokeh Discussion - Public <[email protected]> wrote:

Hi,

Below is my modified code of the movies example app in the bokeh library.

I tried to add several tabs to it, but could not figure out how. The tabs that I added are highlighted in blue.

I want all tabs to look like the main page: widgets on the left, graph and table vertically aligned on the right.

How could I add a few tabs within this template?

Many Thanks & Regards,

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.embed import components
from bokeh.models.widgets import Panel, Tabs

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")
])

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")

w4 = DataTable(source=source, columns=columns, height=280)

tab1 = Panel(child=p, title="plot")
tab2 = Panel(child=w4, title="datatable")

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)

tabs = Tabs(tabs=[ tab1, tab2 ])

l = layout([
    [desc],
    [inputs, p],
    [w4],
], sizing_mode=sizing_mode)

update() # initial load of the data

curdoc().add_root(l)
curdoc().title = "Movies"

--
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/CAFgg%2BiePfBEOZ9LND_Ry_4%2Ba_yvDwU4uumVfeL2yvOAm_F%3Dk2A%40mail.gmail.com.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Hi Bryan,

Yes, that helped. The tabs show up now, Thank you.

I still have a problem with the widgets. I still want widgets to display on all tabs and hence tried to add the same widgets as on tab1 (called inputs) to the tab2. If I try that it does not display anymore.

I tried to change the name to inputs2 instead:


inputs = widgetbox(*controls, sizing_mode=sizing_mode)
# inputs2 = widgetbox(*controls, sizing_mode=sizing_mode)

l1 = layout([[desc],
            [inputs, p],
             [w4], ], sizing_mode=sizing_mode)

# l2 = layout([[inputs2,w5], ], sizing_mode=sizing_mode)

# moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other
tab1 = Panel(child=l1, title="plot")
tab2 = Panel(child=w5, title="datatable")
# tab2 = Panel(child=l2, title="datatable")

tabs = Tabs(tabs=[tab1, tab2])

This did not work however.

Any idea how to do that? I have pasted the updated app below.

Many Thanks & Regards,

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.embed import components
from bokeh.models.widgets import Panel, Tabs

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")
])

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")

w4 = DataTable(source=source, columns=columns, height=280)
w5 = DataTable(source=source, columns=columns, height=280)

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)
# inputs2 = widgetbox(*controls, sizing_mode=sizing_mode)

l1 = layout([[desc],
            [inputs, p],
             [w4], ], sizing_mode=sizing_mode)

# l2 = layout([[inputs2,w5], ], sizing_mode=sizing_mode)

# moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other
tab1 = Panel(child=l1, title="plot")
tab2 = Panel(child=w5, title="datatable")
# tab2 = Panel(child=l2, title="datatable")

tabs = Tabs(tabs=[tab1, tab2])

update() # initial load of the data

# add tabs as a root
curdoc().add_root(tabs)
curdoc().title = "Movies"

···

Am Dienstag, 5. Juli 2016 15:00:04 UTC+1 schrieb Bryan Van de ven:

Hi, a couple of notes:

In the code below, you create a Tabs object, but then it never gets added to the document. It’s also worth mentioning that the same plot cannot currently be added twice (e.g. the exact same plot object in two tabs or columns, etc.) I am not entirely sure about your goals but I did make this small re-arrangement to get a working Tabs:

    inputs = widgetbox(*controls, sizing_mode=sizing_mode)
    l = layout([ [desc], [inputs, p], ], sizing_mode=sizing_mode)


    # moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other

    tab1 = Panel(child=l, title="plot")
    tab2 = Panel(child=w4, title="datatable")
    tabs = Tabs(tabs=[ tab1, tab2 ])


    update() # initial load of the data


    # add tabs as a root

    curdoc().add_root(tabs)
    curdoc().title = "Movies"

Hopefully this helps some,

Thanks,

Bryan

On Jul 5, 2016, at 12:55 AM, ‘Tina Wenzel’ via Bokeh Discussion - Public [email protected] wrote:

Hi,

Below is my modified code of the movies example app in the bokeh library.

I tried to add several tabs to it, but could not figure out how. The tabs that I added are highlighted in blue.

I want all tabs to look like the main page: widgets on the left, graph and table vertically aligned on the right.

How could I add a few tabs within this template?

Many Thanks & Regards,

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.embed import components

from bokeh.models.widgets import Panel, Tabs

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")

])

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”)

w4 = DataTable(source=source, columns=columns, height=280)

tab1 = Panel(child=p, title=“plot”)

tab2 = Panel(child=w4, title=“datatable”)

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)

tabs = Tabs(tabs=[ tab1, tab2 ])

l = layout([

[desc],
[inputs, p],
[w4],

], sizing_mode=sizing_mode)

update() # initial load of the data

curdoc().add_root(l)

curdoc().title = “Movies”


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/CAFgg%2BiePfBEOZ9LND_Ry_4%2Ba_yvDwU4uumVfeL2yvOAm_F%3Dk2A%40mail.gmail.com.

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

Tina,

Yes this is current limitation I mentioned in passing but that bears repeating, which is that each Bokeh model object can only appear once in a given document. So given that, I think in your case a better solution would be something that does not have the widgets in the tabs. For instance:

  inputs = wigetbox(...)

  tabs = Tabs(...) # panels with plots or tables, etc. but not the controls

        layout = row(inputs, tabs)

Should have the widgets always visible, but outside the tab box, which is only used to switch between actually different things.

Thanks,

Bryan

···

On Jul 5, 2016, at 12:05 PM, 'Tina Wenzel' via Bokeh Discussion - Public <[email protected]> wrote:

Hi Bryan,

Yes, that helped. The tabs show up now, Thank you.

I still have a problem with the widgets. I still want widgets to display on all tabs and hence tried to add the same widgets as on tab1 (called inputs) to the tab2. If I try that it does not display anymore.

I tried to change the name to inputs2 instead:

inputs = widgetbox(*controls, sizing_mode=sizing_mode)
# inputs2 = widgetbox(*controls, sizing_mode=sizing_mode)

l1 = layout([[desc],
            [inputs, p],
             [w4], ], sizing_mode=sizing_mode)

# l2 = layout([[inputs2,w5], ], sizing_mode=sizing_mode)

# moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other
tab1 = Panel(child=l1, title="plot")
tab2 = Panel(child=w5, title="datatable")
# tab2 = Panel(child=l2, title="datatable")

tabs = Tabs(tabs=[tab1, tab2])

This did not work however.

Any idea how to do that? I have pasted the updated app below.

Many Thanks & Regards,

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.embed import components
from bokeh.models.widgets import Panel, Tabs

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")
])

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")

w4 = DataTable(source=source, columns=columns, height=280)
w5 = DataTable(source=source, columns=columns, height=280)

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)
# inputs2 = widgetbox(*controls, sizing_mode=sizing_mode)

l1 = layout([[desc],
            [inputs, p],
             [w4], ], sizing_mode=sizing_mode)

# l2 = layout([[inputs2,w5], ], sizing_mode=sizing_mode)

# moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other
tab1 = Panel(child=l1, title="plot")
tab2 = Panel(child=w5, title="datatable")
# tab2 = Panel(child=l2, title="datatable")

tabs = Tabs(tabs=[tab1, tab2])

update() # initial load of the data

# add tabs as a root
curdoc().add_root(tabs)
curdoc().title = "Movies"

Am Dienstag, 5. Juli 2016 15:00:04 UTC+1 schrieb Bryan Van de ven:
Hi, a couple of notes:

In the code below, you create a Tabs object, but then it never gets added to the document. It's also worth mentioning that the same plot cannot currently be added twice (e.g. the exact same plot object in two tabs or columns, etc.) I am not entirely sure about your goals but I did make this small re-arrangement to get a working Tabs:

        inputs = widgetbox(*controls, sizing_mode=sizing_mode)
        l = layout([ [desc], [inputs, p], ], sizing_mode=sizing_mode)

        # moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other
        tab1 = Panel(child=l, title="plot")
        tab2 = Panel(child=w4, title="datatable")
        tabs = Tabs(tabs=[ tab1, tab2 ])

        update() # initial load of the data

        # add tabs as a root
        curdoc().add_root(tabs)
        curdoc().title = "Movies"

Hopefully this helps some,

Thanks,

Bryan

> On Jul 5, 2016, at 12:55 AM, 'Tina Wenzel' via Bokeh Discussion - Public <[email protected]> wrote:
>
> Hi,
>
> Below is my modified code of the movies example app in the bokeh library.
>
> I tried to add several tabs to it, but could not figure out how. The tabs that I added are highlighted in blue.
>
> I want all tabs to look like the main page: widgets on the left, graph and table vertically aligned on the right.
>
> How could I add a few tabs within this template?
>
> Many Thanks & Regards,
>
>
> 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.embed import components
> from bokeh.models.widgets import Panel, Tabs
>
>
> 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")
> ])
>
> 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")
>
> w4 = DataTable(source=source, columns=columns, height=280)
>
> tab1 = Panel(child=p, title="plot")
> tab2 = Panel(child=w4, title="datatable")
>
> 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)
>
> tabs = Tabs(tabs=[ tab1, tab2 ])
>
> l = layout([
> [desc],
> [inputs, p],
> [w4],
> ], sizing_mode=sizing_mode)
>
> update() # initial load of the data
>
> curdoc().add_root(l)
> curdoc().title = "Movies"
>
>
> --
> 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/CAFgg%2BiePfBEOZ9LND_Ry_4%2Ba_yvDwU4uumVfeL2yvOAm_F%3Dk2A%40mail.gmail.com.
> For more options, visit https://groups.google.com/a/continuum.io/d/optout.

--
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/a2a9cf40-9229-4c9f-adc5-016deda03cfe%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Hi Bryan,

That’s exactly what I wanted. Works like a charm!

Many Thanks!

Tina

···

2016-07-05 18:18 GMT+01:00 Bryan Van de Ven [email protected]:

Tina,

Yes this is current limitation I mentioned in passing but that bears repeating, which is that each Bokeh model object can only appear once in a given document. So given that, I think in your case a better solution would be something that does not have the widgets in the tabs. For instance:

    inputs = wigetbox(...)



    tabs = Tabs(...) # panels with plots or tables, etc. but not the controls



    layout = row(inputs, tabs)

Should have the widgets always visible, but outside the tab box, which is only used to switch between actually different things.

Thanks,

Bryan

On Jul 5, 2016, at 12:05 PM, ‘Tina Wenzel’ via Bokeh Discussion - Public [email protected] wrote:

Hi Bryan,

Yes, that helped. The tabs show up now, Thank you.

I still have a problem with the widgets. I still want widgets to display on all tabs and hence tried to add the same widgets as on tab1 (called inputs) to the tab2. If I try that it does not display anymore.

I tried to change the name to inputs2 instead:

inputs = widgetbox(*controls, sizing_mode=sizing_mode)

inputs2 = widgetbox(*controls, sizing_mode=sizing_mode)

l1 = layout([[desc],

        [inputs, p],
         [w4], ], sizing_mode=sizing_mode)

l2 = layout([[inputs2,w5], ], sizing_mode=sizing_mode)

moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other

tab1 = Panel(child=l1, title=“plot”)

tab2 = Panel(child=w5, title=“datatable”)

tab2 = Panel(child=l2, title=“datatable”)

tabs = Tabs(tabs=[tab1, tab2])

This did not work however.

Any idea how to do that? I have pasted the updated app below.

Many Thanks & Regards,

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.embed import components

from bokeh.models.widgets import Panel, Tabs

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")

])

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”)

w4 = DataTable(source=source, columns=columns, height=280)

w5 = DataTable(source=source, columns=columns, height=280)

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)

inputs2 = widgetbox(*controls, sizing_mode=sizing_mode)

l1 = layout([[desc],

        [inputs, p],
         [w4], ], sizing_mode=sizing_mode)

l2 = layout([[inputs2,w5], ], sizing_mode=sizing_mode)

moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other

tab1 = Panel(child=l1, title=“plot”)

tab2 = Panel(child=w5, title=“datatable”)

tab2 = Panel(child=l2, title=“datatable”)

tabs = Tabs(tabs=[tab1, tab2])

update() # initial load of the data

add tabs as a root

curdoc().add_root(tabs)

curdoc().title = “Movies”

Am Dienstag, 5. Juli 2016 15:00:04 UTC+1 schrieb Bryan Van de ven:

Hi, a couple of notes:

In the code below, you create a Tabs object, but then it never gets added to the document. It’s also worth mentioning that the same plot cannot currently be added twice (e.g. the exact same plot object in two tabs or columns, etc.) I am not entirely sure about your goals but I did make this small re-arrangement to get a working Tabs:

    inputs = widgetbox(*controls, sizing_mode=sizing_mode)
    l = layout([ [desc], [inputs, p], ], sizing_mode=sizing_mode)
    # moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other
    tab1 = Panel(child=l, title="plot")
    tab2 = Panel(child=w4, title="datatable")
    tabs = Tabs(tabs=[ tab1, tab2 ])
    update() # initial load of the data
    # add tabs as a root
    curdoc().add_root(tabs)
    curdoc().title = "Movies"

Hopefully this helps some,

Thanks,

Bryan

On Jul 5, 2016, at 12:55 AM, ‘Tina Wenzel’ via Bokeh Discussion - Public [email protected] wrote:

Hi,

Below is my modified code of the movies example app in the bokeh library.

I tried to add several tabs to it, but could not figure out how. The tabs that I added are highlighted in blue.

I want all tabs to look like the main page: widgets on the left, graph and table vertically aligned on the right.

How could I add a few tabs within this template?

Many Thanks & Regards,

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.embed import components

from bokeh.models.widgets import Panel, Tabs

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")

])

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”)

w4 = DataTable(source=source, columns=columns, height=280)

tab1 = Panel(child=p, title=“plot”)

tab2 = Panel(child=w4, title=“datatable”)

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)

tabs = Tabs(tabs=[ tab1, tab2 ])

l = layout([

[desc],
[inputs, p],
[w4],

], sizing_mode=sizing_mode)

update() # initial load of the data

curdoc().add_root(l)

curdoc().title = “Movies”

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/CAFgg%2BiePfBEOZ9LND_Ry_4%2Ba_yvDwU4uumVfeL2yvOAm_F%3Dk2A%40mail.gmail.com.

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

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/a2a9cf40-9229-4c9f-adc5-016deda03cfe%40continuum.io.

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

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/19658B8E-D1AE-45E4-BA4E-E1CDA17DD43F%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Tina Wenzel
23, Shaftesbury Rd

N19 4QW
(+44) 7553775883

Hi Bryan,

I added a few tabs and now face a sizing_mode issue.

Is there a way to use a fixed sizing_model for inputs and **scale_width **for the tabs ? In my project i need about 10 tabs that I want to display next to each other.

When I used sizing_mode=‘fixed’, the tabs were displayed not all in a row, but in two rows stacked underneath each other

.

The relevant code parts look like this:

tabs = Tabs(tabs=[tab1, tab2, tab3, tab4, tab5])

layout = layout([[desc],
                 [inputs, tabs ],],sizing_mode='scale_width')
···

Further, I would wondered whether t’s possible to add pagination and search functionality to the datable in bokeh?

Thanks,

Tina

2016-07-05 20:20 GMT+01:00 Tina Wenzel [email protected]:

Hi Bryan,

That’s exactly what I wanted. Works like a charm!

Many Thanks!

Tina


Tina Wenzel
23, Shaftesbury Rd

N19 4QW
(+44) 7553775883

2016-07-05 18:18 GMT+01:00 Bryan Van de Ven [email protected]:

Tina,

Yes this is current limitation I mentioned in passing but that bears repeating, which is that each Bokeh model object can only appear once in a given document. So given that, I think in your case a better solution would be something that does not have the widgets in the tabs. For instance:

    inputs = wigetbox(...)



    tabs = Tabs(...) # panels with plots or tables, etc. but not the controls



    layout = row(inputs, tabs)

Should have the widgets always visible, but outside the tab box, which is only used to switch between actually different things.

Thanks,

Bryan

On Jul 5, 2016, at 12:05 PM, ‘Tina Wenzel’ via Bokeh Discussion - Public [email protected] wrote:

Hi Bryan,

Yes, that helped. The tabs show up now, Thank you.

I still have a problem with the widgets. I still want widgets to display on all tabs and hence tried to add the same widgets as on tab1 (called inputs) to the tab2. If I try that it does not display anymore.

I tried to change the name to inputs2 instead:

inputs = widgetbox(*controls, sizing_mode=sizing_mode)

inputs2 = widgetbox(*controls, sizing_mode=sizing_mode)

l1 = layout([[desc],

        [inputs, p],
         [w4], ], sizing_mode=sizing_mode)

l2 = layout([[inputs2,w5], ], sizing_mode=sizing_mode)

moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other

tab1 = Panel(child=l1, title=“plot”)

tab2 = Panel(child=w5, title=“datatable”)

tab2 = Panel(child=l2, title=“datatable”)

tabs = Tabs(tabs=[tab1, tab2])

This did not work however.

Any idea how to do that? I have pasted the updated app below.

Many Thanks & Regards,

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.embed import components

from bokeh.models.widgets import Panel, Tabs

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")

])

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”)

w4 = DataTable(source=source, columns=columns, height=280)

w5 = DataTable(source=source, columns=columns, height=280)

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)

inputs2 = widgetbox(*controls, sizing_mode=sizing_mode)

l1 = layout([[desc],

        [inputs, p],
         [w4], ], sizing_mode=sizing_mode)

l2 = layout([[inputs2,w5], ], sizing_mode=sizing_mode)

moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other

tab1 = Panel(child=l1, title=“plot”)

tab2 = Panel(child=w5, title=“datatable”)

tab2 = Panel(child=l2, title=“datatable”)

tabs = Tabs(tabs=[tab1, tab2])

update() # initial load of the data

add tabs as a root

curdoc().add_root(tabs)

curdoc().title = “Movies”

Am Dienstag, 5. Juli 2016 15:00:04 UTC+1 schrieb Bryan Van de ven:

Hi, a couple of notes:

In the code below, you create a Tabs object, but then it never gets added to the document. It’s also worth mentioning that the same plot cannot currently be added twice (e.g. the exact same plot object in two tabs or columns, etc.) I am not entirely sure about your goals but I did make this small re-arrangement to get a working Tabs:

    inputs = widgetbox(*controls, sizing_mode=sizing_mode)
    l = layout([ [desc], [inputs, p], ], sizing_mode=sizing_mode)
    # moved from earlier in the script. Put the layout in one of the tabs panels, and a table in the other
    tab1 = Panel(child=l, title="plot")
    tab2 = Panel(child=w4, title="datatable")
    tabs = Tabs(tabs=[ tab1, tab2 ])
    update() # initial load of the data
    # add tabs as a root
    curdoc().add_root(tabs)
    curdoc().title = "Movies"

Hopefully this helps some,

Thanks,

Bryan

On Jul 5, 2016, at 12:55 AM, ‘Tina Wenzel’ via Bokeh Discussion - Public [email protected] wrote:

Hi,

Below is my modified code of the movies example app in the bokeh library.

I tried to add several tabs to it, but could not figure out how. The tabs that I added are highlighted in blue.

I want all tabs to look like the main page: widgets on the left, graph and table vertically aligned on the right.

How could I add a few tabs within this template?

Many Thanks & Regards,

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.embed import components

from bokeh.models.widgets import Panel, Tabs

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")

])

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”)

w4 = DataTable(source=source, columns=columns, height=280)

tab1 = Panel(child=p, title=“plot”)

tab2 = Panel(child=w4, title=“datatable”)

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)

tabs = Tabs(tabs=[ tab1, tab2 ])

l = layout([

[desc],
[inputs, p],
[w4],

], sizing_mode=sizing_mode)

update() # initial load of the data

curdoc().add_root(l)

curdoc().title = “Movies”

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/CAFgg%2BiePfBEOZ9LND_Ry_4%2Ba_yvDwU4uumVfeL2yvOAm_F%3Dk2A%40mail.gmail.com.

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

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/a2a9cf40-9229-4c9f-adc5-016deda03cfe%40continuum.io.

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

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/19658B8E-D1AE-45E4-BA4E-E1CDA17DD43F%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Tina Wenzel
23, Shaftesbury Rd

N19 4QW
(+44) 7553775883