<jupyter_start><jupyter_text>Bokeh Basics- Charts are built up *one layer at a time*- First we create a `figure` and add elements called *glyphs* to it    - Glyphs can take one of many different shapes    - This is similar to the *geom* elements in `ggplot`    ---The basic steps to creating plots with the `bokeh.plotting` interface are:- Prepare some data    - NumPy arrays or Pandas series.- Tell Bokeh where to generate output    - `output_file('foo.html')` or `output_notebook()`- Call `figure()`    - Create a plot canvas with title, axes labels, etc- Add renderers    - Use `line()` etc, specifying visual customizations like colors, legends and widths- Ask Bokeh to `show()` or `save()` the results.    - Save the plot to an HTML file and/or optionally display it in a browser.    ```pythonfrom bokeh.io import output_notebook, showfrom bokeh.plotting import figureoutput_notebook()df = pd.read_csv(...)p = figure(title=, width=, height=, x_range=, y_range=, tools=, ...)p.circle(x=, y=, color=, ...)p.line(x=, y=, ...)p.xaxis.axis_label = ''p.yaxis.axis_label = ''show(p)```--- Plots- Plots are the central concept in Bokeh. - They are containers that hold all the various objects (renderers, guides, data, and tools) that comprise the final visualization- The Figure class helps with assembling all the necessary objects- The convenience function `figure()` creates Figure objects. Glyphs- Glyphs are the basic visual *marks* that Bokeh can display. - At the lowest level, there are glyph objects, such as line() or circle()- The visual appearance of a glyph is tied directly to the data values that are associated with the glyph’s various attributes.    - attributes like x and y can be set to vectors of data.    - glyphs also have some combination of Line Properties, Fill Properties, and Text Properties to control their appearance.     Guides, Annotations- Guides are visual aids that help users judge distances, angles, etc.     - These include grid lines or bands, axes (such as linear, log, or datetime) that may have ticks and tick labels as well. - Annotations are visual aids that label or name parts of the plot.     - These include titles, legends, etc.<jupyter_code>import os

import pandas as pd
from pandas import Series, DataFrame

path_to_data = "/Users/dkhosla/.bokeh/data/"
Series(sorted(os.listdir(path_to_data)))
df = \
(pd
 .read_csv(f"{path_to_data}/gapminder_population.csv")
 .set_index("Country")
 .T
 .reset_index()
)

df.head()

df2 = \
(pd
 .read_csv(f"{path_to_data}/gapminder_life_expectancy.csv")
 .set_index("Country")
 .T
 .reset_index()
)

df2.head()
from bokeh.plotting import figure, output_notebook, show, DEFAULT_TOOLS
from bokeh.models import ColumnDataSource

TOOLS = "crosshair,pan,wheel_zoom,box_zoom,reset,box_select,lasso_select"
output_notebook()
plot_1 = figure(
    width=800, 
    height=350,
    tools=DEFAULT_TOOLS
)

plot_1.line(
    x=df['index'], 
    y=df['India'], 
    legend='India', 
    line_color='orange',
    line_width=3
)

plot_1.line(
    x=df['index'], 
    y=df['China'], 
    legend='China',
    line_color='steelblue',
    line_width=3
)

plot_1.title.text = 'Gapminder Population'
plot_1.title.text_font = 'Arial'
plot_1.title.text_font_style = 'bold'

plot_1.xaxis.axis_label = 'Time'
plot_1.yaxis.axis_label = 'Population'

show(plot_1)
plot_2 = figure(
    width=800, 
    height=500,
    tools=TOOLS
)

plot_2.circle_x(
    x=df['index'], 
    y=df2['India'], 
    size=df['India'].divide(10**8),
    alpha=0.2,
    color='orange',
    legend='India'
)

plot_2.circle_cross(
    x=df['index'], 
    y=df2['China'], 
    size=df['China'].divide(10**8),
    alpha=0.2,
    color='steelblue',
    legend='China'
)

plot_2.circle(
    x=df['index'], 
    y=df2['United States'], 
    size=df['United States'].divide(10**8),
    alpha=0.2,
    color='red',
    legend='United States'
)

plot_2.title.text = 'Gapminder Population'
plot_2.xaxis.axis_label = 'Time'
plot_2.yaxis.axis_label = 'Life Expectancy'

show(plot_2)
df_ = \
(df
 .query("index == '2000'")
 .drop('index', axis=1)
 .T
 .squeeze()
 .nlargest(10)
 .divide(10**8)
 .pipe(Series, name='Population')
 .to_frame()
 .reset_index()
)

from bokeh.palettes import Greys11
from bokeh.transform import factor_cmap
source_ = ColumnDataSource(data=df_)

TOOLTIPS = [
    ('Country', '@Country'),
    ('Population', '@Population')
]

plot_3 = figure(
    width=800, 
    height=500, 
    tools='hover',
    tooltips=TOOLTIPS,
    title='10 most populous nations in 2000', 
    x_axis_label='Population in 2000',
    x_range=df_.Country.tolist()
)

plot_3.vbar(
    x='Country',  
    top='Population', 
    width=0.75,
    source=source_,
    line_color='white',
    fill_color=factor_cmap('Country', palette=Greys11, factors=df_.Country.tolist())
)

