โ€น Geoff Ruddock

bokeh

import os, sys
import datetime as dt
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#from bokeh.sampledata import download
#download()

%matplotlib inline
%reload_ext autoreload
%autoreload 2

Bokeh

from bokeh.io import output_notebook, push_notebook
from bokeh.plotting import figure, show

output_notebook(hide_banner=True)
output_notebook(verbose=True)
Loading BokehJS ...

Using Settings:

Bokeh version 2.3.2
BokehJS js ['https://cdn.bokeh.org/bokeh/release/bokeh-2.3.2.min.js', 'https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.3.2.min.js', 'https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.3.2.min.js']
css []

Warning: BokehJS previously loaded

Line charts

Single line

fig = figure(plot_width=800, plot_height=400)

x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]

fig.line(x, y, line_width=2)

show(fig)

Use ColumnDataSource

from bokeh.models import ColumnDataSource
from bokeh.sampledata.stocks import AAPL

fig = figure(
    x_axis_type='datetime'
)

aapl_df = (
    pd.DataFrame(
        {'price': AAPL['adj_close']},
        index=pd.DatetimeIndex(AAPL['date']).rename('date')
    ).reset_index()
)

cds_aapl = ColumnDataSource(aapl_df)

fig.line('date', 'price', source=cds_aapl)

show(fig)
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

<ipython-input-5-93148acf9bef> in <module>
      1 from bokeh.models import ColumnDataSource
----> 2 from bokeh.sampledata.stocks import AAPL
      3 
      4 fig = figure(
      5     x_axis_type='datetime'


~/opt/anaconda3/lib/python3.8/site-packages/bokeh/sampledata/stocks.py in <module>
     96 #-----------------------------------------------------------------------------
     97 
---> 98 AAPL = _read_data('AAPL')
     99 FB   = _read_data('FB')
    100 GOOG = _read_data('GOOG')


~/opt/anaconda3/lib/python3.8/site-packages/bokeh/sampledata/stocks.py in _read_data(name)
     68 
     69     '''
---> 70     filename = external_path(name+'.csv')
     71     data = {
     72         'date' : [],


~/opt/anaconda3/lib/python3.8/site-packages/bokeh/util/sampledata.py in external_path(filename)
    121 
    122 def external_path(filename: str) -> str:
--> 123     data_dir = external_data_dir()
    124     fn = join(data_dir, filename)
    125     if not exists(fn) and isfile(fn):


~/opt/anaconda3/lib/python3.8/site-packages/bokeh/util/sampledata.py in external_data_dir(create)
    108     if not exists(data_dir):
    109         if not create:
--> 110             raise RuntimeError('bokeh sample data directory does not exist, please execute bokeh.sampledata.download()')
    111         print("Creating %s directory" % data_dir)
    112         try:


RuntimeError: bokeh sample data directory does not exist, please execute bokeh.sampledata.download()

HoverTool

Bokeh docs: HoverTool

  • field names that begin with $ are special fields, e.g. coordinates
  • @ are columns of a ColumnDataSource
  • Combined as @$name looks up the value of $name at hover point and looks for that column.
import bokeh
bokeh.__version__
# from bokeh.plotting import reset_output
# reset_output()
# output_notebook()

from bokeh.models import HoverTool, DatetimeTickFormatter

fig = figure(
    x_axis_type='datetime',
    plot_height=400,
    sizing_mode='scale_width'
)

cds_aapl = ColumnDataSource(aapl_df)
fig.line('date', 'price', source=cds_aapl)


def datetime(x):
    return np.array(x, dtype=np.datetime64)

fig.add_tools(HoverTool(
    tooltips=[
        ('Date', '@date{%F}'),
        ('Price', '@price')
    ],
    formatters={'@date': 'datetime'},
    mode='vline'
))

fig.xaxis.formatter = DatetimeTickFormatter(
    months=['%b %Y'],
    days=['%b %d']
)

show(fig)
type(fig.xaxis.formatter)
fig.xaxis.formatter.update()
fig.xaxis.formatter.to_json(True)

Multiple lines

from bokeh.sampledata.stocks import AAPL, GOOG

goog = pd.Series(GOOG['adj_close'], index=pd.DatetimeIndex(GOOG['date']).rename('date')).rename('GOOG')
aapl = pd.Series(AAPL['adj_close'], index=pd.DatetimeIndex(AAPL['date']).rename('date')).rename('AAPL')

df = pd.concat([goog, aapl], axis=1).dropna()
df
from bokeh.plotting import reset_output
reset_output()
output_notebook()

from bokeh.palettes import Category10

fig = figure(
    x_axis_type='datetime',
    plot_height=400,
    sizing_mode='scale_width',
    title='Demo of multiple lines'
)

source = df.reset_index().pipe(ColumnDataSource)

for i, col in enumerate(df.columns.tolist()):
    fig.line(
        'date',
        col,
        source=source,
        name=col,
        color=Category10[3][i]
    )


fig.line('date', 'GOOG', source=source, name='GOOG')

fig.add_tools(HoverTool(
    tooltips=[
        ('Date', '@date{%F}'),
        ('Name', '$name'),
        ('Price', '@AAPL')
    ],
    formatters={'@date': 'datetime'},
    #mode='vline'
))

show(fig)

Looping w/ Bokeh

Bokeh’s multi_line method is a bit confusing to use with ColumnDataSource and HoverTool, so it’s best to simply loop over each series and plot them individually. (src)

from bokeh.io import show
from bokeh.models import ColumnDataSource
from bokeh.models import HoverTool
from bokeh.palettes import Category10
from bokeh.plotting import figure

p2 = figure(plot_width=600, plot_height=300)
grp_list = df.group.unique()

for i in range(len(grp_list)):
    source = ColumnDataSource(data={
        'group':df.loc[df.group == grp_list[i]].group,
        'x':df.loc[df.group == grp_list[i]].x,
        'y':df.loc[df.group == grp_list[i]].y}
    )

    p2.line(
        x='x', y='y',
        source=source,
        legend_label=grp_list[i],
        color=(Category10[3])[i]
    )
    
p2.add_tools(HoverTool(tooltips=[('group','@group'),('x','@x'),('y','@y')]))
show(p2)
from bokeh.models import HoverTool, ColumnDataSource

tooltips = [
    ('X', '@xs'),
    ('Y', '@ys')
]

fig = figure(
    plot_width=400, plot_height=400,
    #tooltips=tooltips,
    title='Example with HoverTool'
)


source = ColumnDataSource(data={
    'xs': [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
    'ys': [[1, 1, 2, 2, 3, 3,], [6, 5, 3, 3, 2, 1]]
})

fig.multi_line(xs='xs', ys='ys', line_width=4, source=source)

# fig.multi_line(
#     [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]],
#     [[1, 1, 2, 2, 3, 3,], [6, 5, 3, 3, 2, 1]],
#     color=["firebrick", "navy"], alpha=[0.8, 0.3], line_width=4
# )

tools= HoverTool(tooltips=[('(@x, @y)', '(@xs, @ys)')])

fig.add_tools(tools)

show(fig)

Easy multiple lines w/ hvplot

Source: https://medium.com/@msdata/python-visualization-multiple-line-plotting-2a5483e74da6

group = np.repeat(['A', 'B', 'C'], 10)
x = list(range(1,11))*3
y = np.random.randint(10, size=30)

df = pd.DataFrame({'group': group,'x': x,'y': y})
df.head()
import hvplot.pandas
import holoviews as hv

p1= df.hvplot('x','y', by='group')

fig = hv.render(p1)
show(fig)

๐Ÿ“š Further reading

comments powered by Disqus