
In onze eerdere Bokeh-tutorials bespraken we hoe je je eerste stappen met Bokeh zet en eenvoudige scatter- en lijndiagrammen maakt. Naast de vele mogelijkheden voor datavisualisatie biedt Bokeh ook een manier om apps op je eigen servers te hosten door een verbinding tussen Python en de browser mogelijk te maken.
We beginnen met het maken van de app en deze te draaien op Bokeh-servers om te delen met collega’s. Voor meer informatie over hoe de Bokeh-server werkt, bekijk de Bokeh-documentatie.
Basisprincipes van de Bokeh-server
Bokeh zet objecten (zoals plots, widgets, assen en vrijwel alles wat je maakt) om naar JSON-indeling.
De Bokeh-server zet de Python-code die je schrijft om in een JSON-document. Het JSON-document wordt in JavaScript gerenderd via Bokeh’s clientbibliotheek (BokehJS), zodat gebruikers de applicatie in de browser kunnen bekijken.
Het voordeel van Bokeh is dat het het JavaScript-gedeelte voor zijn rekening neemt. Je hoeft dus geen voorkennis van JavaScript te hebben om een app te maken! De volgende afbeelding geeft een samenvatting van hoe de Bokeh-server werkt.

Bron: The Bokeh Server
Een Bokeh-applicatie bouwen en draaien
De algemene structuur van een Bokeh-applicatie is:
- Maak plots en widgets: Dit is de eerste stap bij het maken van een Bokeh-applicatie. Je hebt een vooraf bepaald plot nodig dat je wilt laten zien.
- Definieer een callbackfunctie: Een callbackfunctie geeft de applicatie instructies over hoe te reageren op gebruikersinteractie. Bijvoorbeeld: wanneer je in een tijdreeksplot een andere ticker selecteert, moet het plot met de nieuwe data worden bijgewerkt.
- Maak layouts: Layouts helpen ons plots effectief en aantrekkelijk te presenteren.
Een Bokeh-webapp voor aandelenanalyse maken
Projectbeschrijving
In deze sectie laten we je zien hoe je een eenvoudige webapp maakt en implementeert voor financieel analisten.
Stel je voor dat je werkt voor Big Money Inc — een toonaangevend vermogensbeheerbedrijf. Je manager heeft collega’s je Pythonvaardigheden horen prijzen. Nu wil ze dat je een aandelenapp maakt die de financieel analisten van het bedrijf zullen gebruiken om twee aandelen te vergelijken. Je manager denkt dat analisten tijd kunnen besparen door snel elk gewenst aandeel te vergelijken met een vergelijkbaar aandeel in dezelfde sector. Zo kunnen ze bijvoorbeeld Apple vergelijken met Microsoft en het beste aandeel kiezen voor de portefeuilles van klanten. De vergelijking moet basisstatistieken bevatten, zoals:
- Trendlijnen van slotkoersen
- Correlatie
- Gemiddelde (verwacht rendement)
- Standaarddeviatie (verwacht risico)
Er moet een manier zijn om de analyseperiode interactief aan te passen. Een gebruiker moet bijvoorbeeld de prestaties van twee aandelen in de afgelopen week, maand, jaar of een willekeurige periode kunnen vergelijken. Zorg ervoor dat de app gemakkelijk beschikbaar is voor alle gebruikers binnen het bedrijf. Dat betekent dat je deze moet implementeren met een clouddienst.
Vereisten
- Basiskennis van Bokeh.
- Enige kennis van Python.
- Een installatie van de pakketten zoals beschreven in onze Getting Started with Bokeh Tutorial.
Overzicht van de aandelenmarkt-webapp
De webapp biedt een oplossing voor de hierboven beschreven casus in finance. Deze webapp laat gebruikers twee tickers selecteren en hun beschrijvende statistieken (zoals gemiddeld en standaarddeviatie) van zowel prijzen als rendementen, correlatieplots en trendlijnen van prijzen voor de geselecteerde aandelen visualiseren. Interactiviteit ontstaat doordat je verschillende combinaties van tickers en verschillende perioden kunt selecteren (op de trendlijnen). De webapp ziet er als volgt uit:

