Plotting in a web interface using Python

Recently I had a go at using different libraries to build  a web-app with a Python backend, and found out this pretty neat module bokeh. Here is an example of the interaction between pandas and bokeh on some financial data:

# Input stock ticks
stock = 'AAPL'


We need to specify the date range:

import datetime
start = datetime.datetime(2018,1,1)
end = datetime.date.today()


… then we import them using pandas DataReader, add a column of Date, find dates when the stock price increases and decreases during the day (for the candlestick plot) …

import pandas as pd
df = data.DataReader(stock, "yahoo", start, end)
df['Date'] = df.index.tolist()
inc = df.Close > df.Open
dec = df.Open > df.Close
w = 12*60*60*1000 # half day in ms


Here we import bokeh to pre-process and display graphs on the web interface.

from bokeh.io import curdoc
from bokeh.plotting import figure, show, output_file
from bokeh.layouts import widgetbox,column
from bokeh.models import Paragraph,TextInput,CustomJS,ColumnDataSource,FuncTickFormatter # pip install flexx


And a little bit of fun interactive functions on the plot:

TOOLS = "pan,wheel_zoom,box_zoom,reset,save"


Now, we define the properties of the candlestick chart p:

p = figure(plot_width=1000, title = "%s Candlestick"%stock)
label_dict = {}
for i, s in enumerate(pd.to_datetime(df["Date"])):
label_dict[i] = s.strftime('%b %d')
p.xaxis.formatter = FuncTickFormatter(code="""
var labels = %s;
return labels[tick];
""" % label_dict)
p.xaxis.major_label_orientation = pi/4
p.grid.grid_line_alpha=0.3

FuncTickFormatter sets the tick labels on the x-axis. We also rotate the x-tick labels to a more readable orientation (ie. $\pi/4$), and turn on the grid lines on the plot.

Here is the interesting bit: we turn the stock ticks into a ColumnDataSource (called source), and plot it on the chart object p. segment creates a line plot. In this scenario we want to plot both the day-high and day-low of the stock prices, hence indicate the first series with y0 and the second with y1. After than the candlestick chart can be represented by vertical bars vbar.

source = ColumnDataSource(df)

p.segment(x0='Date', y0='High', x1='Date', y1='Low', color="red",source=source)
p.vbar(df.Date[inc], w, df.Open[inc], df.Close[inc], fill_color="#D5E1DD", line_color="black")
p.vbar(df.Date[dec], w, df.Open[dec], df.Close[dec], fill_color="#F2583E", line_color="green")


What if we want to check out another company’s stock price? We ask the user to input the ticker through a message box TextInput, and display the option in a banner – which is a Paragraph object.

We have to define a function (here we call it update_message) to take the input attr, old, new from the TextInput object when the text inside has been changed (on_change).

Within the function update_message, we can directly change the properties of the chart p. Since p plots the data from source, if we want to change the data on the plot, we need to modify source as well.

def update_message(attr, old, new):
p.title.text = text.value
dfn['Date'] = dfn.index.tolist()
label_dict = {}
for i, s in enumerate(pd.to_datetime(dfn["Date"])):
label_dict[i] = s.strftime('%b %d')
p.xaxis.formatter = FuncTickFormatter(code="""
var labels = %s;
return labels[tick];
""" % label_dict)

for column in dfn.columns:
source.data[column] = dfn[column]

m = 'you have selected:(none)'
banner=Paragraph(text=m,width=200,height=100)
text = TextInput(value=stock,title='Enter stock ticker')
text.on_change('value',update_message)


To create a webpage:

curdoc().add_root(column(text,banner,p))
curdoc.title='Input'


From the command line, type:

bokeh serve filename.py


Then you’ll see something like:

Starting Bokeh server version x.x.x
Bokeh app running at: http://localhost:500x/filename
Starting Bokeh server with process id: xxxxx


Move to your browser, type the address found after ‘Bokeh app running at:’ to view your app. In the above case, I would have put in http://localhost:500x/filename in my address bar and look, it’s a simple I/O!