Make interactive charts with bokeh

Bokeh is a Python library for interactive data visualization, which allow users to create dynamic and engaging charts that go beyond static pictures. Bokeh's toolkit offers a range of interactive features, from hover tooltips, zoomable plots, to dropdown selection . Here is a demonstration of how to use Bokeh to create an interactive chart to compare historical stock price performance between 7 stocks

  1. Download and prepare historical stock data

Using yfinance library to scrape data from Yahoo Finance and prepare it the usual way


# import libraries
import yfinance as yf
import pandas as pd
import datetime

# Download all stock price historical data from yahoo finance
spy_data = yf.download("SPY")
aapl_data = yf.download("AAPL")
goog_data = yf.download("GOOG")
tsla_data = yf.download("TSLA")
amzn_data = yf.download("AMZN")
meta_data = yf.download("META")
nvda_data = yf.download("NVDA")

# Reset index to turn date to a separate column
spy_data.reset_index(inplace=True)
aapl_data.reset_index(inplace=True)
goog_data.reset_index(inplace=True)
tsla_data.reset_index(inplace=True)
amzn_data.reset_index(inplace=True)
meta_data.reset_index(inplace=True)
nvda_data.reset_index(inplace=True)

# Add a column for ticker symbol
spy_data['Ticker']  = 'SPY'
aapl_data['Ticker'] = 'AAPL'
goog_data['Ticker'] = 'GOOG'
tsla_data['Ticker'] = 'TSLA'
amzn_data['Ticker'] = 'AMZN'
meta_data['Ticker'] = 'META'
nvda_data['Ticker'] = 'NVDA'

# Preview dataframe
spy_data.head()

Printing out the first 5 rows of a dataframe to examine if data shows up as expected


# Put all stocks into a consolidated data frame
stock_all = pd.concat([spy_data, aapl_data, goog_data, tsla_data, amzn_data, meta_data, nvda_data])

# Restrict data to work with to only dates after specific year
stock_all['Date'] = pd.to_datetime(stock_all['Date'])
df = stock_all[stock_all['Date'] >= '2010-01-01']

# preview data frame structure
df.info()

2. Create an interactive chart to compare historical price performance

First, import related modules

# import libraries
from bokeh.layouts import layout, column, row
from bokeh.models import ColumnDataSource, RangeSlider, DateRangeSlider, HoverTool, CDSView, BooleanFilter, CustomJS, Dropdown, Select, Div
from bokeh.plotting import figure, output_notebook, show
output_notebook()

And create a chart, add in Timeline Slider, Legend and Hover Tools


# Define date range for graph
start_date = pd.to_datetime('2010-01-01')
end_date   = datetime.datetime.now()
date_rangeX = pd.date_range(start = start_date, end = end_date)

# Create lists for ticker & color
ticker_list = ['SPY',       'AAPL',    'AMZN',     'GOOG',   'META',       'NVDA',  'TSLA']
color_list  = ['lightblue', 'red',   'orange', 'darkblue',  'olive',  'darkgreen',  'pink']

# Instantiating the figure object
graph = figure(title = f"Stock Closing Prices {start_date.year}-{end_date.year}",
               x_axis_type = "datetime",
               x_axis_label = 'Date', 
               y_axis_label = 'Price (USD)',
               sizing_mode = "stretch_width",
               height = 500)

# Make font size of title bigger
graph.title.text_font_size = '20pt'
graph.title.align = "center"


# Draw graphs for all ticker on the list
for data, name, color in zip([df[df['Ticker']== 'SPY'],    df[df['Ticker']== 'AAPL'], 
                              df[df['Ticker']== 'AMZN'],   df[df['Ticker']== 'GOOG'], 
                              df[df['Ticker']== 'META'],   df[df['Ticker']== 'NVDA'], 
                              df[df['Ticker']== 'TSLA']], 
                              ticker_list, 
                              color_list ):
    graph.line(data['Date'], data['Adj Close'], line_width=1.5, color=color, alpha=0.8, legend_label=name)
    
# Put legend to top left corner & define click_policy
graph.legend.location = "top_left"
graph.legend.click_policy = "hide"

# Set up RangeSlider for timeline
timeline_slider = DateRangeSlider(    title = "Adjust timeline (x-axis) range",
                                      start = date_rangeX.min(),
                                      end   = date_rangeX.max(),
                                      step  = 1,
                                      value = (date_rangeX.min(), date_rangeX.max()),
                                      sizing_mode = "stretch_width")

# Add callback code
timeline_slider.js_link("value", graph.x_range, "start", attr_selector=0)
timeline_slider.js_link("value", graph.x_range, "end", attr_selector=1)

# Define the tooltip
hover_tool = HoverTool(  tooltips   = [   ('Date', '@x{%F}'),  ('Adj Price',  '@y{$0.00}' )   ],
                         formatters = {'@x': 'datetime'}  )

# Add hover_tool to graph
graph.add_tools(hover_tool)

# create layout
layout = column(graph, timeline_slider, sizing_mode = 'stretch_both')

# show result
show(layout)

And the result is a beautiful interactive chart that allows users to read details when they want to utilizing different tools and to narrow comparison to a subset of stocks

Moving the timeline range at the bottom of the chart to start in 2021, we can zoom into the last 2+ years of stock performance. If we hover the mouse over each line, details about date and adjusted closing price are shown

To narrow down the selection of stock to compare, we can click on the ticker symbols in the legend box to the left. In the example below, I want to focus on GOOG, META, and TSLA

You can download the Jupiter Notebook from my Github repository here:

https://github.com/ExcellentBee/Learning-Everyday/blob/main/Stock%20Price%20Comparison%20Interactive%20Charting%20with%20Bokeh.ipynb

Previous
Previous

Scrape Data from Yahoo Finance

Next
Next

Interactive Selection Chart using Bokeh