show(plot_3)<jupyter_output><empty_output><jupyter_text>--- Creating Grids<jupyter_code>from bokeh.layouts import gridplot
# Vertical
show(gridplot([plot_2, plot_3], ncols=1))
# Horizontal
show(gridplot([[plot_2, plot_3]], nrows=1))<jupyter_output><empty_output><jupyter_text>---  Selections<jupyter_code>from bokeh.sampledata.autompg import autompg_clean
from bokeh.models import ColumnDataSource
source_ = ColumnDataSource(autompg_clean)
p = figure(title='Select any point', 
           height=400,
           tools='tap')

p.circle(x='mpg', 
         y='hp', 
         source=source_, 
         size=10, 
         selection_color="firebrick")

show(p)
from bokeh.models.tools import HoverTool
from bokeh.sampledata.iris import flowers
from bokeh.models.annotations import Span, Label
p = figure(title='Hover over points', 
           height=400)

cr = \
p.circle(x='petal_width', 
         y='sepal_width', 
         source=flowers, 
         color='lightgreen',
         size=10, 
         hover_color="firebrick")

p.add_tools(HoverTool(tooltips=None, 
                      renderers=[cr], 
                      mode='vline'))

p.xaxis.axis_label = 'Petal Width'
p.yaxis.axis_label = 'Sepal Width'

vline = Span(dimension='height', location=0.75, line_width=2, line_color='steelblue')
p.add_layout(vline)

label = Label(x=0.8, y=4.4, text='Classification Boundary', text_baseline='middle')
p.add_layout(label)

show(p)<jupyter_output><empty_output><jupyter_text>Tooltips<jupyter_code># Get the data and save it as a ColumnDataSource
df_AAPL = DataFrame(AAPL).assign(date = lambda fr: pd.to_datetime(fr['date']))
display(df_AAPL.head())

source_ = ColumnDataSource(df_AAPL.iloc[:200, :])

hover = HoverTool(tooltips=[
    ('Stock', 'AAPL'),
    ('Vol', '@volume'),
    ('Adj Close', '@adj_close')
])

plot_ = figure(
    height=300,
    width=800,
    tools=[hover],
    x_axis_type='datetime',
    title='Simple Tooltips on Hover'
)

plot_.line(
    source=source_,
    x='date',
    y='adj_close'
)

show(plot_)<jupyter_output><empty_output><jupyter_text>--- Linked Interactions 1. Panning- We'll link the **ranges** of two (or more) plots- When one of the plots is panned or zoomed (or otherwise has its range changed) the other plots will update in unison<jupyter_code>from bokeh.layouts import column
from bokeh.models import ColumnDataSource, RangeTool
from bokeh.sampledata.stocks import AAPL

# Get the data and save it as a ColumnDataSource
df_AAPL = DataFrame(AAPL).assign(date = lambda fr: pd.to_datetime(fr['date']))
source_ = ColumnDataSource(df_AAPL)

# Create the child plot
p = figure(height=300, 
           width=800, 
           tools='', 
           toolbar_location=None, 
           x_axis_type='datetime', 
           x_range=(df_AAPL['date'].iloc[1500], df_AAPL['date'].iloc[2500])
          )

p.line(x='date', 
       y='adj_close', 
       line_width=3,
       line_color='steelblue',
       source=source_)

p.yaxis.axis_label = 'Adjusted Closing Price'
p.xaxis.axis_label = 'Time'

# Create the parent plot
q = figure(title='Select a time window to zoom in to',
           height=150, 
           width=800, 
           tools='', 
           toolbar_location=None, 
           x_axis_type='datetime', 
          )

q.line(x='date', 
       y='adj_close', 
       source=source_)

q.xgrid.grid_line_color = None
q.ygrid.grid_line_color = None

# Define the Range tool
range_tool = RangeTool(x_range=p.x_range)
range_tool.overlay.fill_color = "lightgray"
range_tool.overlay.fill_alpha = 0.5

# Add the tool to the parent plot
q.add_tools(range_tool)
q.toolbar.active_multi = range_tool

# Show
show(column(q, p))<jupyter_output><empty_output><jupyter_text>2. Brushing<jupyter_code>TOOLS = 'box_select,lasso_select'
source_ = ColumnDataSource(df_AAPL)

one = figure(
    tools=TOOLS,
    height=300,
    x_axis_type='datetime'
)

one.line(
    x='date',
    y='adj_close',
    source=source_
)

two = figure(
    tools=TOOLS,
    height=300,
    x_axis_type='datetime'
)

two.circle(
    x='date',
    y='open',
    source=source_
)

show(gridplot([[one, two]]))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1309617326899338, 'fraction_numerical': 0.016945348445741217, 'mean_word_length': 3.8434782608695652, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '280560', 'license': 'MIT', 'n_tokens_mistral': 3256, 'n_tokens_neox': 3059, 'n_words': 752, 'path': '05-bokeh/dk-bokeh-notes.ipynb', 'repo_name': 'dushyantkhosla/dataviz', 'size': '8911'}