对于以Python做为技术栈的数据科学工做者,Jupyter
是不得不提的数据报告工具。可能对于R社区而言,鼎鼎大名的ggplot2
是常见的可视化框架,而你们对于Python,以及Jupyter
为核心的交互式报告的可个视化方案就并无那么熟悉。本文试图比较几个经常使用的解决方案,方便你们选择。javascript
数据工做者使用的图的类别,常见的就三类:GIS可视化、网络可视化和统计图。所以,大多数场景下,咱们并不想接触很是底层的基于点、线、面的命令,因此,选择一个好的封装的框架至关重要。html
固然,公认较好的封装是基于《The Grammar of Graphics (Statistics and Computing)》一书,R中的ggplot2
基本上就是一个很好的实现。咱们基本上能够像用「天然语言」(Natural Language)同样使用这些绘图命令。咱们姑且采用计算机科学领域的「陈述式」来表达这种绘图方式。前端
相反,有时候,如下情形时,咱们可能对于这种绘图命令可能并不在乎:java
这些状况下,显然,简单操做式并提供底层绘制命令的框架更让人愉快,与上面相似,咱们借用「命令式」描述这类框架。python
与传统的交付静态图标不一样,基于Web端的Jupter
的一大好处就是能够绘制交互的图标(最近的RNotebook
也有实现),所以,是否选择交互式,也是一个须要权衡的地方。git
交互图的优点:github
非交互图的优点:json
Jupyter
上大多数命令经过如下方式获取数据,而大多数绘图方式事实上只是经过Notebook内的代码在Notebook与内核交互后展现出输出结果。但ipywidgets
框架则能够实现Code Cell中的代码与Notebook中的前端控件(好比按钮等)绑定来进行操做内核,提供不一样的绘图结果,甚至某些绘图框架的每一个元素均可以直接和内核进行交互。前端框架
用这些框架,能够搭建更复杂的Notebook的可视化应用,但缺点是由于基于内核,因此在呈递、展现报告时若是使用离线文件时,这些交互就会无效。网络
matplotlib
最家喻户晓的绘图框架是matplotlib
,它提供了几乎全部python内静态绘图框架的底层命令。若是按照上面对可视化框架的分法,matplotlib
属于非交互式的的「命令式」做图框架。
## matplotlib代码示例 from pylab import * X = np.linspace(-np.pi, np.pi, 256,endpoint=True) C,S = np.cos(X), np.sin(X) plot(X,C) plot(X,S) show()
优势是相对较快,底层操做较多。缺点是语言繁琐,内置默认风格不够美观。
matplotlib
在jupyter中须要一些配置,能够展示更好的效果,详情参见这篇文章.
ggplot
和plotnine
值得一说,对于R迁移过来的人来讲,ggplot
和plotnine
简直是福音,基本克隆了ggplot2
全部语法。横向比较的话,plotnine
的效果更好。这两个绘图包的底层依旧是matplotlib
,所以,在引用时别忘了使用%matplotlib inline
语句。值得一说的是plotnine
也移植了ggplot2
中良好的配置语法和逻辑。
## plotnine示例 (ggplot(mtcars, aes('wt', 'mpg', color='factor(gear)')) + geom_point() + stat_smooth(method='lm') + facet_wrap('~gear'))
Seaborn
seaborn
准确上说属于matplotlib
的扩展包,在其上作了许多很是有用的封装,基本上能够知足大部分统计做图的需求,以matplotlib
+seaborn
基本能够知足大部分业务场景,语法也更加「陈述式」。
缺点是封装较高,基本上API不提供的图就彻底不可绘制,对于各种图的拼合也不适合;此外配置语句语法又回归「命令式」,相对复杂且不一致。
## seaborn示例 import seaborn as sns; sns.set(color_codes=True) iris = sns.load_dataset("iris") species = iris.pop("species") g = sns.clustermap(iris)
plotly
plotly
是跨平台JavaScript交互式绘图包,因为开发者的核心是javascript,因此整个语法相似于写json配置,语法特质也介于「陈述式」和「命令式」之间,无服务版本是免费的。
有点是学习成本不高,能够很快将语句移植到javascript版本;缺点是语言相对繁琐。
##plotly示例 import plotly.plotly as py import plotly.graph_objs as go # Add data month = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] high_2000 = [32.5, 37.6, 49.9, 53.0, 69.1, 75.4, 76.5, 76.6, 70.7, 60.6, 45.1, 29.3] low_2000 = [13.8, 22.3, 32.5, 37.2, 49.9, 56.1, 57.7, 58.3, 51.2, 42.8, 31.6, 15.9] high_2007 = [36.5, 26.6, 43.6, 52.3, 71.5, 81.4, 80.5, 82.2, 76.0, 67.3, 46.1, 35.0] low_2007 = [23.6, 14.0, 27.0, 36.8, 47.6, 57.7, 58.9, 61.2, 53.3, 48.5, 31.0, 23.6] high_2014 = [28.8, 28.5, 37.0, 56.8, 69.7, 79.7, 78.5, 77.8, 74.1, 62.6, 45.3, 39.9] low_2014 = [12.7, 14.3, 18.6, 35.5, 49.9, 58.0, 60.0, 58.6, 51.7, 45.2, 32.2, 29.1] # Create and style traces trace0 = go.Scatter( x = month, y = high_2014, name = 'High 2014', line = dict( color = ('rgb(205, 12, 24)'), width = 4) ) trace1 = go.Scatter( x = month, y = low_2014, name = 'Low 2014', line = dict( color = ('rgb(22, 96, 167)'), width = 4,) ) trace2 = go.Scatter( x = month, y = high_2007, name = 'High 2007', line = dict( color = ('rgb(205, 12, 24)'), width = 4, dash = 'dash') # dash options include 'dash', 'dot', and 'dashdot' ) trace3 = go.Scatter( x = month, y = low_2007, name = 'Low 2007', line = dict( color = ('rgb(22, 96, 167)'), width = 4, dash = 'dash') ) trace4 = go.Scatter( x = month, y = high_2000, name = 'High 2000', line = dict( color = ('rgb(205, 12, 24)'), width = 4, dash = 'dot') ) trace5 = go.Scatter( x = month, y = low_2000, name = 'Low 2000', line = dict( color = ('rgb(22, 96, 167)'), width = 4, dash = 'dot') ) data = [trace0, trace1, trace2, trace3, trace4, trace5] # Edit the layout layout = dict(title = 'Average High and Low Temperatures in New York', xaxis = dict(title = 'Month'), yaxis = dict(title = 'Temperature (degrees F)'), ) fig = dict(data=data, layout=layout) py.iplot(fig, filename='styled-line')
注意:此框架在jupyter中使用须要使用init_notebook_mode()加载JavaScript框架。
bokeh
bokeh
是pydata
维护的比较具备潜力的开源交互可视化框架。
值得一说的是,该框架同时提供底层语句和「陈述式」绘图命令。相对来讲语法也比较清楚,但其配置语句依旧有不少可视化框架的问题,就是与「陈述式」命令不符,没有合理的结构。此外,一些常见的交互效果都是以底层命令的方式使用的,所以若是要快速实现Dashboard或者做图时就显得较为不便了。
## Bokeh示例 import numpy as np import scipy.special from bokeh.layouts import gridplot from bokeh.plotting import figure, show, output_file p1 = figure(title="Normal Distribution (μ=0, σ=0.5)",tools="save", background_fill_color="#E8DDCB") mu, sigma = 0, 0.5 measured = np.random.normal(mu, sigma, 1000) hist, edges = np.histogram(measured, density=True, bins=50) x = np.linspace(-2, 2, 1000) pdf = 1/(sigma * np.sqrt(2*np.pi)) * np.exp(-(x-mu)**2 / (2*sigma**2)) cdf = (1+scipy.special.erf((x-mu)/np.sqrt(2*sigma**2)))/2 p1.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:], fill_color="#036564", line_color="#033649") p1.line(x, pdf, line_color="#D95B43", line_width=8, alpha=0.7, legend="PDF") p1.line(x, cdf, line_color="white", line_width=2, alpha=0.7, legend="CDF") p1.legend.location = "center_right" p1.legend.background_fill_color = "darkgrey" p1.xaxis.axis_label = 'x' p1.yaxis.axis_label = 'Pr(x)' p2 = figure(title="Log Normal Distribution (μ=0, σ=0.5)", tools="save", background_fill_color="#E8DDCB") mu, sigma = 0, 0.5 measured = np.random.lognormal(mu, sigma, 1000) hist, edges = np.histogram(measured, density=True, bins=50) x = np.linspace(0.0001, 8.0, 1000) pdf = 1/(x* sigma * np.sqrt(2*np.pi)) * np.exp(-(np.log(x)-mu)**2 / (2*sigma**2)) cdf = (1+scipy.special.erf((np.log(x)-mu)/(np.sqrt(2)*sigma)))/2 p2.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:], fill_color="#036564", line_color="#033649") p2.line(x, pdf, line_color="#D95B43", line_width=8, alpha=0.7, legend="PDF") p2.line(x, cdf, line_color="white", line_width=2, alpha=0.7, legend="CDF") p2.legend.location = "center_right" p2.legend.background_fill_color = "darkgrey" p2.xaxis.axis_label = 'x' p2.yaxis.axis_label = 'Pr(x)' p3 = figure(title="Gamma Distribution (k=1, θ=2)", tools="save", background_fill_color="#E8DDCB") k, theta = 1.0, 2.0 measured = np.random.gamma(k, theta, 1000) hist, edges = np.histogram(measured, density=True, bins=50) x = np.linspace(0.0001, 20.0, 1000) pdf = x**(k-1) * np.exp(-x/theta) / (theta**k * scipy.special.gamma(k)) cdf = scipy.special.gammainc(k, x/theta) / scipy.special.gamma(k) p3.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:], fill_color="#036564", line_color="#033649") p3.line(x, pdf, line_color="#D95B43", line_width=8, alpha=0.7, legend="PDF") p3.line(x, cdf, line_color="white", line_width=2, alpha=0.7, legend="CDF") p3.legend.location = "center_right" p3.legend.background_fill_color = "darkgrey" p3.xaxis.axis_label = 'x' p3.yaxis.axis_label = 'Pr(x)' p4 = figure(title="Weibull Distribution (λ=1, k=1.25)", tools="save", background_fill_color="#E8DDCB") lam, k = 1, 1.25 measured = lam*(-np.log(np.random.uniform(0, 1, 1000)))**(1/k) hist, edges = np.histogram(measured, density=True, bins=50) x = np.linspace(0.0001, 8, 1000) pdf = (k/lam)*(x/lam)**(k-1) * np.exp(-(x/lam)**k) cdf = 1 - np.exp(-(x/lam)**k) p4.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:], fill_color="#036564", line_color="#033649") p4.line(x, pdf, line_color="#D95B43", line_width=8, alpha=0.7, legend="PDF") p4.line(x, cdf, line_color="white", line_width=2, alpha=0.7, legend="CDF") p4.legend.location = "center_right" p4.legend.background_fill_color = "darkgrey" p4.xaxis.axis_label = 'x' p4.yaxis.axis_label = 'Pr(x)' output_file('histogram.html', title="histogram.py example") show(gridplot(p1,p2,p3,p4, ncols=2, plot_width=400, plot_height=400, toolbar_location=None))
bqplot
bqplot
是基于ipywidgets
和d3.js
组合发展的内核交互式的可视化框架。语法上采用了和matplotlib
大体一致的语法已经相对封装较高的「陈述式语法」。优势是直接和内核交互,可使用大量控件来实现更多的图像处理,缺点也是直接的,离线文档则不会显示任何图案、控件也都失效。
## bqplot示例 import numpy as np from IPython.display import display from bqplot import ( OrdinalScale, LinearScale, Bars, Lines, Axis, Figure ) size = 20 np.random.seed(0) x_data = np.arange(size) x_ord = OrdinalScale() y_sc = LinearScale() bar = Bars(x=x_data, y=np.random.randn(2, size), scales={'x': x_ord, 'y': y_sc}, type='stacked') line = Lines(x=x_data, y=np.random.randn(size), scales={'x': x_ord, 'y': y_sc}, stroke_width=3, colors=['red'], display_legend=True, labels=['Line chart']) ax_x = Axis(scale=x_ord, grid_lines='solid', label='X') ax_y = Axis(scale=y_sc, orientation='vertical', tick_format='0.2f', grid_lines='solid', label='Y') Figure(marks=[bar, line], axes=[ax_x, ax_y], title='API Example', legend_location='bottom-right')
除了统计做图,网络可视化和GIS可视化也是很经常使用的,在此只作一个简单的罗列:
GIS类:
gmap
:交互,使用google maps接口ipyleaflet
:交互,使用leaflet接口网络类:
networkx
:底层为matplotlib
plotly
底层实现 | 交互方式 | 语法 | 语言结构 | 备注 | 推荐程度 | |
---|---|---|---|---|---|---|
matplotlib |
- | 无 | 命令式 | 底层语言 | 能够实现复杂底层操做 | ★★★ |
gglot |
matplotlib |
无 | 陈述式 | 类ggplot2 |
建议选择plotnine |
★★ |
plotnine |
matplotlib |
无 | 陈述式 | 类ggplot2 |
彻底移植ggplot2 |
★★★★★ |
seaborn |
matplotlib |
无 | 陈述式 | 高级语言 | 有不少有用的统计图类的封装;但不适合作图拼装 | ★★★★★ |
plotly |
plotly.js |
前端交互 | 介于命令式和陈述式之间 | 相似JavaScript | 语法相似于json配置 | ★★★★ |
bokeh |
- | 前端交互 | 命令、陈述式 | 同时有底层语言和高级语言 | 社区具备潜力 | ★★★ |
bqplot |
d3.js |
内核交互 | 命令、陈述式 | 有相似matplotlib 底层语言,已经封装好的高级语言 |
内核交互 | ★★★★ |