打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Jupyter 常见可视化框架选择

还有一个本文没提到的库,pyecharts,大家也可以尝试一下。


作者:三次方根

来源:https://segmentfault.com/a/1190000011831228

对于以Python作为技术栈的数据科学工作者, Jupyter是不得不提的数据报告工具。可能对于R社区而言,鼎鼎大名的 ggplot2是常见的可视化框架,而大家对于Python,以及 Jupyter为核心的交互式报告的可个视化方案就并没有那么熟悉。本文试图比较几个常用的解决方案,方便大家选择。

选择标准

称述式还是命令式

数据工作者使用的图的类别,常见的就三类:GIS可视化、网络可视化和统计图。因此,大多数场景下,我们并不想接触非常底层的基于点、线、面的命令,所以,选择一个好的封装的框架相当重要。

当然,公认较好的封装是基于《The Grammar of Graphics (Statistics and Computing)》一书,R中的 ggplot2基本上就是一个很好的实现。我们基本上可以像用「自然语言」(Natural Language)一样使用这些绘图命令。我们姑且采用计算机科学领域的「陈述式」来表达这种绘图方式。

相反,有时候,以下情形时,我们可能对于这种绘图命令可能并不在意:

  1. 出图相当简单,要求绘制速度,一般大的框架较重(当然只是相对而言);

  2. 想要对细节做非常详尽的微调,一般大框架在微调方面会相对复杂或者退缩成一句句命令

  3. 是统计作图可视化的创新者,想要尝试做出新的可视化实践。

这些情况下,显然,简单操作式并提供底层绘制命令的框架更让人愉快,与上面类似,我们借用「命令式」描述这类框架。

是否交互

与传统的交付静态图标不同,基于Web端的 Jupter的一大好处就是可以绘制交互的图标(最近的 RNotebook也有实现),因此,是否选择交互式,也是一个需要权衡的地方。

交互图的优势:

  1. 可以提供更多的数据维度和信息;

  2. 用户端可以做更多诸如放大、选取、转存的操作;

  3. 可以交付BI工程师相应的JavaScript代码用以工程化;

  4. 效果上比较炫酷,考虑到报告接受者的特征可以选择。

非交互图的优势:

  1. 报告文件直接导出成静态文件时相对问题,不会因为转换而损失信息;

  2. 图片可以与报告分离,必要时作为其他工作的成果;

  3. 不需要在运行Notebook时花很多世界载入各类前端框架。

是非内核交互

Jupyter上大多数命令通过以下方式获取数据,而大多数绘图方式事实上只是通过Notebook内的代码在Notebook与内核交互后展示出输出结果。但 ipywidgets框架则可以实现Code Cell中的代码与Notebook中的前端控件(比如按钮等)绑定来进行操作内核,提供不同的绘图结果,甚至某些绘图框架的每个元素都可以直接和内核进行交互。

用这些框架,可以搭建更复杂的Notebook的可视化应用,但缺点是因为基于内核,所以在呈递、展示报告时如果使用离线文件时,这些交互就会无效。

框架罗列

matplotlib

最家喻户晓的绘图框架是 matplotlib,它提供了几乎所有python内静态绘图框架的底层命令。如果按照上面对可视化框架的分法, matplotlib属于非交互式的的「命令式」作图框架。

  1. ## matplotlib代码示例

  2. from pylab import *

  3. X = np.linspace(-np.pi, np.pi, 256,endpoint=True)

  4. C,S = np.cos(X), np.sin(X)

  5. plot(X,C)

  6. plot(X,S)

  7. show()

优点是相对较快,底层操作较多。缺点是语言繁琐,内置默认风格不够美观。

matplotlib在jupyter中需要一些配置,可以展现更好的效果,详情参见这篇文章.

ggplot和 plotnine

值得一说,对于R迁移过来的人来说, ggplot和 plotnine简直是福音,基本克隆了 ggplot2所有语法。横向比较的话, plotnine的效果更好。这两个绘图包的底层依旧是 matplotlib,因此,在引用时别忘了使用 %matplotlib inline语句。值得一说的是 plotnine也移植了 ggplot2中良好的配置语法和逻辑。

  1. ## plotnine示例

  2. (ggplot(mtcars, aes('wt', 'mpg', color='factor(gear)'))

  3. + geom_point()

  4. + stat_smooth(method='lm')

  5. + facet_wrap('~gear'))

