r语言|R数据可视化(如何绘制条形图())

条形图也许是最常用的数据可视化工具,通常用来展示不同的分类下(在x轴上)某个数值型变量的取值(在y轴上)。例如,条形图可以用来形象地展示4种不同商品的价格,但不适宜用来展示商品价格随时间的变动趋势,因为这里的时间是一个连续变量——尽管我们也可以这么做,后面会看到这种情形。
绘制条形图时需特别注意一个重要的细节:有时条形图的条形高度表示的是数据集中变量的频数,有时则表示变量取值本身。牢记这个区别——这里极易混淆,因为两者与数据集的对应关系不同,但又对应同样的术语。本章将对此进行深入讨论,并分别介绍这两类条形图的绘图技巧。
从本章开始,本书将重点介绍使用ggplot2而不是R基础绘图系统。用ggplot2绘图更简便,并且可以绘制更复杂的图形。
3.1 绘制基本条形图 问题 你有一个包含了两列数据的数据框,其中一列数据表示条形在x轴上的位置,另一列表示每个条形在y轴上对应的高度,基于此,如何绘制条形图?
方法 使用ggplot()函数和geom_col()绘制上述条形图,并分别指定与x轴和y轴对应的变量(见图3-1)。

library(gcookbook) # 加载gcookbook是为了使用其中的pg_mean数据集 ggplot(pg_mean, aes(x = group, y = weight)) + geom_col()

r语言|R数据可视化(如何绘制条形图())
文章图片


图3-1:当x是离散变量时绘制的条形图
在之前版本的ggplot2中,建议用geom_bar(stat ="identity")来绘制针对变量值的条形图。在ggplot2 2.2.0版中,用geom_col()函数可以执行相同的操作。
讨论 当x是连续(数值型)变量时,条形图的结果与上图会略有不同。此时,ggplot不是只在实际取值处绘制条形,也会在x轴上介于最大值和最小值之间所有可能的取值处绘制条形,如图3-2所示。我们可以使用factor()函数将连续变量转化为离散变量。
# 没有Time == 6的输入 BOD #>Time demand #> 118.3 #> 2210.3 #> 3319.0 #> 4416.0 #> 5515.6 #> 6719.8# Time是数值型(连续)变量 str(BOD) #> 'data.frame':6 obs. of 2 variables: #>$ Time: num1 2 3 4 5 7 #>$ demand: num8.3 10.3 19 16 15.6 19.8 #>- attr(*, "reference")= chr "A1.4, p. 270"ggplot(BOD, aes(x = Time, y = demand)) + geom_col()# 使用factor()函数将Time转化为离散(分类)变量 ggplot(BOD, aes(x = factor(Time), y = demand)) + geom_col()

r语言|R数据可视化(如何绘制条形图())
文章图片


图3-2:针对变量值绘制的条形图,x轴对应的是连续变量(左图);将x转化为因子型变量之后绘制的条形图(注意此处缺失了取值为6的条形,右图)
值得注意的是,BOD中没有对应Time = 6的行。当x是连续变量时,ggplot2将使用数值坐标轴,该坐标轴在该范围内具有所有数值的空间,因此在图中会出现数值为6的空区域。当Time被转化成因子时,ggplot2会把它作为离散变量处理,其中的值被视为任意标签而不是数值,因此它不会在x轴上为最小值和最大值之间的所有可能的数值分配空间。
在本例中,数据集中有两列值分别对应于变量x和y。如果想让条形图的高度与每组变量的频数相对应,可参见3.3节的内容。
默认设置下,条形图的填充色为深灰色且条形图没有边框线,我们可通过调整fill参数的值来改变条形图的填充色;可通过colour参数为条形图添加边框线。在图3-3中,我们将填充色和边框线的颜色分别指定为浅蓝色和黑色。
ggplot(pg_mean, aes(x = group, y = weight)) + geom_col(fill = "lightblue", colour = "black")

