Erlo

在Python中使用ggplot2风格及语法: plotnine与ggplot|可视化系列05

2020-11-19 18:30:10 发布   486 浏览  
页面报错/反馈
收藏 点赞

Leland Wilkinson所沉淀的The Grammar of Graphics (简称GG)代表着一种可视化语句风格,对可视化领域有着深远的影响。Hadley Wickham编写的ggplot2 在R语言中声名远扬,使得统计数据可视化能力成为R语言的一大优势(这位大神还写了dplyr、tidyr等影响深远的R包)。

Wickham有如下观点:

一张统计图形是从数据到几何对象(geometric object, 缩写为geom, 包括点、线、条形等)的图形属性(aesthetic attributes, 缩写为aes, 包括形状、颜色、大小等)的一个映射。此外, 图形中还可能包含数据的统计变换(statistical transformation, 缩写为stats), 最后绘制在某个特定的坐标系(coordinate system, 缩写为coord)中, 而分面(facet)则可以用来生成数据中不同子集的图形。

将其简化就是:数据+图形映射+坐标系=>出图。

返璞归真幻化万千可视化表达 — 绝云 & 御术[1] 

如果说ggplot2库的语句写法是以上思想的典范之作,在Python里ggplot库便是实践的先行者(项目叫ggpy,开发的库名是ggplot),但因为不达预期,2016年之后,几位大佬在补充完善ggplot库的过程中选择了另起炉灶,写了plotnine库,该库诞生后备受关注。plotnine在处理统计操作方面用了statsmodels、scipy等库,依赖库挺多,建议用pip安装时用清华镜像加速,数了一下一共装了12个库。

本文用这两个库实践日常可视化的需求,包括绘制基础图形和分面主题等,通过对比使用plotnine和ggplot两个库,去理解图形语法的理念。

绘图基础

因为plotnine和ggplot两个库都对标R的ggplot2库,他们大部分语句写法相同,本文不使用from plotnine import * 的写法,而是采用加前缀的写法import plotnine as pn,通过pn.ggplot()gg.ggplot()的写法区分和对比两个库。plotnine的绘图框架如下:

import plotnine as pnimport ggplot as gg #两个库对比着用,所以就不写 from ggplot import * 了pn.ggplot(df,pn.aes(x='x',y='y'))+ pn.geom_point() #绘制一个基础散点图

基础散点图绘制效果

绘图效果如上,绘制了反映x-y关系的散点图,把第三句的pn改为gg就是ggplot库的实践了,具体来看下第三句,pn.ggplot(df,pn.aes(x='x',y='y'))新建一个ggplot对象(可以理解为画布)并绑定数据集df,其中的pn.aes(x='x',y='y')表示将df['x']列对应x坐标轴,df['y']对应y轴,再通过pn.geom_point()映射x-y数据为散点图。+号连接表示将+号后面的操作或条件应用到+号前的对象上,同时生成的新对象可以继续应用+,这几个库的语句写起来就是有很多+号。

继续细看绘图的语句,aes()用于描述数据列和图形元素的映射关系,所谓的映射即为数据集中的一对对数据关联到对应的图形属性上,例如散点图就有点的形状、大小、颜色、透明度等,aes()可以放在pn.ggplot()里也可以具体写在geom_xx()里,区别是ggplot()对象里的aes具有全局优先级,在画多个图时体现。geom_xx系列表示抽象出来的一些基础图,根据点、线、面分类如下:

plotnine常用绘图类型[2]

pn.geom_line绘制折线图,默认的x轴需要是数值型变量,分类变量需要设置group参数,group = 1

df=pd.DataFrame({'x':['Mon.','Tue.','Wed.','Thu.','Fri.'],                 'y':[76,37,90,60,50],                 'z':[37,46,53,81,60],                 'h':[2,5,1,3,3],                 'k':['a','a','c','d','c']})pn.ggplot(df,pn.aes(x='x', y='y'))+pn.geom_line(group = 1,color='#1EAFAE')          #折线图,x是分类变量,需设置group参数