Seaborn

seaborn准确上说属于 matplotlib的扩展包,在其上做了许多非常有用的封装,基本上可以满足大部分统计作图的需求,以 matplotlibseaborn基本可以满足大部分业务场景,语法也更加「陈述式」。

缺点是封装较高,基本上API不提供的图就完全不可绘制,对于各类图的拼合也不适合;此外配置语句语法又回归「命令式」,相对复杂且不一致。

  1. ## seaborn示例

  2. import seaborn as sns; sns.set(color_codes=True)

  3. iris = sns.load_dataset('iris')

  4. species = iris.pop('species')

  5. g = sns.clustermap(iris)

plotly

plotly是跨平台JavaScript交互式绘图包,由于开发者的核心是javascript,所以整个语法类似于写json配置,语法特质也介于「陈述式」和「命令式」之间,无服务版本是免费的。

有点是学习成本不高,可以很快将语句移植到javascript版本;缺点是语言相对繁琐。

  1. ##plotly示例

  2. import plotly.plotly as py

  3. import plotly.graph_objs as go

  4. # Add data

  5. month = ['January', 'February', 'March', 'April', 'May', 'June', 'July',

  6.         'August', 'September', 'October', 'November', 'December']

  7. 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]

  8. 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]

  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]

  10. 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]

  11. 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]

  12. 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]

  13. # Create and style traces

  14. trace0 = go.Scatter(

  15.    x = month,

  16.    y = high_2014,

  17.    name = 'High 2014',

  18.    line = dict(

  19.        color = ('rgb(205, 12, 24)'),

  20.        width = 4)

  21. )

  22. trace1 = go.Scatter(

  23.    x = month,

  24.    y = low_2014,

  25.    name = 'Low 2014',

  26.    line = dict(

  27.        color = ('rgb(22, 96, 167)'),

  28.        width = 4,)

  29. )

  30. trace2 = go.Scatter(

  31.    x = month,

  32.    y = high_2007,

  33.    name = 'High 2007',

  34.    line = dict(

  35.        color = ('rgb(205, 12, 24)'),

  36.        width = 4,

  37.        dash = 'dash') # dash options include 'dash', 'dot', and 'dashdot'

  38. )

  39. trace3 = go.Scatter(

  40.    x = month,

  41.    y = low_2007,

  42.    name = 'Low 2007',

  43.    line = dict(

  44.        color = ('rgb(22, 96, 167)'),

  45.        width = 4,

  46.        dash = 'dash')

  47. )

  48. trace4 = go.Scatter(

  49.    x = month,

  50.    y = high_2000,

  51.    name = 'High 2000',

  52.    line = dict(

  53.        color = ('rgb(205, 12, 24)'),

  54.        width = 4,

  55.        dash = 'dot')

  56. )

  57. trace5 = go.Scatter(

  58.    x = month,

  59.    y = low_2000,

  60.    name = 'Low 2000',

  61.    line = dict(

  62.        color = ('rgb(22, 96, 167)'),

  63.        width = 4,

  64.        dash = 'dot')

  65. )

  66. data = [trace0, trace1, trace2, trace3, trace4, trace5]

  67. # Edit the layout

  68. layout = dict(title = 'Average High and Low Temperatures in New York',

  69.              xaxis = dict(title = 'Month'),

  70.              yaxis = dict(title = 'Temperature (degrees F)'),

  71.              )

  72. fig = dict(data=data, layout=layout)

  73. py.iplot(fig, filename='styled-line')

注意:此框架在jupyter中使用需要使用initnotebookmode()加载JavaScript框架。

bokeh

bokeh是 pydata维护的比较具有潜力的开源交互可视化框架。

