美文网首页R语言商业智能BI那点事儿数据分析
R|ggplot2(二)|覆盖柱状图各种需求

R|ggplot2(二)|覆盖柱状图各种需求

作者: 天善智能 | 来源:发表于2017-10-20 14:26 被阅读726次

感谢关注天善智能,走好数据之路↑↑↑

欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!

本文作者:天善智能社区专家dwzb

天善智能社区地址:https://www.hellobi.com/

第一篇戳:R|ggplot2(一)|一个完整的绘图流程

目录

赋权和所用数据类型

分组作图与aes

隐含参数解释

分组条形图,三种展现形式,如不同组在一根柱子上堆叠还是并排放置

柱子高低顺序排列

正负条形图

横向条形图

饼图(这里没有专门画饼图的函数,饼图是柱状图的一种特例)

分面

柱子上标注文字

本文使用R自带数据集mpg。横轴使用class列,分组使用cyl列,数量使用dyspl列。

赋权和所用数据类型

library(ggplot2)ggplot(mpg,aes(x=class)) + geom_bar() # 查看class中每种类别的个数ggplot(mpg,aes(x=class,y=displ)) + geom_bar(stat="identity") # 使用第二种数据类型,接受两个参数ggplot(mpg,aes(x=class)) + geom_bar(aes(weight=displ)) # 使用displ对class赋权ggplot(mpg,aes(x=class)) + geom_bar(aes(weight=rep(1,length(class)))) # 第一种相当于赋权全为1

我们会发现14图形相同,23图形相同。这里涉及到的数据样式和之前说的有所不同。

之前我们说画柱状图可以接受两种数据样式

一种是 名字罗列

一种是 名字-频数

本文第一种做法便是所谓的名字罗列,函数内部会自动数出每一类有多少个,柱子有多高。第二种的数据却不太一样,因为 名字-频数 是已经统计出每一个名字总共的频数,而这个数据集展现的名字却有重复的,这其实相当于是第三种数据样式,我暂且称之为赋权样式。

赋权样式可以当成名字-频数来处理,函数内部会自动将相同的名字合并。

也可以当成名字罗列的情况处理,同时指定权重,这就是第三个代码显示的方法。第四个图表示第一种只是查数,代表赋权全为1。

分组作图与aes

上一篇文章中,我们已经简单设置了柱状图中的 col fill width 等参数,它们都是直接放在geom_bar里面的,而有一些参数像x和y则是放在又套了一层aes,现在我们要对这个现象进行解释。

我们从分组作图入手,下面使用fill的5种尝试,3种不报错的形式中,只有最后一种实现了分组作图,我们来看一看他们之间的区别

# ggplot(mpg,aes(x=class)) + geom_bar(fill=cyl) # 报错# ggplot(mpg,aes(x=class)) + geom_bar(fill=mpg$cyl) # 报错ggplot(mpg,aes(x=class)) + geom_bar(fill=1:7)ggplot(mpg,aes(x=class)) + geom_bar(aes(fill=cyl)) # 未成功完成分组ggplot(mpg,aes(x=class)) + geom_bar(aes(fill=factor(cyl))) # 按照cyl分组# 其他参数ggplot(mpg,aes(x=class)) + geom_bar(aes(col=factor(cyl)))ggplot(mpg,aes(x=class)) + geom_bar(aes(alpha=factor(cyl)))ggplot(mpg,aes(x=class)) + geom_bar(fill="blue") # 显示蓝色ggplot(mpg,aes(x=class)) + geom_bar(aes(fill="blue")) # 显示粉红色ggplot(mpg,aes(x=class)) + geom_bar(aes(fill="a")) # 显示粉红色

(图形展示了前四张图)

上面的结果说明了一下几个问题(按顺序一个一个看)

第一次报错,在aes外面无法找到cyl对象,说明只有放在aes中,才能直接引用数据集的列名,而不需要使用$

第二行,加了$仍然报错,是因为在aes外面的fill指向的是那7根柱子,所以应该接一个长度为7的向量。只有在aes中,数据才能和原数据框的每一行相对应

知道了这个,读者就应该明白了上一部分赋权时,weight参数放在aes里面的原因了。

第三行使用了长度为7的颜色向量,实现了每根柱子颜色不一样,但是无法按照cyl分组展示

第四行没有实现分组,说明fill想要接分类变量(离散变量),需要是因子型数据

第五行成功分组显示。其内在逻辑如下,请读者在脑海中想象一下:class中一个名字是一个柱子,每个柱子被拆分成n个短柱子(n为名字重复的次数),堆在一起。每个短柱子对应一个cyl值(一行),所有短柱子的cyl值相同则颜色相同,现在应该能想象出这样一幅画面:一共7根柱子,每根柱子上都是色彩斑斓的,由4个颜色组成。接下来,对于每根长柱子,把颜色相同的短柱子放在一起再重新堆起来,最后展示出来的便是分组作图的结果。