在ggplot2中,颜色参数默认使用的是英式拼写colour,而非美式拼写color。然而,ggplot2会在底层将美式拼写重映射为英式拼写,因此输入美式拼写的参数并不影响函数的运行。
r语言|R数据可视化(如何绘制条形图())
文章图片


图3-3:所有条形的填充色和边框线颜色均为单色
另见 如果想让条形图的高度对应于每组变量的频数,参见3.3节。
要根据另一个变量的值重排因子水平顺序,参见15.9节。要手动更改因子水平顺序,参见15.8节。
关于图形着色的更多内容,参见第12章。
3.2 绘制簇状条形图 问题 如何绘制基于某些分类变量的簇状条形图?
方法 将分类变量映射到fill参数上,并运行命令geom_col(position = "dodge")。
下面以cabbage_exp数据集为例演示一下绘图过程,该数据集包含两个分类变量Cultivar和Date及一个连续变量Weight。
library(gcookbook) # 加载gcookbook是为了使用cabbage_exp数据集 cabbage_exp #>Cultivar Date Weightsdnse #> 1c39d163.180.9566144 10 0.30250803 #> 2c39d202.800.2788867 10 0.08819171 #> 3c39d212.740.9834181 10 0.31098410 #> 4c52d162.260.4452215 10 0.14079141 #> 5c52d203.110.7908505 10 0.25008887 #> 6c52d211.470.2110819 10 0.06674995

我们分别将Date和Cultivar映射到x和fill(见图3-4)。
ggplot(cabbage_exp, aes(x = Date, y = Weight, fill = Cultivar)) + geom_col(position = "dodge")

r语言|R数据可视化(如何绘制条形图())
文章图片


图3-4:簇状条形图
讨论 最基本的条形图通常只对应一个绘制在x轴上的分类变量和一个绘制在y轴上的连续变量。有时我们想额外添加一个分类变量跟x轴上的分类变量一起对数据进行分组。此时,可通过将该分类变量映射到fill参数来绘制簇状条形图,这里的fill参数用来指定条形的填充色。在这一过程中必须令参数position = "dodge"以使得两组条形在水平方向上错开排列,否则,系统会输出堆积条形图(参见3.7节)。
与映射到条形图x轴上的变量类似,映射到条形填充色参数上的变量应该是分类变量而不是连续变量。
我们可以通过将geom_col()中的参数指定为colour = "black"为条形添加黑色边框线;可以通过scale_fill_brewer()或者scale_fill_manual()函数对图形颜色进行设置。在图3-5中,我们使用RColorBrewer包中的Pastel1调色盘对图形进行调色。
ggplot(cabbage_exp, aes(x = Date, y = Weight, fill = Cultivar)) + geom_col(position = "dodge", colour = "black") + scale_fill_brewer(palette = "Pastel1")

其他图形属性诸如颜色colour(指定条形图的边框线颜色)和线型(linestyle)也能用来对变量进行分组,不过,填充色(fill)也许是最合人心意的图形属性。
注意,如果分类变量各水平的组合中有缺失项,那么,绘图结果中的条形则相应地略去不绘,同时,临近的条形将自动扩充到相应位置。删去上例数据中的最后一行后,可得到图3-6。
ce <- cabbage_exp[1:5, ] ce #>Cultivar DateWeightsdnse #> 1c39d163.18 0.9566144 10 0.30250803 #> 2c39d202.80 0.2788867 10 0.08819171 #> 3c39d212.74 0.9834181 10 0.31098410 #> 4c52d162.26 0.4452215 10 0.14079141 #> 5c52d203.11 0.7908505 10 0.25008887ggplot(ce, aes(x = Date, y = Weight, fill = Cultivar)) + geom_col(position = "dodge", colour = "black") + scale_fill_brewer(palette = "Pastel1")

r语言|R数据可视化(如何绘制条形图())
文章图片


图3-5:添加了黑色边框线和不同配色的簇状条形图
r语言|R数据可视化(如何绘制条形图())
文章图片