值得一说的是,该框架同时提供底层语句和「陈述式」绘图命令。相对来说语法也比较清楚,但其配置语句依旧有很多可视化框架的问题,就是与「陈述式」命令不符,没有合理的结构。此外,一些常见的交互效果都是以底层命令的方式使用的,因此如果要快速实现Dashboard或者作图时就显得较为不便了。

  1. ## Bokeh示例

  2. import numpy as np

  3. import scipy.special

  4. from bokeh.layouts import gridplot

  5. from bokeh.plotting import figure, show, output_file

  6. p1 = figure(title='Normal Distribution (μ=0, σ=0.5)',tools='save',

  7.            background_fill_color='#E8DDCB')

  8. mu, sigma = 0, 0.5

  9. measured = np.random.normal(mu, sigma, 1000)

  10. hist, edges = np.histogram(measured, density=True, bins=50)

  11. x = np.linspace(-2, 2, 1000)

  12. pdf = 1/(sigma * np.sqrt(2*np.pi)) * np.exp(-(x-mu)**2 / (2*sigma**2))

  13. cdf = (1+scipy.special.erf((x-mu)/np.sqrt(2*sigma**2)))/2

  14. p1.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:],

  15.        fill_color='#036564', line_color='#033649')

  16. p1.line(x, pdf, line_color='#D95B43', line_width=8, alpha=0.7, legend='PDF')

  17. p1.line(x, cdf, line_color='white', line_width=2, alpha=0.7, legend='CDF')

  18. p1.legend.location = 'center_right'

  19. p1.legend.background_fill_color = 'darkgrey'

  20. p1.xaxis.axis_label = 'x'

  21. p1.yaxis.axis_label = 'Pr(x)'

  22. p2 = figure(title='Log Normal Distribution (μ=0, σ=0.5)', tools='save',

  23.            background_fill_color='#E8DDCB')

  24. mu, sigma = 0, 0.5

  25. measured = np.random.lognormal(mu, sigma, 1000)

  26. hist, edges = np.histogram(measured, density=True, bins=50)

  27. x = np.linspace(0.0001, 8.0, 1000)

  28. pdf = 1/(x* sigma * np.sqrt(2*np.pi)) * np.exp(-(np.log(x)-mu)**2 / (2*sigma**2))

  29. cdf = (1+scipy.special.erf((np.log(x)-mu)/(np.sqrt(2)*sigma)))/2

  30. p2.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:],

  31.        fill_color='#036564', line_color='#033649')

  32. p2.line(x, pdf, line_color='#D95B43', line_width=8, alpha=0.7, legend='PDF')

  33. p2.line(x, cdf, line_color='white', line_width=2, alpha=0.7, legend='CDF')

  34. p2.legend.location = 'center_right'

  35. p2.legend.background_fill_color = 'darkgrey'

  36. p2.xaxis.axis_label = 'x'

  37. p2.yaxis.axis_label = 'Pr(x)'

  38. p3 = figure(title='Gamma Distribution (k=1, θ=2)', tools='save',

  39.            background_fill_color='#E8DDCB')

  40. k, theta = 1.0, 2.0

  41. measured = np.random.gamma(k, theta, 1000)

  42. hist, edges = np.histogram(measured, density=True, bins=50)

  43. x = np.linspace(0.0001, 20.0, 1000)

  44. pdf = x**(k-1) * np.exp(-x/theta) / (theta**k * scipy.special.gamma(k))

  45. cdf = scipy.special.gammainc(k, x/theta) / scipy.special.gamma(k)

  46. p3.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:],

  47.        fill_color='#036564', line_color='#033649')

  48. p3.line(x, pdf, line_color='#D95B43', line_width=8, alpha=0.7, legend='PDF')

  49. p3.line(x, cdf, line_color='white', line_width=2, alpha=0.7, legend='CDF')

  50. p3.legend.location = 'center_right'

  51. p3.legend.background_fill_color = 'darkgrey'

  52. p3.xaxis.axis_label = 'x'

  53. p3.yaxis.axis_label = 'Pr(x)'

  54. p4 = figure(title='Weibull Distribution (λ=1, k=1.25)', tools='save',

  55.            background_fill_color='#E8DDCB')

  56. lam, k = 1, 1.25

  57. measured = lam*(-np.log(np.random.uniform(0, 1, 1000)))**(1/k)

  58. hist, edges = np.histogram(measured, density=True, bins=50)

  59. x = np.linspace(0.0001, 8, 1000)

  60. pdf = (k/lam)*(x/lam)**(k-1) * np.exp(-(x/lam)**k)

  61. cdf = 1 - np.exp(-(x/lam)**k)

  62. p4.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:],

  63.       fill_color='#036564', line_color='#033649')

  64. p4.line(x, pdf, line_color='#D95B43', line_width=8, alpha=0.7, legend='PDF')

  65. p4.line(x, cdf, line_color='white', line_width=2, alpha=0.7, legend='CDF')

  66. p4.legend.location = 'center_right'

  67. p4.legend.background_fill_color = 'darkgrey'

  68. p4.xaxis.axis_label = 'x'

  69. p4.yaxis.axis_label = 'Pr(x)'

  70. output_file('histogram.html', title='histogram.py example')

  71. show(gridplot(p1,p2,p3,p4, ncols=2, plot_width=400, plot_height=400, toolbar_location=None))