第六七行表示除了fill,还有col和alpha都可以接分组变量实现分组展示,只是区分展示方式不一样。如果是画点图的话,对应起来可以用颜色、大小、形状等来区分,也都是用相应参数接分类变量实现的

我们可以看出,我们没有指定具体的颜色,只是告诉函数,按照这个变量来分类,就会使用默认的颜色,同时生成图例。这样默认生成的图形本身就很大气美观,省去了很多优化的步骤,这是ggplot2包的一大优势

最后一部分三个函数反映了在aes里面和外面定义颜色的区别。在aes外面定义蓝色就是蓝色,在aes里面其实”blue”被认为是一个分组的因子了,它本身是什么已经不重要了,它只是传达了,所有柱子都被认为分到了同一组,使用同一个颜色,而颜色则是使用默认的

隐含参数解释

当我们使用 罗列名字 的数据来作图的时候,其实函数内部计算出了每个名字的数量,这样才能代表每个柱子的高度,这个数值不是我们输进去的,但是我们可以引用它,但是只有在aes中使用才有效

柱状图的参数有以下两个

..count.. 每根柱子多高

..prop.. 每根短柱子占整个长柱子的百分比,如果没进行分组,则每根柱子对应的..prop..都是1

ggplot(mpg,aes(x=class)) + geom_bar() # 只接一个参数相当于第二个参数是..count..ggplot(mpg,aes(x=class,y=..count..)) + geom_bar()ggplot(mpg,aes(x=class,y=..prop..)) + geom_bar() # 每根柱子的prop都是1# ggplot(mpg,aes(x=class)) + geom_bar(aes(fill=..count..)) # 连续性变量与后面因子型变量,看差别ggplot(mpg,aes(x=class)) + geom_bar(aes(fill=factor(..count..)))ggplot(mpg,aes(x=class)) + geom_bar(aes(group=factor(cyl),fill=..prop..))

(为了展示代码的真实结果,图有点丑,比如坐标轴标注重叠可以用之后学到的内容再进行调整)

后两个例子解释一下。

因为..count..数的是每根长柱子的高度,所以每个长柱子的下分短柱子对应的fill值没有差异,差异体现在长柱子与长柱子之间,所以结果便是每根柱子颜色不一样。

可以看到分类时用连续性变量,则使用的颜色是渐变的,而使用因子型变量则为分类颜色

第二个例子为了让..prop..不再为1,需要分组,group接分组变量可以实现分组,但是它不像fill表示颜色,alpha表示透明度,它没有展示的途径,所以一般即使用group分组,做出图形也看不出来组别之间的区别。但是对于..prop..确是有影响的。这个例子只是为了展示..prop..这个变量,真正使用的时候不会画这样的图

分组条形图,三种展现形式

上面我们看到的分组条形图中,每根柱子上的不同组别短柱子是堆叠起来的,我们还可以实现并排放置和填充比例展示,只要使用position参数调整

ggplot(mpg,aes(x=class)) + geom_bar(aes(fill=factor(cyl)),position="stack") # position默认,堆叠ggplot(mpg,aes(x=class)) + geom_bar(aes(fill=factor(cyl)),position="dodge") # 并排放置ggplot(mpg,aes(x=class)) + geom_bar(aes(fill=factor(cyl)),position="fill") # 填充显示比例

柱子高低顺序排列

我们使用两种方法

自己编写函数,根据factor原理来进行排序

使用包中自带的reorder函数

1. 首先我们要理解ggplot2包中factor的使用

其实前面我们在画柱状图时,使用的变量并不规范,当横坐标是离散型变量时,像柱状图这样一根一根柱子这样,x参数接的应该是一个因子型数据,我们直接x=name在这里没显示出什么错误,但是看看如下例子

aa <- data.frame(a=sample(1:7,30,replace=T),                 b=sample(1:3,30,replace=T))ggplot(aa,aes(x=a)) + geom_bar()ggplot(aa,aes(x=factor(a))) + geom_bar()ggplot(aa,aes(x=factor(a))) + geom_bar(aes(fill=b))ggplot(aa,aes(x=factor(a))) + geom_bar(aes(fill=factor(b)))

我们可以看出x没有用factor的时候,横轴没有把所有的标签全标上,这表示把横轴当成连续性变量来看了,所以只标了一部分标签以表示大小关系。

fill也是作为离散分类变量,也应该接一个factor,我们可以看到不加时,图例是一个连续性渐变颜色的形式,这无法达到我们分类的要求。

2. 使用自己编写的函数