图3-6:缺失条形的簇状条形图——临近的条形自动扩充到相应位置
如果你的数据与上面类似,那么可以在分类变量组合缺失的那一项为变量y手动输入一个NA值。
另见 关于条形图着色的更多内容,参见3.4节。
要根据另一个变量的值重排因子水平顺序,参见15.9节。
3.3 绘制频数条形图 问题 如果数据集中每行数据对应于一个样本,如何针对样本频数绘制条形图?
方法 使用函数goem_bar(),同时不要映射任何变量到y参数(见图3-7):
# 等价于使用geom_bar(stat = "bin") ggplot(diamonds, aes(x = cut)) + geom_bar()

r语言|R数据可视化(如何绘制条形图())
文章图片


图3-7:频数条形图
讨论 diamonds数据集共有53 940行数据,每行数据对应于一颗钻石的品质信息:
diamonds #> # A tibble: 53,940 x 10 #>caratcutcolor clarity depth table pricexyz #> #> 1 0.23IdealESI261.5553263.953.982.43 #> 2 0.21PremiumESI159.8613263.893.842.31 #> 3 0.23GoodEVS156.9653274.054.072.31 #> 4 0.290 PremiumIVS262.4583344.24.232.63 #> 5 0.31GoodJSI263.3583354.344.352.75 #> 6 0.24Very Good JVVS262.8573363.943.962.48 #> # ... with 5.393e+04 more rows

geom_bar()函数在默认情况下将参数设定为stat = "bin",该操作会自动计算每组(根据x轴上面的变量进行分组)变量对应的观测数。从图3-7可以看到,切工精美(Ideal)的钻石大概有23 000颗。
在本例中,x轴对应的是离散变量。当x轴对应于连续变量时,我们会在每一个x值处得到一个条形,如图3-8上图所示。
x轴对应连续变量的条形图与直方图类似,但不完全相同。直方图如图3-8下图所示。在此类条形图中,每个条形表示唯一的x值,而在直方图中,每个条形表示一定范围内的x值。
r语言|R数据可视化(如何绘制条形图())
文章图片


图3-8:x轴对应于连续变量的频数条形图(上图);直方图(下图)
另见 如果不想让ggplot()函数自动计算每组数据的行数绘制频数条形图,而是想通过数据框中的某列来指定y参数的话,使用geom_col()函数,可以参见3.1节的内容。
当然,也可以通过先计算出每组数据的行数,再将计算结果传递给ggplot()函数来绘制上图。关于数据汇总的更多内容,参见15.17节。
关于直方图的更多内容,参见6.1节。
3.4 条形图着色 问题 如何将条形图中的条形设定为不同的颜色?
方法 将合适的变量映射到填充色(fill)上即可。
这里以数据集uspopchange为例。该数据集描述了美国各州人口自2000年到2010年的变化情况。我们选取出人口增长最快的10个州进行绘图。图中会根据地区信息(东北部、南部、中北部、西部)对条形进行着色。
首先,选取出人口增长最快的10个州:
library(gcookbook) # 加载gcookbook是为了使用uspopchange数据集 library(dplyr)upc <- uspopchange %>% arrange(desc(Change)) %>% slice(1:10)upc #>State AbbRegionChange #> 1NevadaNVWest35.1 #> 2ArizonaAZWest24.6 #> 3UtahUTWest23.8 #>...<4 more rows>... #> 8FloridaFLSouth17.6 #> 9ColoradoCOWest16.9 #> 10 South CarolinaSCSouth15.3

接下来,将Region映射到fill上并绘制条形图(见图3-9):
ggplot(upc, aes(x = Abb, y = Change, fill = Region)) + geom_col()

r语言|R数据可视化(如何绘制条形图())
文章图片

【r语言|R数据可视化(如何绘制条形图())】
图3-9:将分类变量映射到fill参数
讨论 条形图的默认颜色不是最吸引眼球的,因此,可能需要借助函数scale_fill_brewer()或scale_fill_manual()重新设定图形颜色。这里我们调用后者。我们通过设置colour = "black"将条形的边框线设定为黑色(见图3-10)。注意:颜色的映射设定是在aes()内部完成的,而颜色的设定是在aes()外部完成的:
ggplot(upc, aes(x = reorder(Abb, Change), y = Change, fill = Region)) + geom_col(colour = "black") + scale_fill_manual(values = c("#669933", "#FFCC66")) + xlab("State")