绘制阶梯图的geom_step也同理,参数和geom_line一脉相承。

而在绘制柱状图时,对于x时分类变量的情况且设置y参数时,用pn.geom_bar()需要设置geom_bar的参数为 stat = "identity",否则会报错PlotnineError,另一个plotnine中绘制柱状图的pn.geom_col()则不需要额外设置stat参数。

pn.geom_bar()的绘图效果如下:

pn.ggplot(df,pn.aes(x='x',y='y'))+ pn.geom_bar(stat = "identity",fill='#1EAFAE')

geom_bar的stat参数表示本图层数据使用的统计变换(statistical transformation),geom_bar默认的是stat=count。表示的是y值是x变量的计数,因此aes(x='x',y='y')的情况下需要设置stat = "identity"。在plotnine中,pn.geom_col()更像传统意义的柱状图绘制方法,

给柱状图增加文本标签和图表标题:

pn.ggplot(df,pn.aes(x='x',y='y'))+ pn.geom_bar(stat = "identity",fill='#1EAFAE')          + pn.geom_text(pn.aes(label='y'),va='bottom') +pn.ggtitle('每天骑行时间(mins)')+th

绘制条形图,不是通过改pn.geom_bar里面的参数实现或者简单替换X-Y的值,而是用到pn.coord_flip()进行坐标变换。体现了图形语法理念的几何对象、统计变换、坐标系变换及分面的独立性和图层叠加特性。

#换一个坐标系映射 变成条形图pn.ggplot(df,pn.aes(x='x', y='y'))+ pn.geom_bar(stat = "identity",fill='#1EAFAE')   + pn.geom_text(pn.aes(label='y'),ha='left')+ pn.coord_flip()

值得一提的是,目前(202011)plotnine没有极坐标,不能通过坐标转换画出饼图(plotnine/issues/10[3])。

而ggplot库是可以进行极坐标变换的,用gg.coord_polar()

gg.ggplot(df,gg.aes(x='x', y='y'))+gg.geom_bar(    stat = "identity",fill='#1EAFAE')+ gg.coord_polar()

ggplot画饼

复合图表

上个部分通过一个简单数据集df绘制了折线、柱状图等基础图表,热身完毕后进一步实践多图叠加、分面等情况。plotnine挺重视图层概念的,+号既可以加图形细节和限制,也可以加另一个图形,例如要绘制一个柱状图+折线图语句如下:

pn.ggplot(df,pn.aes(x='x',y='y'))    + pn.geom_bar(stat = "identity",fill='#1EAFAE')    + pn.geom_line(pn.aes(x='x',y='z'),group = 1,color='#ba5c25')

从图层角度看就是在geom_bar()绘制了柱状图的基础上用geom_line()把折线图叠加上去。ggplot的叠加也如此,通过+号连接多个geom几何对象就行。

为了更好体现plotnine处理表格数据的优势,后面通过plotnine内置的钻石数据集(Diamonds)[4]进行绘图实践。

Diamonds数据集在各种R语言数据分析文章里有很高的出镜率。数据集有10列,csv文件约2.64MB,包含了近54000颗钻石的价格及其他属性,大家普遍用来做探索性数据分析和可视化案例。通过from plotnine.data import diamonds导入该钻石数据集。

不同切割质量与价格的箱线图:

pn.ggplot(dia,pn.aes(x='cut', y='price'))+ pn.geom_boxplot()

绘制克拉数和价格散点图并进行线性拟合,用不同颜色区分切割质量:

pn.ggplot(dia,pn.aes(x='carat',y='price',                     color='cut'))+ pn.geom_point()+pn.stat_smooth()

pn.facet_wrap('k')表示根据k列的变量进行分面。

在图表的输出方面,save_as_pdf_pages接口可以将绘制的图表输出为pdf文件。

p1=pn.ggplot(df,pn.aes(x='x', y='y'))    +pn.geom_col(fill='#1EAFAE')+pn.facet_wrap('k')pn.save_as_pdf_pages([p1],'保存图片的文件名.pdf')

