ts-python

Seminar VII: 2022-10-21 Dashboarding In Python

KRUSTY THE CLOWN: “Let’s just say it moved me… TO A BIGGER HOUSE! Oops! I said the quiet part loud and the loud part quiet.”

— “A Star is Burns” (S06E18)

Abstract

How do you create an interactive dashboard in Python? How do you deploy and share that dashboard? And, critically, can we do this without being a front-end developer?

Do you…

Then come join us for a session on dashboarding in Python!

Python is a premiere programming language for scientific computation, whether its used for data exploration, visualization, or reporting. While Python has always supported interactive visualizations via matplotlib its web-based dashboarding capabilities have been limited to rendering static plots onto the web.

In this episode, we will provide an overview of some Python based dashboarding tools like panel, bokeh, and holoviews. These tools provide a convenient mechanism to create complex dashboards enabling you to better understand your data, and even share that understanding with your colleagues. We’ll develop an understanding about the uses of a data dashboard, the core features of these Python tools, and how these frameworks are implemented to effectively work with them without needing to be a front-end developer.

Keywords:

Notes

premise

print("Let's take a look!")

What am I here to do? What is the problem at hand?

from pathlib import Path

from pandas import read_pickle

data_dir = Path('data')

prices = read_pickle(data_dir / 'prices.pkl')
trades = read_pickle(data_dir / 'trades.pkl')
industries = read_pickle(data_dir / 'industries.pkl')

print(
    prices.head(3),
    trades.head(3),
    industries.head(3),
    sep='\n{}\n'.format('\N{box drawings light horizontal}' * 40),
)
from pathlib import Path

from matplotlib.pyplot import show
from pandas import read_pickle

data_dir = Path('data')

prices = read_pickle(data_dir / 'prices.pkl')

prices.unstack('ticker').iloc[:, :4].plot()
show()

plotly dash

print("Let's take a look!")
from dash import Dash
from dash.html import Div, H1, P

app = Dash(__name__)
app.layout = Div([
    H1('Dashboard...'),
    P('some description of our problem'),
])
app.run_server(debug=True)
from dash import Dash
from dash.dcc import Input
from dash.html import Div, H1

app = Dash(__name__)
app.layout = Div([
    H1('Dashboard'),
    Input(),
])
app.run_server(debug=True)
from dash import Dash
from dash.dcc import Dropdown
from dash.html import Div, H1

app = Dash(__name__)
app.layout = Div([
    H1('Dashboard'),
    Dropdown(options=['a', 'b', 'c']),
])
app.run_server(debug=True)
from pathlib import Path
from pandas import read_pickle

from dash import Dash
from dash.dcc import Dropdown
from dash.html import Div, H1

data_dir = Path('data')
industries = read_pickle(data_dir / 'industries.pkl')

app = Dash(__name__)
app.layout = Div([
    H1('Dashboard'),
    Dropdown(sorted(industries.unique())),
])
app.run_server(debug=True)
from pathlib import Path
from pandas import read_pickle

from dash import Dash, Input, Output
from dash.dcc import Dropdown
from dash.html import Div, H1, H2

data_dir = Path('data')
industries = read_pickle(data_dir / 'industries.pkl')

app = Dash(__name__)
app.layout = Div([
    h1 := H1('Dashboard'),
    h2 := H2(),
    dd := Dropdown(sorted(industries.unique())),
])

@app.callback(
    Output(h2, 'children'),
    Input(dd, 'value')
)
def callback(value):
    return 'All Industries' if value is None else value

app.run_server(debug=True)
from pathlib import Path
from pandas import read_pickle

from dash import Dash, Input, Output
from dash.dcc import Dropdown, Graph
from dash.html import Div, H1, H2

from plotly.express import line

data_dir = Path('data')
industries = read_pickle(data_dir / 'industries.pkl')

app = Dash(__name__)
app.layout = Div([
    h1 := H1('Dashboard'),
    h2 := H2(),
    dd := Dropdown(sorted(industries.unique())),
    gr := Graph(),
])