r语言|R数据可视化(如何绘制条形图())
文章图片


图3-10:分类着色、具有黑色边框线的簇状条形图,条形根据人口变动百分比排序
本例用reorder()函数将Abb的因子水平根据Change变量的值重新排序。在本例中,根据条形图的高度进行排序比按照字母顺序对分类变量排序更有意义。
另见 关于reorder()函数的更多用法,参见15.9节。
关于图形着色的更多内容,参见第12章。
3.5 对正负条形图分别着色 问题 如何根据条形对应的正负取值分别对其进行着色?
方法 下面以climate数据集的一个子集为例。首先,创建一个对取值正负性进行标示的变量pos:
library(gcookbook) # 加载gcookbook是为了使用climate数据集 library(dplyr)climate_sub <- climate %>% filter(Source == "Berkeley" & Year >= 1900) %>% mutate(pos = Anomaly10y >= 0)climate_sub #>Source Year Anomaly1y Anomaly5y Anomaly10y Unc10ypos #> 1Berkeley 1900NANA-0.1710.108 FALSE #> 2Berkeley 1901NANA-0.1620.109 FALSE #> 3Berkeley 1902NANA-0.1770.108 FALSE #>...<99 more rows>... #> 103 Berkeley 2002NANA0.8560.028TRUE #> 104 Berkeley 2003NANA0.8690.028TRUE #> 105 Berkeley 2004NANA0.8840.029TRUE

上述过程准备完毕后,将pos映射到填充色参数(fill)并绘制条形图(见图3-11)。注意:这里条形图的参数设定为position = "identity",可以避免系统因对负值绘制堆积条形而发出的警告消息。
ggplot(climate_sub, aes(x = Year, y = Anomaly10y, fill = pos)) + geom_col(position = "identity")

r语言|R数据可视化(如何绘制条形图())
文章图片


图3-11:对正负取值的条形分别着色
讨论 上面的绘图过程存在一些问题。首先,图形着色效果可能跟我们想要的相反:蓝色是冷色,通常对应于负值;红色是暖色,通常对应于正值。其次,图例显得多余且扰乱视觉。
我们可以通过scale_fill_manual()参数对图形颜色进行调整,设定参数guide = FALSE可以删除图例,如图3-12所示。同时,我们通过设定边框颜色(colour)和边框线宽度(size)为图形填加了一个细黑色边框。其中,边框线宽度(size)是用来控制边框线宽度的参数(单位是毫米):
ggplot(climate_sub, aes(x = Year, y = Anomaly10y, fill = pos)) + geom_col(position = "identity", colour = "black", size = 0.25) + scale_fill_manual(values = c("#CCEEFF", "#FFDDDD"), guide = FALSE)

r语言|R数据可视化(如何绘制条形图())
文章图片


图3-12:重新设定颜色并移除了图例的条形图
另见 要更改所用的颜色,参见12.4节和12.5节。
要隐藏图例,参见10.1节。
3.6 调整条形宽度和条形间距 问题 如何调整条形图的条形宽度和条形间距?
方法 通过设定geom_bar()函数的参数width可以使条形变得更宽或者更窄。该参数的默认值为0.9,更大的值将使绘制的条形更宽,反之则更窄(见图3-13)。
例如,标准宽度的条形图如下:

library(gcookbook) # 加载gcookbook是为了使用pg_mean数据集ggplot(pg_mean, aes(x = group, y = weight)) + geom_col()

r语言|R数据可视化(如何绘制条形图())
文章图片


图3-13:不同条形宽度的条形图
窄些的条形图如下:
ggplot(pg_mean, aes(x = group, y = weight)) + geom_col(width = 0.5)