ggplot(mpg,aes(x=factor(class))) + geom_bar()

先看这张图,默认画图时横轴标度排列顺序为,按照首字母排序,这和因子型数据有关

mpg$class[1:5]# [1] "compact" "compact" "compact" "compact" "compact"fclass <- factor(mpg$class)fclass[1:5]# [1] compact compact compact compact compact# Levels: 2seater compact midsize minivan pickup subcompact suv

这里我们可以看出,转化为因子型之后数据的level的排列方式,不是根据元素出现的前后顺序来排列的(否则第一根柱子应该是compact),而是按照首字母排列的(2seater)。

所以ggplot2柱状图横轴排列顺序的本质就是根据factor的levels,所以我们只要改变这个factor的level,就可以调整柱子排列顺序。我们通过定义一个函数来实现level的改变

reorder_size <- function(x) {  factor(x, levels = names(sort(table(x))))}ggplot(mpg, aes(reorder_size(class))) + geom_bar() # 柱子从低到高排列

这样柱子就从低向高排列了

3. 使用包中的reorder函数

x <- sample(letters[1:3],30,replace = T)y <- 1:30reorder(x,y,sum)

我们可以看到reorder函数接3个参数,最后返回的向量是一个因子型向量,其主体还是x,只是改变了levels,改变的原则是:按照x对y进行分组,对每一组组成的向量计算后面的函数,最后根据计算结果从小到大指定x中元素的levels

使用这个函数来画条形图的原理:根据class对一个全是1的向量分组求和(相当于计算了class中每一个元素出现的个数),再根据求和结果指定levels

ggplot(mpg,aes(reorder(class,rep(1,length(class)),sum)))+geom_bar() # 作图结果和上面相同

正负条形图

只要数据是负数,就能画出往下方的条形图

d <- data.frame(a=letters[1:7], b=c(4,-6,5,-4,-3,6,4))ggplot(d,aes(a,b)) + geom_bar(stat="identity")ggplot(d,aes(a,b)) + geom_bar(aes(fill=factor((b>0)+1)),stat="identity")

横向条形图

ggplot(mpg,aes(x=class)) + geom_bar() + coord_flip()

coord_flip 表示横纵坐标位置互换

饼图

ggplot(mpg, aes(class))+geom_bar()+coord_polar(theta = "y")ggplot(mpg, aes(class))+geom_bar()+coord_polar(theta = "x")ggplot(mpg, aes(class))+geom_bar(aes(fill=drv))+coord_polar(theta = "y")ggplot(mpg, aes(class))+geom_bar(aes(fill=drv))+coord_polar(theta = "x")

我们可以看出,这里所谓的饼图,只是把坐标轴做了圆形扭曲,只是theta参数接”x”和”y”不一样,扭曲的方式不一样

theta=”y”时,是把y轴方向扭曲了,柱子都变成了弯的

theta=”x”时,是把x轴方向扭曲了,柱子都从同一个中心出发

加上颜色分类变量之后,也只是在相应柱子上分了组

有的读者可能会疑惑,这里要讲的不是饼图吗,这里展示的都只是和圆形搭边,却不是正常我们看到的饼图。

其实正常形式的饼图是theta=”y”时的一种特例:只有一根柱子

所以当我们拿到数据的时候,想要画饼图,对数据的思考和柱状图是不一样的。这一点和基础作图函数是不一样的。

比如还是class这一列

基础函数中,画饼图和画柱状图的思路是一样的,让x=class

ggplot2的饼图中,则是fill=class,为了保持一根柱子,x=1

ggplot(mpg, aes(1, fill=class))+geom_bar()+coord_polar(theta = "y")

分面

分面条形图其实就是分组条形图的另外一种展现形式,也是拿用来分组的变量将数据拆分,为了更方便地使用分面功能,这里不局限在柱状图,我们使用点图来完成。

两个函数,两种思路

facet_grid 函数,按照一个指标分成m个,按照另一个指标分成n个,排列方式就是m*n式

facet_wrap函数的思路和matrix创建的思路相似,现有一串,再指定每行放几个

看下面的帮助文档中的例子就大概懂了,其他参数细节可以自己查看帮助文档学习

p <- ggplot(mpg, aes(displ, cty)) + geom_point()ggplot(mpg, aes(displ, cty)) + geom_point(aes(color=factor(cyl)))p + facet_grid(. ~ cyl)p + facet_grid(drv ~ .)p + facet_grid(drv ~ cyl)ggplot(mpg, aes(displ, hwy)) +  geom_point() +  facet_wrap(~class)ggplot(mpg, aes(displ, hwy)) +  geom_point() +  facet_wrap(~class, nrow = 4)ggplot(mpg, aes(displ, hwy)) +  geom_point() +  facet_wrap(~ cyl + drv)ggplot(mpg, aes(displ, hwy)) +  geom_point() +  facet_wrap(c("cyl", "drv"))