@app.callback(
    Output(h2, 'children'),
    Input(dd, 'value')
)
def update_title(value):
    return 'All Industries' if value is None else value

@app.callback(
    Output(gr, 'figure'),
    Input(dd, 'value')
)
def update_graph(value):
    return line([1, 2, 3], [4, 5, 6])

app.run_server(debug=True)
from pathlib import Path
from pandas import read_pickle, IndexSlice

from dash import Dash, Input, Output
from dash.dcc import Dropdown, Graph
from dash.html import Div, H1, H2

# from plotly.express import line

data_dir = Path('data')
industries = read_pickle(data_dir / 'industries.pkl')
prices = read_pickle(data_dir / 'prices.pkl')

# app = Dash(__name__)
# app.layout = Div([
#     h1 := H1('Dashboard'),
#     h2 := H2(),
#     dd := Dropdown(sorted(industries.unique())),
#     gr := Graph(),
# ])

# @app.callback(
#     Output(h2, 'children'),
#     Input(dd, 'value')
# )
# def update_title(industry):
#     return 'All Industries' if industry is None else industry

# @app.callback(
#     Output(gr, 'figure'),
#     Input(dd, 'value')
# )
# def update_graph(industry):
#     if industry is not None:
#         tickers = industries.loc[lambda s: s == industry].index
#     else:
#         tickers = industries.index
#     data = prices.loc[IndexSlice[:, tickers], 'bid'].groupby('date').mean()
#     return line(
#         data,
#     )

# app.run_server(debug=True)
from pathlib import Path
from pandas import read_pickle, IndexSlice

from dash import Dash, Input, Output
from dash.dcc import Dropdown, Graph
from dash.html import Div, H1, H2

from plotly.express import line

data_dir = Path('data')
industries = read_pickle(data_dir / 'industries.pkl')
prices = read_pickle(data_dir / 'prices.pkl')

app = Dash(__name__)
app.layout = Div([
    h1 := H1('Dashboard'),
    h2 := H2(),
    dd := Dropdown(sorted(industries.unique())),
    gr := Graph(),
])

@app.callback(
    Output(h2, 'children'),
    Input(dd, 'value')
)
def update_title(industry):
    return 'All Industries' if industry is None else industry

@app.callback(
    Output(gr, 'figure'),
    Input(dd, 'value')
)
def update_graph(industry):
    if industry is not None:
        tickers = industries.loc[lambda s: s == industry].index
    else:
        tickers = industries.index
    data = prices.loc[IndexSlice[:, tickers], 'bid'].reset_index('ticker', drop=False)
    return line(
        data,
        line_group='ticker',
    )

app.run_server(debug=True)
from pathlib import Path
from pandas import read_pickle, IndexSlice

from dash import Dash, Input, Output
from dash.dcc import Dropdown, Graph
from dash.html import Div, H1, H2

from plotly.express import line

data_dir = Path('data')
industries = read_pickle(data_dir / 'industries.pkl')
prices = read_pickle(data_dir / 'prices.pkl')

app = Dash(__name__)
app.layout = Div([
    h1 := H1('Dashboard'),
    h2 := H2(),
    dd := Dropdown(sorted(industries.unique())),
    gr := Graph(),
])

@app.callback(
    Output(h2, 'children'),
    Input(dd, 'value')
)
def update_title(industry):
    return 'All Industries' if industry is None else industry

@app.callback(
    Output(gr, 'figure'),
    Input(dd, 'value')
)
def update_graph(industry):
    if industry is not None:
        tickers = industries.loc[lambda s: s == industry].index
    else:
        tickers = industries.index
    data = prices.loc[IndexSlice[:, tickers], 'bid'].reset_index('ticker', drop=False)
    return line(
        data,
        line_group='ticker',
    )

app.run_server(debug=True)
from pathlib import Path
from pandas import read_pickle, IndexSlice

from dash import Dash, Input, Output
from dash.dcc import Dropdown, Graph
from dash.html import Div, H1, H2

from plotly.express import line

