本节简要概述ggplot2包的工作原理。如果您只是简单地寻找代码来创建特定类型的图,那么可以跳过这一部分。然而,这些材料可以帮助你理解这些碎片是如何组合在一。起的。
ggplot2包中的函数构建了一个分层的图形。我们将通过从一个简单的图开始并添加额外的元素,一次添加一个元素来构建一个复杂的图。
这个例子使用了1985年当前人口调查的数据来探索工资和经验之间的关系。
library(tidyverse)
library(mosaicData)
# load data
data(CPS85 , package = "mosaicData")
CPS85 %>% glimpse()
## Observations: 534
## Variables: 11
## $ wage <dbl> 9.00, 5.50, 3.80, 10.50, 15.00, 9.00, 9.57, 15.00, 11.00, ...
## $ educ <int> 10, 12, 12, 12, 12, 16, 12, 14, 8, 12, 17, 17, 14, 14, 12,...
## $ race <fct> W, W, W, W, W, W, W, W, W, W, W, W, W, W, W, W, W, NW, NW,...
## $ sex <fct> M, M, F, F, M, F, F, M, M, F, M, M, M, M, M, M, M, M, M, M...
## $ hispanic <fct> NH, NH, NH, NH, NH, NH, NH, NH, NH, NH, Hisp, NH, Hisp, NH...
## $ south <fct> NS, NS, NS, NS, NS, NS, NS, NS, NS, NS, NS, NS, NS, NS, NS...
## $ married <fct> Married, Married, Single, Married, Married, Married, Marri...
## $ exper <int> 27, 20, 4, 29, 40, 27, 5, 22, 42, 14, 18, 3, 4, 14, 35, 0,...
## $ union <fct> Not, Not, Not, Not, Union, Not, Union, Not, Not, Not, Not,...
## $ age <int> 43, 38, 22, 47, 58, 49, 23, 42, 56, 32, 41, 26, 24, 34, 53...
## $ sector <fct> const, sales, sales, clerical, const, clerical, service, s...
在构建ggplot2图时,只需要下面描述的前两个函数。其他函数是可选的,可以以任何顺序出现。
构建图形的第一个函数是ggplot函数
包含要绘制的数据的数据框
变量到图形可视属性的映射,映射被放置在aes函数。
# specify dataset and mapping
library(ggplot2)
ggplot(data = CPS85,
mapping = aes(x = exper, y = wage))
为什么图表是空的?我们指定exper变量应该映射到x轴,wage应该映射到y轴,但是我们还没有指定我们想要放置在图上的内容。
geoms是可以放置在图形上的几何对象(点、线、条等)。它们是使用以geom开头的函数添加的。在这个例子中,我们将使用 geom_point函数添加点,创建散点图。
在ggplot2图中,函数使用+符号链接在一起来构建最终的绘图。
# add points
ggplot(data = CPS85,
mapping = aes(x = exper, y = wage)) +
geom_point()
图表显示存在一个异常值。 一个人的工资比其他人高得多。在继续之前,我们将删除这个观测值。
CPS85 %>%
filter(wage < 40) %>%
ggplot(aes(exper,wage)) +
geom_point()
可以在geom 函数中指定许多参数(选项)。geom_point函数的选项包括color、size和 alpha。 它们分别控制点的颜色、大小和透明度。透明度范围从0(完全透明)到1(完全不透明)。 增加一定程度的透明度可以帮助可视化重叠点。
# make points blue, larger, and semi-transparent
CPS85 %>%
filter(wage < 40) %>%
ggplot(aes(exper,wage)) +
geom_point(color = "cornflowerblue",
alpha = .7,
size = 3)
接下来,让我们添加一行最佳拟合。我们可以用geom_smooth函数来实现。选项控制线条的类型(linear, quadratic, nonparametric),线条的粗细,线条的颜色,以及置信区间的存在与否。这里我们请求一个线性回归线(方法lm)(其中lm代表线性模型)。
CPS85 %>%
filter(wage < 40) %>% # 工资小于40
ggplot(aes(exper,wage)) +
geom_point(color = "cornflowerblue",
alpha = .7,
size = 3) +
geom_smooth(method = "lm")
## `geom_smooth()` using formula 'y ~ x'
工资似乎随着经验的增加而增加。
除了将变量映射到x轴和y轴之外,变量还可以映射到几何对象的颜色、形状、大小、透明度和其他视觉特征。这使得一组观测数据可以叠加在一个单一的图表中。
让我们在plot中加入性别元素,用color来表现它。
# indicate sex using colol
CPS85 %>%
filter(wage < 40) %>% # 工资小于40
ggplot(aes(exper,wage,col = sex)) + # x轴,y轴
geom_point(alpha = .7,
size = 3) +
geom_smooth(method = "lm",
se = FALSE,
size = 1.5)
## `geom_smooth()` using formula 'y ~ x'
性别选项被放置在aes函数中,因为我们将一个变量映射到一个美学上。增加geom_smooth选项(se = FALSE)用来取消置信区间。看起来男人比女人挣的钱多。此外,男性的经验与工资之间的关系可能比女性更为密切。
scales控制变量如何映射到plot的视觉特征。scales函数(以scale_为开始)允许您修改此映射。在下一个图中,我们将更改x 轴和y 轴scales以及使用的颜色。
# modify the x and y axes and specify the colors to be used
CPS85 %>%
filter(wage < 40) %>% # 工资小于40
ggplot(aes(exper,wage,col = sex)) + # x轴,y轴
geom_point(alpha = .7,
size = 3) +
geom_smooth(method = "lm",
se = FALSE,
size = 1.5)->p1
CPS85 %>%
filter(wage < 40) %>% # 工资小于40
ggplot(aes(exper,wage,col = sex)) + # x轴,y轴
geom_point(alpha = .7,
size = 3) +
geom_smooth(method = "lm",
se = FALSE,
size = 1.5) +
scale_x_continuous(breaks = seq(0,60,10)) +
scale_y_continuous(breaks = seq(0,30,5),labels = paste("$",seq(0,30,5),sep = "")) +
scale_color_manual(values = c("indianred3",
"cornflowerblue"))->p2
gridExtra::grid.arrange(p1,p2,ncol = 2)
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
X轴和y轴上的数字更好,y轴使用美元符号,而且颜色更有吸引力(IMHO)。
我有个问题: 经验、工资和性别之间的关系是否在每个工作部门都是相同的?为了探究这个问题,让我们在每个职业领域重复一次这个图表。
# reproduce plot for each level of job sector
psych::describe(CPS85)
## vars n mean sd median trimmed mad min max range skew
## wage 1 534 9.02 5.14 7.78 8.28 4.12 1 44.5 43.5 1.69
## educ 2 534 13.02 2.62 12.00 13.05 1.48 2 18.0 16.0 -0.20
## race* 3 534 1.87 0.33 2.00 1.97 0.00 1 2.0 1.0 -2.25
## sex* 4 534 1.54 0.50 2.00 1.55 0.00 1 2.0 1.0 -0.16
## hispanic* 5 534 1.95 0.22 2.00 2.00 0.00 1 2.0 1.0 -4.09
## south* 6 534 1.29 0.46 1.00 1.24 0.00 1 2.0 1.0 0.91
## married* 7 534 1.34 0.48 1.00 1.31 0.00 1 2.0 1.0 0.65
## exper 8 534 17.82 12.38 15.00 16.75 11.86 0 55.0 55.0 0.68
## union* 9 534 1.18 0.38 1.00 1.10 0.00 1 2.0 1.0 1.66
## age 10 534 36.83 11.73 35.00 36.07 11.86 18 64.0 46.0 0.55
## sector* 11 534 4.63 2.35 5.00 4.67 2.97 1 8.0 7.0 -0.19
## kurtosis se
## wage 4.90 0.22
## educ 0.81 0.11
## race* 3.09 0.01
## sex* -1.98 0.02
## hispanic* 14.76 0.01
## south* -1.17 0.02
## married* -1.58 0.02
## exper -0.40 0.54
## union* 0.77 0.02
## age -0.60 0.51
## sector* -1.14 0.10
CPS85 %>%
filter(wage < 40) %>% # 工资小于40
ggplot(aes(exper,wage,col = sex)) + # x轴,y轴
geom_point(alpha = .7,
size = 3) +
geom_smooth(method = "lm",
se = FALSE,
size = 1.5) +
scale_x_continuous(breaks = seq(0,60,10)) +
scale_y_continuous(breaks = seq(0,30,5),labels = paste("$",seq(0,30,5),sep = "")) +
scale_color_manual(values = c("indianred3",
"cornflowerblue")) +
facet_wrap(~sector) # 相当于研究四个变量
## `geom_smooth()` using formula 'y ~ x'
男人和妇女之间的差别似乎取决于所考虑的就业部门。
图表应该易于解释,信息标签是实现这一目标的关键因素。labs函数为轴和图例提供自定义标签。此外,还可以添加自定义标题、副标题和caption。
# add informative labels
CPS85 %>%
filter(wage < 40) %>%
ggplot(aes(exper,wage,col = sex)) +
geom_point(size = 2,alpha = 0.7) +
geom_smooth(method = "lm",se = FALSE,size = 1.5) +
scale_x_continuous(breaks = seq(0,60,10)) + # 划分X轴坐标数据
scale_y_continuous(breaks = seq(0, 30, 5),
label = scales::dollar) +
scale_color_manual(values = c("indianred3",
"cornflowerblue")) +
facet_wrap(~sector) +
labs(title = "Relationship between wages and experience", # 标题
subtitle = "Current Population Survey", # 副标题
caption = "source: http://mosaic-web.org/", # 注释
x = "Years of Experience",
y = "Hourly Wage",
color = "Gender") +
theme(plot.title = element_text(hjust = 0.5))
## `geom_smooth()` using formula 'y ~ x'
现在,读者不需要猜测 expr 和 wage 的含义,也不需要猜测数据来自哪里。
最后,我们可以使用主题微调图形的外观。主题函数(以主题开始)控制图形的背景颜色、字体、网格线、图例放置和其他与数据无关的特性。 让我们使用一个干净的主题。
CPS85 %>%
filter(wage < 40) %>%
ggplot(aes(exper,wage,col = sex)) +
geom_point(size = 2,alpha = 0.7) +
geom_smooth(method = "lm",se = FALSE,size = 1.5) +
scale_x_continuous(breaks = seq(0,60,10)) + # 划分X轴坐标数据
scale_y_continuous(breaks = seq(0, 30, 5),
label = scales::dollar) +
scale_color_manual(values = c("indianred3",
"cornflowerblue")) +
facet_wrap(~sector) +
labs(title = "Relationship between wages and experience", # 标题
subtitle = "Current Population Survey", # 副标题
caption = "source: http://mosaic-web.org/", # 注释
x = "Years of Experience",
y = "Hourly Wage",
color = "Gender") +
theme(plot.title = element_text(hjust = 0.5)) +
theme_minimal()
## `geom_smooth()` using formula 'y ~ x'
现在我们有了一些东西。在management, manufacturing, sales和“other” category中,男性似乎比女性挣得多。他们在clerical, professional和service positions最为相似。 这些数据没有包括建筑业的妇女。 就construction职位而言,男性的工资似乎与经验有关,而女性的工资则与经验无关(这可能是最有趣的发现)。对于销售来说也是如此。
当然,这些发现都是试验性的。它们基于有限的样本规模,不涉及统计测试,以评估差异是否可能是由于偶然变化。
使用ggplot2创建的图形总是从ggplot函数开始。在上面的示例中,数据和映射选项被放置在这个函数中。 在这种情况下,它们应用于后面的每个geom函数。您还可以将这些选项直接放置在geom中。在这种情况下,它们只适用于特定的geom。 考虑下面的图表。
# placing color mapping in the ggplot function
CPS85 %>%
filter(wage < 40) %>%
ggplot(aes(x = exper,
y = wage,
color = sex)) +
geom_point(alpha = .7,
size = 3) +
geom_smooth(method = "lm",
formula = y ~ poly(x,2),
se = FALSE,
size = 1.5)
由于性别映射出现在ggplot函数中,因此它既适用于geom_point(),也适用于geom_smooth()。点的颜色表示性别,并且为男性和女性生成一条单独的颜色趋势线。
比较一下
# placing color mapping in the geom_point function
CPS85 %>%
filter(wage < 40) %>%
ggplot(aes(x = exper,
y = wage)) +
geom_point(aes(color = sex),
alpha = .7,
size = 3) +
geom_smooth(
method = "lm",
formula = y ~ poly(x, 2),
se = FALSE,
size = 1.5
)
由于性别映射只出现在geom_point函数中,因此只能在geom_point函数中使用。为所有的观察数据创建一条单一的趋势线。
本书中的大多数示例都将数据data和映射mapping选项放在ggplot函数中。 此外,短语数据data和映射mapping被省略,因为第一个选项总是引用数据,而第二个选项总是引用映射。
ggplot2图可以保存为命名的r对象(类似于数据框) ,进一步操作,然后打印或保存到磁盘。
# prepare data
data(CPS85 , package = "mosaicData")
plotdata <- CPS85[CPS85$wage < 40, ]
# create scatterplot and save it
myplot <- ggplot(data = plotdata,
aes(x = exper, y = wage)) +
geom_point()
# print the graph
myplot
# make the points larger and blue then print the graph
myplot <- myplot + geom_point(size = 3, color = "blue")
myplot
# print the graph with a title and line of best fit but don't save those changes
myplot +
geom_smooth(method = "lm") +
labs(title = "Mildly interesting graph")
## `geom_smooth()` using formula 'y ~ x'
# print the graph with a black and white theme but don't save those changes
myplot + theme_bw()
这可以真正节省时间。当以编程方式保存图形时,它也很方便。现在是时候尝试其他类型的图表了。