Het Bokeh-project voor de aandelenmarkt-webapp maken
1. Maak een projectmap en noem deze SelectStock.
2. Open de projectmap en maak een bestand met de naam main.py.
3. Sla een kopie van de beursdata op in de projectmap als “all_stocks_5yr.csv”.
Sla een kopie op van de tickers. Het bestand ticker.py bevat de lijst met tickers. Er zijn slechts 505 tickers; de volledige lijst in het script main.py opnemen zou de code onhandig maken. Het is beter om de lijst met tickers in een apart bestand op te slaan en daaruit te importeren wanneer nodig.
Open het bestand main.py in je favoriete code-editor, zoals Spyder, Atom of Sublime Text.
Packages importeren
Typ de volgende code in het bestand main.py. Deze code importeert de packages en tickers die nodig zijn om de webapp te maken:
# Import the required packages
import pandas as pd
from functools import lru_cache
from bokeh.io import curdoc
from bokeh.layouts import column, row
from bokeh.models import ColumnDataSource, PreText, Select, Div
from bokeh.plotting import figure
# load the list of tickers
import tickers
tickers = tickers.tickers
Data inlezen en laden
Schrijf een functie om te voorkomen dat een ticker met zichzelf wordt vergeleken:
# Create a function to ensure that a ticker is not compared to itself
def foo(val, lst):
return [x for x in lst if x != val]
Add the following code to read and load data for the webapp:
# A function to read and load data
# Note the use of @lru_cache() decorator is to cache the data and speed up reloads
@lru_cache()
def load_ticker(ticker):
data = pd.read_csv('all_stocks_5yr.csv', parse_dates=['date'])
data = data.set_index('date')
data = data[data['Name'] == ticker]
return pd.DataFrame({ticker: data.close, ticker+'_returns': data.close.diff()})
# A function to create a dataframe for the selected tickers
@lru_cache()
def get_data(t1, t2):
df1 = load_ticker(t1)
df2 = load_ticker(t2)
data = pd.concat([df1, df2], axis=1)
data = data.dropna()
data['t1'] = data[t1]
data['t2'] = data[t2]
data['t1_returns'] = data[t1+'_returns']
data['t2_returns'] = data[t2+'_returns']
return data
# Put data into a ColumnDataSource
source = ColumnDataSource(
data=dict(date=[], t1=[], t2=[], t1_returns=[], t2_returns=[]))
Widgets maken
# set up widgets
stats = PreText(text='', width=500)
ticker1 = Select(value='AAPL', options=foo('GOOG', tickers))
ticker2 = Select(value='GOOG', options=foo('AAPL', tickers))
Met de widgets kan de gebruiker de eerste en tweede ticker voor de vergelijking selecteren. Zodra je de tickers selecteert, kan Bokeh plots maken.
Plots maken
# set up plots
tools = 'pan,wheel_zoom,xbox_select,reset'
corr = figure(width=400, height=350,
tools='pan,wheel_zoom,box_select,reset', output_backend='webgl')
corr.diamond('t1_returns', 't2_returns', size=2, source=source, color="red",
selection_color="orange", alpha=0.6, nonselection_alpha=0.1, selection_alpha=0.4)
time_series1 = figure(width=900, height=200, tools=tools,
x_axis_type='datetime', active_drag="xbox_select", output_backend='webgl')
time_series1.line('date', 't1', source=source, color='orange')
time_series2 = figure(width=900, height=200, tools=tools,
x_axis_type='datetime', active_drag="xbox_select", output_backend='webgl')
time_series2.x_range = time_series1.x_range
time_series2.line('date', 't2', source=source, color='green')
In deze code definiëren we eerst de tools die bij de plots horen. De correlatieplot is de eerste plot, met de functie figure() die width = 400 en height = 350 specificeert. De correlatieplot gebruikt ruitvormige markers.
We gebruiken de line-glyph om de tijdreeksplots voor de tickers te maken. De bereikinstelling van de tijdreeksen is gelijk, zodat je goed kunt vergelijken.
# Define callbacks
def change_ticker1(attrname, old, new):
ticker2.options = foo(new, tickers)
update()
def change_ticker2(attrname, old, new):
ticker1.options = foo(new, tickers)
update()
def update(selected=None):
t1, t2 = ticker1.value, ticker2.value
df = get_data(t1, t2)
data = df[['t1', 't2', 't1_returns', 't2_returns']]
source.data = data
update_stats(df, t1, t2)
corr.title.text = '%s returns vs. %s returns' % (t1, t2)
time_series1.title.text, time_series2.title.text = t1, t2
def update_stats(data, t1, t2):
stats.text = str(data[[t1, t2, t1+'_returns', t2+'_returns']].describe())
ticker1.on_change('value', change_ticker1)
ticker2.on_change('value', change_ticker2)
def selection_change(attrname, old, new):
t1, t2 = ticker1.value, ticker2.value
data = get_data(t1, t2)
selected = source.selected.indices
if selected:
data = data.iloc[selected, :]
update_stats(data, t1, t2)
source.selected.on_change('indices', selection_change)
In de callback-sectie definiëren de eerste en tweede functie respectievelijk de callback voor ticker 1 en ticker 2.
De functie update() werkt de plots bij wanneer de gebruiker een andere combinatie van tickers selecteert; de functie update_stats() werkt de statistieken bij wanneer de gebruiker een nieuwe set tickers kiest; en de functie selection_change() werkt de hele app bij wanneer de gebruiker tickers bijwerkt.
De layout opzetten
De eerste stap is de app een titel geven die de gebruiker instructies biedt over hoe met de webapp te werken. Met de functie Div kun je de tekst opgeven en de hoogte en breedte definiëren, samen met andere aanpassingen.
# set up layout
# Add a title message to the app
div = Div(
text="""
<p>Select two Stocks to compare key Statistics:</p>
""",
width=900,
height=30,
)
# Create layouts
app_title = div
widgets = column(ticker1, ticker2, stats)
main_row = row(widgets, corr)
series = column(time_series1, time_series2)
layout = column(app_title, main_row, series)
De app-layout combineert zowel de functies column als row.
Eerst staat er bovenaan een titel. De hoofdrij staat daaronder (de hoofdrij bevat de beschrijvende statistieken en de correlatieplot). De volgende rij bevat de eerste tijdreeksplot (voor ticker 1) en de laatste rij bevat de tijdreeksplot voor de tweede ticker.
De app initialiseren
Deze stap initialiseert de webapp wanneer deze op de server wordt aangeroepen.
# initialize the app
update()
curdoc().add_root(layout)
curdoc().title = "Compare Stocks"
De webapp implementeren
Om je webapp te testen, kun je deze implementeren op je lokale machine. Open hiervoor simpelweg Anaconda Prompt of de terminal van jouw keuze. Ga naar de map die de projectmap ‘SelectStock’ bevat. Dit doe je door de volgende code te typen:
cd "System path to where the SelectStock folder is contained"
bijv. cd "C:\Users\... \SelectStock"
Typ de volgende code om de webapp te draaien:
bokeh serve --show SelectStock
Je kunt ook naar de map SelectStock navigeren en het bestand main.py uitvoeren:
Bokeh serve --show main.py
Dit start de webapp in de standaardwebbrowser als:
http://localhost:5006/SelectStock of
Je gebruikt de Bokeh Server om je webapp te draaien en te implementeren.
Je kunt de webapp ook implementeren met diensten zoals Heroku.
Conclusie
In deze tutorial heb je de basis geleerd van het bouwen en implementeren van je eigen Bokeh-applicaties op je lokale machine. De tutorial laat zien hoe je alles wat je hebt geleerd samenbrengt om een praktische, leuke en interactieve app te bouwen die gebruikers enthousiast zal maken.
De beste manier om je programmeervaardigheden snel op te bouwen, is door na het leren van een concept of tool projecten zoals deze te bouwen. Deze praktische aanpak zorgt ervoor dat je een tool of vaardigheid goed begrijpt en aan potentiële werkgevers kunt laten zien wat je hebt gedaan.
Als je meer over Bokeh wilt leren, kun je dit boek lezen. Of beter nog: volg DataCamps cursus Interactive Visualization with Bokeh. Die gaat dieper in op Bokeh en hoe je geavanceerdere plots maakt. Je kunt nog verder gaan en leren hoe je je eigen Bokeh-webapps bouwt met realtime data.