进一步深入

plotnine包含了多种配色和主题,支持自定义全局修改主题和样式,和matplotlib一样提供了各个图元个性化设置的接口。

目前plotnine内置了14种主题,通过pn.theme_seaborn() 让图表使用seaborn的主题色, pn.theme_xkcd()绘制出漫画效果的图表。

pn.ggplot(df,pn.aes(x='x',y='y'))+pn.geom_line(group=1)+pn.theme_xkcd() #手绘效果

而应用pn.theme(axis_text,panel_grid_minor)可以自定义主题,各种图元都是能找到参数进行设置的,自定义的自由度很高。

pn.ggplot(df,pn.aes(x='x', y='y'))+pn.geom_line(group = 1) + pn.geom_text(pn.aes(label='y'),va='bottom')+ pn.theme(    axis_line_x=pn.element_line(color='red'),    axis_line_y=pn.element_line(color='blue'),    axis_text=pn.element_text(margin={'t': 5, 'r': 5}),    panel_grid_major_x=pn.element_line(linetype='dashed'),    axis_text_x=pn.element_text(color='black'),    axis_text_y=pn.element_text(color='purple'),    panel_grid_minor=pn.element_line(alpha=.25),    panel_grid_minor_x=pn.element_line(color='red'))

plotnine和ggplot这两个库都内置了一些数据集,例如可以通过以下语句导入钻石数据集:

import plotnine.data as pnddf=pnd.diamonds#ggplot中:import ggplot.datasets as gdsdf1=gds.diamonds

pnd.__all__语句可以列出plotnine能直接调用的数据集:

__all__ = ['diamonds', 'economics', 'economics_long', 'midwest', 'mpg', 'msleep', 'presidential', 'seals', 'txhousing', 'luv_colours', 'faithful', 'faithfuld', 'huron', 'meat', 'mtcars', 'pageviews']

ggplot提供的数据集如下:

chopsticks, diamonds, mtcars, meat, pageviews, pigeons, movies, mpg, salmon, load_world

除了world世界地图数据是需要从github下载之外,其他数据集都存在本地,site-packagesggplotdatasets目录下,也都是csv文件。

绘制地图:

pn.geom_map(lakes, fill=water_color, color=None)

动画支持,类似matplotlib的调用方式:

plots = (plot(k) for k in np.linspace(kmin, kmax, num_frames))pn.PlotnineAnimation(plots, interval=100, repeat_delay=500)

总结

plotnine是一个践行The Grammar of Graphics理论的Python可视化库,plotnine和ggplot[5]这两个库按照R语言里的可视化库ggplot2为范本打造,因此熟悉R语言绘图的人会觉得其写法非常熟悉,ggplot库不完善且不再更新,plotnine也尚未完善,在坐标转换和图形类型方面有所缺漏,但基础的东西都有了,各类接口向ggplot2看齐,有geom_map绘制地图,有 PlotnineAnimation 可以绘制多帧的动画。

在使用plotnine和ggplot的过程中,如果有需求不会实现或遇到报错,用plotnine作为关键词搜不到解决方案时,可以使用ggplot2关键词,看看成熟的R库ggplot2是如何实现相关功能的,然后尝试这一写法,大概率能实现。目前plotnine是0.7版,未来可期。

有问题留言或后台交流,ipynb代码笔记可在后台回复 plotnine 获取。

相关阅读

References

[1] SEE Conf 2018: https://www.yuque.com/seeconf/content/highlights
[2] plotnine文档: https://plotnine.readthedocs.io/en/stable/api.html
[3] plotnine/issues/10: https://github.com/has2k1/plotnine/issues/10
[4] 钻石数据集: https://ggplot2.tidyverse.org/reference/diamonds.html
[5] ggplot文档: https://pypi.org/project/ggplot/

本文分享自微信公众号 - 蛰虫始航(lyns_sailing)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认