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. ), 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!