data_dir = Path('data')
industries = read_pickle(data_dir / 'industries.pkl')
prices = read_pickle(data_dir / 'prices.pkl')

app = Dash(__name__)
app.layout = Div([
    h1 := H1('Dashboard'),
    h2 := H2(),
    dd := Dropdown(sorted(industries.unique())),
    gr := Graph(),
])

@app.callback(
    [Output(h2, 'children'), Output(gr, 'figure')],
    Input(dd, 'value')
)
def update(industry):
    if industry is not None:
        title = industry
        tickers = industries.loc[lambda s: s == industry].index
    else:
        title = 'All industries'
        tickers = industries.index
    data = prices.loc[IndexSlice[:, tickers], 'bid'].reset_index('ticker', drop=False)
    ln = line(
        data,
        line_group='ticker',
    )
    return title, ln

app.run_server(debug=True)
from pathlib import Path
from pandas import read_pickle, IndexSlice

from dash import Dash, Input, Output
from dash.dcc import Dropdown, Graph
from dash.html import Div, H1, H2

from plotly.express import line

data_dir = Path('data')
industries = read_pickle(data_dir / 'industries.pkl')
prices = read_pickle(data_dir / 'prices.pkl')
trades = read_pickle(data_dir / 'trades.pkl')

app = Dash(__name__)
app.layout = Div([
    h1 := H1('Dashboard'),
    prx_h2 := H2(),
    prx_dd := Dropdown(sorted(industries.unique())),
    prx_gr := Graph(),
    trd_h2 := H2(),
    trd_dd := Dropdown(),
    pf_dd  := Dropdown(sorted(trades.index.get_level_values('portfolio').unique())),
    trd_gr := Graph(),
])

@app.callback(
    [Output(prx_h2, 'children'), Output(prx_gr, 'figure'), Output(trd_dd, 'options')],
    Input(prx_dd, 'value')
)
def update_prices(industry):
    if industry is not None:
        title = industry
        tickers = industries.loc[lambda s: s == industry].index
    else:
        title = 'All industries'
        tickers = industries.index
    data = prices.loc[IndexSlice[:, tickers], 'bid'].reset_index('ticker', drop=False)
    ln = line(
        data,
        line_group='ticker',
    )
    return title, ln, sorted(tickers)

@app.callback(
    Output(trd_gr, 'figure'),
    [Input(trd_dd, 'value'), Input(pf_dd, 'value')]
)
def update_trades(ticker, portfolio):
    if ticker is not None and portfolio is not None:
        data = trades.loc[IndexSlice[:, portfolio, ticker, :], 'price']
    elif ticker is not None:
        data = trades.loc[IndexSlice[:, :, ticker, :], 'price']
    elif portfolio is not None:
        data = trades.loc[IndexSlice[:, portfolio, :, :], 'price']
    else:
        data = trades.loc[:, 'price']
    data = data.groupby(['date']).mean()
    return line(data)

app.run_server(debug=True)
from io import BytesIO
from base64 import b64encode

from numpy import linspace
from matplotlib.pyplot import subplots

from dash import Dash, Input, Output
from dash.dcc import Input as dccInput
from dash.html import Div, H1, Img

app = Dash(__name__)
app.layout = Div([
    H1('Dashboard'),
    inp := dccInput(value=2),
    img := Img(),
])

xs = linspace(-100, 100, 1_000)

@app.callback(
    Output(img, 'src'),
    Input(inp, 'value'),
)
def update(value):
    if not value:
        return ''
    ys = xs ** int(value)
    fig, ax = subplots()
    ax.plot(xs, ys)
    fig.savefig(buf := BytesIO(), format='png')
    return f'data:img/png;base64,{b64encode(buf.getbuffer()).decode("utf8")}'

app.run_server(debug=True)

panel

print("Let's take a look!")

```python -m panel serve from panel.pane import HTML

HTML(‘’’ <h1>Dashboard</h1> ‘’’).servable()


```python -m panel serve
from panel import Column
from panel.widgets import TextInput


Column(
    '# Dashboard',
    TextInput(),
).servable()