宽些的条形图(条形图的最大宽度为1)如下:
ggplot(pg_mean, aes(x = group, y = weight)) + geom_col(width = 1)

簇状条形图默认组内的条形间距为0。如果希望增加组内条形的间距,则可以将width设定得小一些,并令position_dodge的取值大于width(见图3-14)。
r语言|R数据可视化(如何绘制条形图())
文章图片


图3-14:条形更窄的簇状条形图(左图);具有条形间距的簇状条形图(右图)
要得到更窄的簇状条形图,可运行:
ggplot(cabbage_exp, aes(x = Date, y = Weight, fill = Cultivar)) + geom_col(width = 0.5, position = "dodge")

要添加条形间距,可运行:
ggplot(cabbage_exp, aes(x = Date, y = Weight, fill = Cultivar)) + geom_col(width = 0.5, position = position_dodge(0.7))

左图的绘图命令中用到了参数position = "dodge",右图的绘图命令中用到了参数position = position_dodge()。这是因为position = "dodge"是参数默认为0.9的position = position_dodge()的简写。当我们需要单独指定该参数的时候,必须输入完整的格式。
讨论 width参数的默认值是0.9,position_dodge()函数中width参数的默认值也是0.9。更确切地说,position_dodge()函数中width参数的默认值为NULL,和geom_bar()函数中的width参数的取值是一样的。
下面的4条命令是等价的:
geom_bar(position = "dodge") geom_bar(width = 0.9, position = position_dodge()) geom_bar(position = position_dodge(0.9)) geom_bar(width = 0.9, position = position_dodge(width = 0.9))

条形图中,条形中心对应的x轴坐标分别是1、2、3等,但通常我们用不上这些数值。当用户运行命令geom_bar(width = 0.9)时,每组条形将在x轴上占据0.9个单位宽度。运行命令position_dodge(width = 0.9)时,ggplot2会自动调整条形位置,以使每个条形的中心恰好位于当每组条形宽度为0.9,且组内条形紧贴在一起时的位置,如图3-15所示。图中左右两部分的条形间距都为0.9,只是左图对应于0.9的条形宽度,右图对应于0.2的条形宽度。虽然左右两部分对应的条形宽度不同,但两图的条形中心是保持一致的。
r语言|R数据可视化(如何绘制条形图())
文章图片


图3-15:条形间距均为0.9,条形宽度分别为0.9(左图)和0.2(右图)的簇状条形图
如果做整幅图形的伸缩,那么条形图也会依照相应的比例进行伸缩。要了解图形是怎样变化的,只需改变图形所在窗口的大小,然后观察图形的变化即可。关于在输出图形文件时控制图片大小的更多内容,参见第14章。
本文摘自:《R数据可视化手册 第2版》
r语言|R数据可视化(如何绘制条形图())
文章图片


[美] 温斯顿·常(Winston Chang) 著,王佳,林枫,王祎帆,张晔 译
R语言数据可视化经典书籍全新升级,第2版中的大部分技巧使用的是新版的ggplot2包,精选快速绘制高质量图形的150多个技巧,全彩印刷。
1.R语言数据可视化经典书籍全新升级,第2版中的大部分技巧使用的是新版的ggplot2包,这是R中非常强大且灵活的绘图工具。

2.本书提供了150多个技巧,借助这些技巧,科学家、工程师、程序员和数据分析师无须梳理出R绘图系统的全部细节就可以快速绘制出高质量的图形。每个技巧解决一个特定的问题,读者可以将这些技巧应用到自己的项目中。

3.书中还包含图可视化设计的扩展内容。读者只要对R语言有基本的了解,就可以开始使用这本简单易用的参考书。
■ 用R中的默认图形来快速探索数据。
■ 绘制各种条形图、折线图和散点图。
■ 用直方图、密度曲线、箱形图和其他图形来描述数据分布。
■ 提供注解来帮助读图者理解数据。
■ 控制图形的整体外观。
■ 探索配色的选择。
■ 绘制网络图、热图和三维散点图。
■ 用tidyverse中的包对数据塑形。

    推荐阅读