bqplot

bqplot是基于 ipywidgets和 d3.js组合发展的内核交互式的可视化框架。语法上采用了和 matplotlib大致一致的语法已经相对封装较高的「陈述式语法」。优点是直接和内核交互,可以使用大量控件来实现更多的图像处理,缺点也是直接的,离线文档则不会显示任何图案、控件也都失效。

  1. ## bqplot示例

  2. import numpy as np

  3. from IPython.display import display

  4. from bqplot import (

  5.    OrdinalScale, LinearScale, Bars, Lines, Axis, Figure

  6. )

  7. size = 20

  8. np.random.seed(0)

  9. x_data = np.arange(size)

  10. x_ord = OrdinalScale()

  11. y_sc = LinearScale()

  12. bar = Bars(x=x_data, y=np.random.randn(2, size), scales={'x': x_ord, 'y':

  13. y_sc}, type='stacked')

  14. line = Lines(x=x_data, y=np.random.randn(size), scales={'x': x_ord, 'y': y_sc},

  15.             stroke_width=3, colors=['red'], display_legend=True, labels=['Line chart'])

  16. ax_x = Axis(scale=x_ord, grid_lines='solid', label='X')

  17. ax_y = Axis(scale=y_sc, orientation='vertical', tick_format='0.2f',

  18.            grid_lines='solid', label='Y')

  19. Figure(marks=[bar, line], axes=[ax_x, ax_y], title='API Example',

  20.       legend_location='bottom-right')

其他特殊需求的作图

除了统计作图,网络可视化和GIS可视化也是很常用的,在此只做一个简单的罗列:

GIS类:

  • gmap:交互,使用google maps接口

  • ipyleaflet:交互,使用leaflet接口

网络类:

  • networkx:底层为 matplotlib

  • plotly

总结


底层实现交互方式语法语言结构备注推荐程度
matplotlib-命令式底层语言可以实现复杂底层操作★★★
gglotmatplotlib陈述式类 ggplot2建议选择 plotnine★★
plotninematplotlib陈述式类 ggplot2完全移植 ggplot2★★★★★
seabornmatplotlib陈述式高级语言有很多有用的统计图类的封装;但不适合做图拼装★★★★★
plotlyplotly.js前端交互介于命令式和陈述式之间类似JavaScript语法类似于json配置★★★★
bokeh-前端交互命令、陈述式同时有底层语言和高级语言社区具有潜力★★★
bqplotd3.js内核交互命令、陈述式有类似 matplotlib底层语言,已经封装好的高级语言内核交互★★★★

题图:pexels,CC0 授权。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
matplotlib-绘制精美的图表
如何使用Matplotlib制作出动画??
要想成为一名月入几万的数据分析师,绘制图表是必会的!实例教程
pandas 读写sql数据库和matplotlib模块
干货|教你一文掌握:Matplotlib+Seaborn可视化
一个交互式可视化Python库——Bokeh
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服