之前本來想想研究下 pandas+highchart 的解決方案,網(wǎng)上搜了下發(fā)現(xiàn)Bokeh 這個(gè)好東西,簡(jiǎn)單易用,天然就是支持python 和 pandas。而且很多場(chǎng)合都能用 (可以純python用,可以在jupyter里面用,可以和flask結(jié)合用,甚至有自己的bokeh server), 挺有意思的
官方網(wǎng)址: http://bokeh.pydata.org/en/latest/
Github: https://github.com/bokeh/bokeh
安裝
bokeh需要這幾個(gè)庫(kù):
- NumPy
- Jinja2
- Six
- Requests
- Tornado >= 4.0
- PyYaml
- DateUtil
最方便的方式還是在anacode 下面安裝, 用這個(gè)命令 conda install bokeh
簡(jiǎn)單的例子
from bokeh.plotting import figure, output_file, show
# prepare some data
x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]
# output to static HTML file
output_file("lines.html")
# create a new plot with a title and axis labels
p = figure(title="simple line example", x_axis_label='x', y_axis_label='y')
# add a line renderer with legend and line thickness
p.line(x, y, legend="Temp.", line_width=2)
# show the results
show(p)
Jupyter 中的使用
先導(dǎo)入下面的package. from bokeh.io import push_notebook, show, output_notebook, 再用 output_notebook() 設(shè)置輸出在jupyter notebook里面。( 一般情況是用output_file()輸出為html文件。) 這樣還不夠, 還需要在show()函數(shù)設(shè)置 notebook_hanlde 參數(shù)為True。
下面是個(gè)官方的例子:
from bokeh.io import push_notebook, show, output_notebook
from bokeh.layouts import row
from bokeh.plotting import figure
output_notebook()
opts = dict(plot_width=250, plot_height=250, min_border=0)
p1 = figure(**opts)
r1 = p1.circle([1,2,3], [4,5,6], size=20)
p2 = figure(**opts)
r2 = p2.circle([1,2,3], [4,5,6], size=20)
# get a handle to update the shown cell with
t = show(row(p1, p2), notebook_handle=True)
可以用push_notebook() 函數(shù)更新上面的渲染的圖像。在上面的代碼后建新的cell:
# this will update the left plot circle color with an explicit handle
r1.glyph.fill_color = "white"
push_notebook(handle=t)
運(yùn)行完后可以發(fā)現(xiàn)上面cell的輸出圖像變化了。
可以去github中example->howto->notebook_comms->basic Usage.ipynb 自己下載下來玩
chart 庫(kù) + pandas
如何方便的bokeh去快速渲染pandas的數(shù)據(jù)呢, 用chart, chart 庫(kù)的使用說明可以去http://bokeh.pydata.org/en/latest/docs/reference/charts.html 看
簡(jiǎn)而言之,chart 庫(kù)下面支持下面的幾種渲染類型:
- Area
- Bar
- BoxPlot
- Chord
- Donut
- HeatMap
- Horizon
- Line
- Scatter
- Step
- TimeSeries
一個(gè)例子:
from bokeh.charts import Histogram, output_file, show
from bokeh.layouts import row
from bokeh.sampledata.autompg import autompg as df
hist = Histogram(df, values='mpg', title="Auto MPG Histogram", plot_width=400)
hist2 = Histogram(df, values='mpg', label='cyl', color='cyl', legend='top_right',
title="MPG Histogram by Cylinder Count", plot_width=400)
output_file('hist.html')
show(row(hist, hist2))
bokeh的sample data里面自帶一些pandas 的dataframe的數(shù)據(jù)
mpl 庫(kù)
我之前其實(shí)已經(jīng)有用matplotlib.pyplot 庫(kù)去產(chǎn)生圖片了,mpl庫(kù)提供了一個(gè)快速替換的方法。
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from scipy import optimize
from bokeh import mpl
from bokeh.plotting import output_file, show
# Set the palette colors.
sns.set(palette="Set2")
# Build the sin wave
def sine_wave(n_x, obs_err_sd=1.5, tp_err_sd=.3):
x = np.linspace(0, (n_x - 1) / 2, n_x)
y = np.sin(x) + np.random.normal(0, obs_err_sd) + np.random.normal(0, tp_err_sd, n_x)
return y
sines = np.array([sine_wave(31) for _ in range(20)])
# Generate the Seaborn plot with "ci" bars.
ax = sns.tsplot(sines, err_style="ci_bars", interpolate=False)
xmin, xmax = ax.get_xlim()
x = np.linspace(xmin, xmax, sines.shape[1])
out, _ = optimize.leastsq(lambda p: sines.mean(0) - (np.sin(x / p[1]) + p[0]), (0, 2))
a, b = out
xx = np.linspace(xmin, xmax, 100)
plt.plot(xx, np.sin(xx / b) + a, c="#444444")
plt.title("Seaborn tsplot with CI in bokeh.")
output_file("seaborn_errorbar.html", title="seaborn_errorbar.py example")
#原來用plt.show()去產(chǎn)生圖片
#plt.show()
show(mpl.to_bokeh())
可以看到之前我用plt.show() 去產(chǎn)生圖片,現(xiàn)在可以直接用show(mpl.to_bokeh()) .只要改動(dòng)一行代碼就可以了!
Flask 中的使用
一個(gè)例子, python:
'''This example demonstrates embedding a standalone Bokeh document
into a simple Flask application, with a basic HTML web form.
To view the example, run:
python simple.py
in this directory, and navigate to:
http://localhost:5000
'''
from __future__ import print_function
import flask
from bokeh.embed import components
from bokeh.plotting import figure
from bokeh.resources import INLINE
from bokeh.util.string import encode_utf8
app = flask.Flask(__name__)
colors = {
'Black': '#000000',
'Red': '#FF0000',
'Green': '#00FF00',
'Blue': '#0000FF',
}
def getitem(obj, item, default):
if item not in obj:
return default
else:
return obj[item]
@app.route("/")
def polynomial():
""" Very simple embedding of a polynomial chart
"""
# Grab the inputs arguments from the URL
args = flask.request.args
# Get all the form arguments in the url with defaults
color = getitem(args, 'color', 'Black')
_from = int(getitem(args, '_from', 0))
to = int(getitem(args, 'to', 10))
# Create a polynomial line graph with those arguments
x = list(range(_from, to + 1))
fig = figure(title="Polynomial")
fig.line(x, [i ** 2 for i in x], color=colors[color], line_width=2)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
script, div = components(fig)
html = flask.render_template(
'embed.html',
plot_script=script,
plot_div=div,
js_resources=js_resources,
css_resources=css_resources,
color=color,
_from=_from,
to=to
)
return encode_utf8(html)
if __name__ == "__main__":
print(__doc__)
app.run()
embed.html:
<!doctype html>
<html lang="en">
<head>
<meta charset='utf-8' />
<meta http-equiv='content-type' content='text/html; charset=utf-8' />
<title>Embed Demo</title>
{{ js_resources|indent(4)|safe }}
{{ css_resources|indent(4)|safe }}
{{ plot_script|indent(4)|safe }}
</head>
<body>
<!-- A simple form for changing the graph -->
<p> Select your settings: </p>
<form name="color_button" method='GET'>
Color:
<select name="color">
<option {{ "selected" if color|indent(4)|safe == "Red" }} value="Red">Red</option>
<option {{ "selected" if color|indent(4)|safe == "Green" }} value="Green">Green</option>
<option {{ "selected" if color|indent(4)|safe == "Blue" }} value="Blue">Blue</option>
<option {{ "selected" if color|indent(4)|safe == "Black" }} value="Black">Black</option>
</select>
<br>
From:
<input type="text" name="_from" value="{{ _from }}">
<br>
To:
<input type="text" name="to" value="{{ to }}">
<br>
<button type="submit">Submit</button>
</form>
{{ plot_div|indent(4)|safe }}
<p> Demonstrates some very simple embedding into a webpage</p>
</body>
</html>