柱子上标注文字

下面我们通过两个例子来解释如何在柱状图柱子上方标数字

df <- data.frame(  x = factor(c(1, 1, 2, 2)),  y = c(1, 3, 2, 1),  grp = c("a", "b", "a", "b"))ggplot(df, aes(x)) + geom_bar() +  geom_text(aes(label=..count..),            stat="count", color = "red",            vjust = -0.5, size = 5)ggplot(data = df, aes(x, y, group = grp)) +  geom_col(aes(fill = grp), position = "dodge") +  geom_text(aes(label = y), position = position_dodge(0.9))

看第一个图的参数,需要注意一下几点

stat=”count” 因为geom_text函数默认 stat = “identity”,这种情况在前面说柱状图的时候遇到过,是接受两个参数xy时使用的,而此处只有一个x,因此要改成数数的”count”

上面改成count之后,函数会自动计算出一个变量 ..count..,表示每根柱子的高度,这正是我们要使用的,它只能在aes之中使用,令label=..count..即让每根柱子上标签对应该值

color调整颜色,size调整字体大小

vjust 调整竖直方向位置

(读者可以修改参数体验变化,这样可以理解的更深刻)

看第二个图的参数,需要注意一下几点

此时使用数据为xy,因此正好使用默认的stat = “identity”,不用修改

这次涉及到分组,要让每个组的柱子上分别标注上,所以要告诉函数geom_text如何分组。这里没有在geom_text函数中重新设置,所以继承了前面的group = grp,按照grp分组。

label = y前面已经按照grp分组,所以y产生了4个值

position = position_dodge(0.9) 如果没加这个参数,每一类的两个数值都在一条竖直线上显示,这里是告诉函数柱子的宽度,让两组的数分开放置

如果没有group,即使有position,也无法将两组分开。

文末彩蛋

推荐几个rstudio快捷键

ctrl + U 删除本行光标之前的所有内容

ctrl + K 删除本行光标之后的所有内容

ctrl + D 删除本行

天善智能社区地址:https://www.hellobi.com/

天善学院svip正限时特惠火爆报名中!包含业务知识一站通、Excel BI商业智能、七周成为数据分析师、对话大数据系列技术、R语言15案例、Python3网络爬虫实战案例、Python机器学习、Python数据科学家精华实战课程、深度学习模型和实战课程、数据分析报告共10套课程,其他课程只需五折即可,欢迎大家关注报名。https://www.hellobi.com/svip

相关文章

  • R|ggplot2(二)|覆盖柱状图各种需求

    感谢关注天善智能,走好数据之路↑↑↑ 欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领...

  • R语言绘制GO富集分析柱状图

    ggplot2绘制GO富集分析柱状图 - sryjm - 博客园 GO富集分析及结果柱状图绘制R代码_x2ylin...

  • 【R>>barplot】特别的柱状图

    题记:一个简单但富有特色的柱状图 本文为ggplot2绘制一个特别的柱状图(来自公众号:R语言数据分析指南)的学习...

  • ggplot2优雅的绘制圆形柱状图

    本节来介绍如何利用ggchicklet包通过ggplot2来绘制圆形柱状图 加载R包 加载数据 数据清洗 数据可视...

  • 科研绘图——柱状图

    R语言科研绘图——柱状图 前言 使用R语言绘制能够发表的图片,ggplot2是一个很好的选择。并且一些基于ggpl...

  • R语言|绘制组间差异柱状图

    柱状图也是差异可视化图形的一种,今天小编来分享一下组间差异柱状图在R语言中的绘制方法,主要用的是ggplot2包,...

  • 瑞德学习R语言day03

    factor(变量) 因子类型的转化 R语言绘图 使用ggplot2绘图导入依赖 绘制柱状图 统计一组数中元素的情...

  • ggplot2绘制柱状图+折线图

    之前分享过不少绘制柱状图的案例,各种类型的都有,今天来展示一个ggplot2绘制柱状图并加上折线图的案例,依然使用...

  • 生物统计-数据可视化

    可视化工具:R包,ggplot,ggplot2,两种可视化变量:类别型、定量型。饼图、柱状图。条形图、散点图、箱线...

  • R语言 | ggplot2-boxplot的上下边缘的横线去哪了

    废话 ggplot2是R语言绘图神奇,在各种扩展包的加持下无往而不胜。然而使用ggplot2绘制boxplot的时...

网友评论

    本文标题:R|ggplot2(二)|覆盖柱状图各种需求

    本文链接:https://www.haomeiwen.com/subject/zckvuxtx.html