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:

Let’s start with a company that everyone would have known …

# 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
from pandas_datareader import data
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=data.DataReader(text.value, "yahoo", start, end)
    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!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s