之前本来想想研究下 pandas+highchart 的解决方案,网上搜了下发现Bokeh 这个好东西,简单易用,天然就是支持python 和 pandas。而且很多场合都能用 (可以纯python用,可以在jupyter里面用,可以和flask结合用,甚至有自己的bokeh server), 挺有意思的
官方网址: http://bokeh.pydata.org/en/latest/
Github: https://github.com/bokeh/bokeh
安装
bokeh需要这几个库:
- NumPy
- Jinja2
- Six
- Requests
- Tornado >= 4.0
- PyYaml
- DateUtil
最方便的方式还是在anacode 下面安装, 用这个命令 conda install bokeh
简单的例子
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 中的使用
先导入下面的package. from bokeh.io import push_notebook, show, output_notebook
, 再用 output_notebook()
设置输出在jupyter notebook里面。( 一般情况是用output_file()
输出为html文件。) 这样还不够, 还需要在show()
函数设置 notebook_hanlde
参数为True
。
下面是个官方的例子:
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()
函数更新上面的渲染的图像。在上面的代码后建新的cell:
# this will update the left plot circle color with an explicit handle
r1.glyph.fill_color = "white"
push_notebook(handle=t)
运行完后可以发现上面cell的输出图像变化了。
可以去github中example->howto->notebook_comms->basic Usage.ipynb 自己下载下来玩
chart 库 + pandas
如何方便的bokeh去快速渲染pandas的数据呢, 用chart, chart 库的使用说明可以去http://bokeh.pydata.org/en/latest/docs/reference/charts.html 看
简而言之,chart 库下面支持下面的几种渲染类型:
- Area
- Bar
- BoxPlot
- Chord
- Donut
- HeatMap
- Horizon
- Line
- Scatter
- Step
- TimeSeries
一个例子:
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的数据
mpl 库
我之前其实已经有用matplotlib.pyplot 库去产生图片了,mpl库提供了一个快速替换的方法。
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()去产生图片
#plt.show()
show(mpl.to_bokeh())
可以看到之前我用plt.show()
去产生图片,现在可以直接用show(mpl.to_bokeh())
.只要改动一行代码就可以了!
Flask 中的使用
一个例子, 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>