```python -m panel serve from matplotlib.pyplot import subplots from numpy import linspace

from panel import Column, bind from panel.widgets import IntSlider

def plot(exp): xs = linspace(-100, +100, 1_001) fig, ax = subplots() ax.plot(xs, xs ** exp) return fig

Column( ‘# Dashboard’, exp := IntSlider(start=2, end=10), bind(plot, exp=exp), ).servable()


```python -m panel serve
from matplotlib.pyplot import subplots
from numpy import linspace

from panel import Column, bind
from panel.widgets import IntSlider

def create_slider(end):
    return IntSlider(start=2, end=end + 1)

Column(
    '# Dashboard',
    inp1 := IntSlider(start=2, end=10),
    bind(create_slider, end=inp1),
).servable()

```python -m panel serve from pathlib import Path

from pandas import read_pickle

from panel import Column from panel.widgets import Select

data_dir = Path(‘data’)

industries = read_pickle(data_dir / ‘industries.pkl’)

Column( ‘# Dashboard’, Select(options=sorted(industries.unique())), ).servable()


```python -m panel serve
from pathlib import Path

from pandas import read_pickle, IndexSlice

from panel import Column, bind
from panel.widgets import Select

data_dir = Path('data')

industries = read_pickle(data_dir / 'industries.pkl')
prices = read_pickle(data_dir / 'prices.pkl')

def graph_prices(industry):
    if not industry:
        return '*Select an industry.*'
    tickers = industries.loc[lambda s: s == industry].index
    return prices.loc[IndexSlice[:, tickers, :], 'bid'].unstack('ticker').plot()

Column(
    '# Dashboard',
    sel := Select(options=sorted(industries.unique())),
    bind(graph_prices, industry=sel)
).servable()

```python -m panel serve from pathlib import Path

from pandas import read_pickle, IndexSlice from matplotlib.pyplot import subplots

from panel import Column, bind from panel.widgets import Select

data_dir = Path(‘data’)

industries = read_pickle(data_dir / ‘industries.pkl’) prices = read_pickle(data_dir / ‘prices.pkl’)

def graph_prices(industry): if not industry: return ‘Select an industry.

tickers = industries.loc[lambda s: s == industry].index
data = prices.loc[IndexSlice[:, tickers, :], 'bid'].unstack('ticker').plot()

fig, ax = subplots()
data.plot(ax=ax)
return fig

Column( ‘# Dashboard’, sel := Select(options=sorted(industries.unique())), bind(graph_prices, industry=sel) ).servable()


```python -m panel serve
from panel import Column, Row, bind

Column(
    '# Dashboard',
    Row(
        Column(
            '## prices',
        ),
        Column(
            '## trades',
        ),
    ),
).servable()

```python -m panel serve from pathlib import Path

from pandas import read_pickle, IndexSlice

from panel import Column, Row, bind from panel.widgets import Select

data_dir = Path(‘data’)

industries = read_pickle(data_dir / ‘industries.pkl’) prices = read_pickle(data_dir / ‘prices.pkl’) trades = read_pickle(data_dir / ‘trades.pkl’)

def ticker_select(industry): return Select(options=[industry])

def portfolio_select(industry): return Select(options=[industry])

Column( ‘# Dashboard’, Row( Column( ‘## prices’, ind_sel := Select(options=sorted(industries.unique())), ), Column( ‘## trades’, trd_sel := bind(ticker_select, industry=ind_sel), pf_sel := bind(portfolio_select, industry=ind_sel), ), ), ).servable()


```python -m panel serve
from pathlib import Path

from pandas import read_pickle, IndexSlice

from panel import Column, Row, bind
from panel.widgets import Select

data_dir = Path('data')

industries = read_pickle(data_dir / 'industries.pkl')
prices = read_pickle(data_dir / 'prices.pkl')
trades = read_pickle(data_dir / 'trades.pkl')

def ticker_select(industry):
    if not industry:
        return '*Please select industry.*'
    tickers = industries.loc[lambda s: s == industry].index
    return Select(options=sorted(tickers.unique()))

def portfolio_select(industry):
    if not industry:
        return '*Please select industry.*'
    tickers = industries.loc[lambda s: s == industry].index
    portfolios = trades.loc[IndexSlice[:, :, tickers, :]].index.get_level_values('portfolio')
    return Select(options=sorted(portfolios.unique()))

Column(
    '# Dashboard',
    Row(
        Column(
            '## prices',
            ind_sel := Select(options=sorted(industries.unique())),
        ),
        Column(
            '## trades',
            tick_sel := bind(ticker_select, industry=ind_sel),
            pf_sel := bind(portfolio_select, industry=ind_sel),
        ),
    ),
).servable()

```python -m panel serve from pathlib import Path

from matplotlib.pyplot import subplots from pandas import read_pickle, IndexSlice

from panel import Column, Row, bind from panel.widgets import Select

data_dir = Path(‘data’)

industries = read_pickle(data_dir / ‘industries.pkl’) prices = read_pickle(data_dir / ‘prices.pkl’) trades = read_pickle(data_dir / ‘trades.pkl’)

def ticker_select(industry): if not industry: return ‘Please select industry.’ tickers = industries.loc[lambda s: s == industry].index return Select(options=sorted(tickers.unique()))

def portfolio_select(industry): if not industry: return ‘Please select industry.’ tickers = industries.loc[lambda s: s == industry].index portfolios = trades.loc[IndexSlice[:, :, tickers, :]].index.get_level_values(‘portfolio’) return Select(options=sorted(portfolios.unique()))

def plot_prices(industry): fig, ax = subplots() tickers = industries.loc[lambda s: s == industry].index prices.loc[IndexSlice[:, tickers, :]].unstack(‘ticker’).plot(ax=ax) return fig

def plot_trades(ticker, portfolio): ticker, portfolio = ticker.value, portfolio.value fig, ax = subplots() ( trades.loc[IndexSlice[:, portfolio, ticker, :], ‘price’] .droplevel([‘portfolio’, ‘ticker’]) .plot(ax=ax) ) return fig

Column( ‘# Dashboard’, Row( Column( ‘## prices’, ind_sel := Select(options=sorted(industries.unique())), bind(plot_prices, industry=ind_sel), ), Column( ‘## trades’, tick_sel := bind(ticker_select, industry=ind_sel), port_sel := bind(portfolio_select, industry=ind_sel), bind(plot_trades, ticker=tick_sel, portfolio=port_sel), ), ), ).servable()


```python -m panel serve
from pathlib import Path

from matplotlib.pyplot import subplots
from pandas import read_pickle, IndexSlice

from panel import Column, Row, bind
from panel.widgets import Select

data_dir = Path('data')

industries = read_pickle(data_dir / 'industries.pkl')
prices = read_pickle(data_dir / 'prices.pkl')
trades = read_pickle(data_dir / 'trades.pkl')

def ticker_select(industry):
    if not industry:
        return '*Please select industry.*'
    tickers = industries.loc[lambda s: s == industry].index
    return Select(options=sorted(tickers.unique()))

def portfolio_select(industry):
    if not industry:
        return '*Please select industry.*'
    tickers = industries.loc[lambda s: s == industry].index
    portfolios = trades.loc[IndexSlice[:, :, tickers, :]].index.get_level_values('portfolio')
    return Select(options=sorted(portfolios.unique()))

def plot_prices(industry):
    fig, ax = subplots()
    tickers = industries.loc[lambda s: s == industry].index
    prices.loc[IndexSlice[:, tickers, :]].unstack('ticker').plot(ax=ax)
    return fig

def plot_trades(ticker, portfolio):
    fig, ax = subplots()
    (
        trades.loc[IndexSlice[:, portfolio, ticker, :], 'price']
        .droplevel(['portfolio', 'ticker'])
        .plot(ax=ax)
    )
    return fig

def trades_col(industry):
    return Column(
        '## trades',
        tick_sel := ticker_select(industry),
        port_sel := portfolio_select(industry),
        bind(plot_trades, ticker=tick_sel, portfolio=port_sel),
    )

Column(
    '# Dashboard',
    Row(
        Column(
            '## prices',
            ind_sel := Select(options=sorted(industries.unique())),
            bind(plot_prices, industry=ind_sel),
        ),
        bind(trades_col, industry=ind_sel),
    ),
).servable()

```python -m panel serve from numpy import linspace

from bokeh.plotting import figure

from panel import Column, bind from panel.widgets import IntSlider

xs = linspace(-100, +100, 1_001)

def plot(exp): fig = figure(title=’plot’) fig.line(xs, xs**exp) return fig

Column( ‘# Dashboard’, sld := IntSlider(start=1, end=9), bind(plot, exp=sld), ).servable()


```python -m panel serve
from pathlib import Path

from bokeh.plotting import figure
from pandas import read_pickle, IndexSlice

from panel import Column, Row, bind
from panel.widgets import Select

data_dir = Path('data')

industries = read_pickle(data_dir / 'industries.pkl')
prices = read_pickle(data_dir / 'prices.pkl')
trades = read_pickle(data_dir / 'trades.pkl')

def ticker_select(industry):
    if not industry:
        return '*Please select industry.*'
    tickers = industries.loc[lambda s: s == industry].index
    return Select(options=sorted(tickers.unique()))

def portfolio_select(industry):
    if not industry:
        return '*Please select industry.*'
    tickers = industries.loc[lambda s: s == industry].index
    portfolios = trades.loc[IndexSlice[:, :, tickers, :]].index.get_level_values('portfolio')
    return Select(options=sorted(portfolios.unique()))

def plot_prices(industry):
    fig = figure(title='prices')
    tickers = industries.loc[lambda s: s == industry].index
    for t, s in prices.loc[IndexSlice[:, tickers, :], 'bid'].groupby('ticker'):
        fig.line(s.index.get_level_values('date'), s.values, legend_label=t)
    return fig

def plot_trades(ticker, portfolio):
    fig = figure(title='trades')
    for (p, t), s in trades.loc[IndexSlice[:, portfolio, ticker, :], 'price'].groupby(['portfolio', 'ticker']):
        fig.line(s.index.get_level_values('date'), s.values, legend_label=f'{p}, {t}')
    return fig

def trades_col(industry):
    return Column(
        '## trades',
        tick_sel := ticker_select(industry),
        port_sel := portfolio_select(industry),
        bind(plot_trades, ticker=tick_sel, portfolio=port_sel),
    )


Column(
    '# Dashboard',
    Row(
        Column(
            '## prices',
            ind_sel := Select(options=sorted(industries.unique())),
            bind(plot_prices, industry=ind_sel),
        ),
        bind(trades_col, industry=ind_sel),
    ),
).servable()

voilà

print("Let's take a look!")

streamlit

print("Let's take a look!")

```python -m streamlit run –server.headless true –server.address localhost from streamlit import title

title(‘Dashboard’)


```python -m streamlit run --server.headless true --server.address localhost
from streamlit import title, slider

title('Dashboard')
print(slider('value', 0, 10))

```python -m streamlit run –server.headless true –server.address localhost from numpy import linspace

from bokeh.plotting import figure from streamlit import title, slider, bokeh_chart

xs = linspace(-100, +100, 1_001)

title(‘Dashboard’)

exp = slider(‘value’, 0, 10)

print(f’{exp = }’)

fig = figure(title=’plot’) fig.line(xs, xs ** exp) bokeh_chart(fig)


```python -m streamlit run --server.headless true --server.address localhost
from streamlit import title, multiselect, container, columns

title('Dashboard')
with container():
    left, right = columns(2)

    with left:
        multiselect('industry', options=['a', 'b', 'c'])

    with right:
        multiselect('portfolio', options=['a', 'b', 'c'])
        multiselect('ticker', options=['a', 'b', 'c'])

```python -m streamlit run –server.headless true –server.address localhost from pathlib import Path

from pandas import read_pickle, IndexSlice

from streamlit import title, multiselect, container, columns

data_dir = Path(‘data’)

industries = read_pickle(data_dir / ‘industries.pkl’) prices = read_pickle(data_dir / ‘prices.pkl’) trades = read_pickle(data_dir / ‘trades.pkl’)

title(‘Dashboard’) with container(): left, right = columns(2)

with left:
    inds = multiselect('industry', options=sorted(industries.unique()))

ticks = industries.loc[lambda s: s.isin(inds)].index
ports = trades.loc[IndexSlice[:, :, ticks, :]].index.get_level_values('portfolio')

with right:
    multiselect('portfolio', options=sorted(ports.unique()))
    multiselect('ticker', options=sorted(ticks.unique())) ```

```python -m streamlit run –server.headless true –server.address localhost from pathlib import Path

from pandas import read_pickle, IndexSlice

from bokeh.plotting import figure from streamlit import title, multiselect, container, columns, bokeh_chart

data_dir = Path(‘data’)

industries = read_pickle(data_dir / ‘industries.pkl’) prices = read_pickle(data_dir / ‘prices.pkl’) trades = read_pickle(data_dir / ‘trades.pkl’)

title(‘Dashboard’) with container(): left, right = columns(2, gap=’large’)

with left, container():
    inds = multiselect('industry', options=sorted(industries.unique()))

    ticks = industries.loc[lambda s: s.isin(inds)].index
    ports = trades.loc[IndexSlice[:, :, ticks, :]].index.get_level_values('portfolio')

    px_fig = figure()
    for t, s in prices.loc[IndexSlice[:, ticks, :], 'bid'].groupby('ticker'):
        px_fig.line(s.index.get_level_values('date'), s.values, legend_label=t)
    bokeh_chart(px_fig, use_container_width=True)

with right, container():
    port = multiselect('portfolio', options=sorted(ports.unique()))
    tick = multiselect('ticker', options=sorted(ticks.unique()))

    td_fig = figure()
    for (p, t), s in (
        trades
            .loc[IndexSlice[:, port, :, :]]
            .loc[IndexSlice[:, :, tick, :]]['price']
            .groupby(['portfolio', 'ticker'])
    ):
        td_fig.line(s.index.get_level_values('date'), s.values, legend_label=f'{p}, {t}')
    bokeh_chart(px_fig, use_container_width=True) ```

```python -m streamlit run –server.headless true –server.address localhost from pathlib import Path

from pandas import read_pickle, IndexSlice

from bokeh.plotting import figure from streamlit import title, multiselect, container, columns, bokeh_chart, experimental_memo, set_page_config set_page_config(layout=’wide’)

@experimental_memo def load_data(): data_dir = Path(‘data’) return ( read_pickle(data_dir / ‘industries.pkl’), read_pickle(data_dir / ‘prices.pkl’), read_pickle(data_dir / ‘trades.pkl’), ) industries, prices, trades = load_data()

title(‘Dashboard’) with container(): left, right = columns(2, gap=’large’)

with left, container():
    inds = multiselect('industry', options=sorted(industries.unique()))

    ticks = industries.loc[lambda s: s.isin(inds)].index
    ports = trades.loc[IndexSlice[:, :, ticks, :]].index.get_level_values('portfolio')

    px_fig = figure()
    for t, s in prices.loc[IndexSlice[:, ticks, :], 'bid'].groupby('ticker'):
        px_fig.line(s.index.get_level_values('date'), s.values, legend_label=t)
    bokeh_chart(px_fig, use_container_width=True)

with right, container():
    multiselect('portfolio', options=sorted(ports.unique()))
    multiselect('ticker', options=sorted(ticks.unique()))

    td_fig = figure()
    for (p, t), s in (
        trades
            .loc[IndexSlice[:, ports, :, :]]
            .loc[IndexSlice[:, :, ticks, :]]['price']
            .groupby(['portfolio', 'ticker'])
    ):
        td_fig.line(s.index.get_level_values('date'), s.values, legend_label=f'{p}, {t}')
    bokeh_chart(px_fig, use_container_width=True) ```