ggplot2是R语言中最优雅,最美观的图形框架。它具有精心设计的结构。本教程重点介绍可用于制作任何ggplot的基础结构。但是,在ggplot2中绘制图的方式与学习曲线陡峭的基本图形截然不同。因此,将您对基本图形的了解留在后面并继续。

1.设置

首先,您需要告诉ggplot使用什么数据集data。这是使用ggplot(df)函数完成的,其中df的数据框包含制作绘图所需的所有功能。这是最基本的步骤。与基础图形不同,ggplot不会将向量作为参数。

您可以aes()通过指定数据集中的各个变量,将想要应用到ggplot(内部参数)的任何美学效果添加到其中-例如X和Y轴。颜色,大小,形状应基于其更改的变量也可以在此处本身指定。此处指定的美学将被您随后添加的所有geom层继承。

如果以后打算添加更多的图层(可能是折线图顶部的条形图),则可以在添加这些图层时指定各自的外观。

下面,我展示了一些如何在自身diamonds随附的数据集中使用ggplot的示例ggplot2。但是,在添加几何图层之前,不会打印任何图。

library(ggplot2)
ggplot(diamonds)  # if only the dataset is known.
ggplot(diamonds, aes(x=carat))  # if only X-axis is known. The Y-axis can be specified in respective geoms.
ggplot(diamonds, aes(x=carat, y=price))  # if both X and Y axes are fixed for all layers.
ggplot(diamonds, aes(x=carat, color=cut))  # Each category of the 'cut' variable will now have a distinct  color, once a geom is added.

该aes论点代表美学。ggplot2还将图的X轴和Y轴以及颜色,大小,形状,填充等也视为美观。如果要固定颜色,大小等(即,不根据数据框中的变量而变化) ,您需要aes()像这样在之外指定它。

ggplot(diamonds, aes(x=carat), color="steelblue")

2.图层

ggplot2中的图层也称为“geoms”。完成基本设置后,您可以将几何图形一个附加在另一个图形之上。该文档提供了所有可用几何的完整列表。

library(tidyverse)
## -- Attaching packages ------------------------ tidyverse 1.3.0 --
## √ tibble  2.1.3     √ dplyr   0.8.3
## √ tidyr   1.0.0     √ stringr 1.4.0
## √ readr   1.3.1     √ forcats 0.4.0
## √ purrr   0.3.3
## -- Conflicts --------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(DT)
ggplot(diamonds, aes(x = carat, y = price, color = cut)) + 
  geom_point() +
  geom_smooth() # Adding scatterplot geom (layer1) and smoothing geom (layer2).
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

我们在该绘图中添加了两个图层(geom)-geom_point()和geom_smooth()。由于X轴Y轴和颜色是在ggplot()设置本身中定义的,因此这两层继承了那些美学。另外,您也可以在geom层中指定这些外观。

ggplot(diamonds) + 
  geom_point(aes(x=carat, y=price, color=cut)) +
  geom_smooth(aes(x=carat, y=price, color=cut),se = F) # Same as above but specifying the aesthetics inside the geoms.
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

注意X和Y轴以及点的颜色如何根据cut变量的值而变化。图例已自动添加。我想提出一个改变。我不想在每个级别上使用多条平滑线,而是将它们全部集成在一条线下。怎么做?color从geom_smooth()层次上消除美学将达到目的。

ggplot(diamonds) + 
  geom_point(aes(x=carat, y=price, color=cut)) +
  geom_smooth(aes(x=carat, y=price)) # Remove color from geom_smooth
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
ggplot(diamonds, aes(x=carat, y=price)) + 
  geom_point(aes(color=cut)) + 
  geom_smooth()  # same but simpler
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

这对您来说是一个快速的挑战。能否使点的形状随color功能而变化

尽管设置过程花费了我们很多代码,但增加了更多的复杂性,例如层,每个cut的不同颜色等都很容易。想象一下,如果要在基本图形中进行编写,将必须编写多少代码?感谢ggplot2!

diamonds %>% 
  ggplot(aes(carat,price)) +
  geom_point(aes(color = cut,shape = cut),size = 2) +
  geom_smooth(aes(color = cut,linetype = cut),se = FALSE,size = 1.5)
## Warning: Using shapes for an ordinal variable is not advised
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

3.标签

现在,您已经绘制了图形的主要部分。您可能想要添加图解的主标题,并可能更改X和Y轴标题。这可以通过labs用于指定标签的层来完成。但是,操纵标签的大小,颜色是“主题”的工作。

library(ggplot2)
gg <- ggplot(diamonds, aes(x=carat, y=price, color=cut)) + 
  geom_point() + 
  labs(title="Scatterplot", x="Carat", y="Price")  # add axis lables and plot title.
print(gg)

将添加该图的主标题,并且将X和Y轴标签大写。

注意:如果要在函数内部显示ggplot,则需要显式保存它,然后使用进行打印print(gg),就像我们上面所做的那样。

4.主题

除了我们要增加标签的大小并更改图例标题外,几乎所有内容都已设置。调整标签的大小可以用做theme()通过设置功能plot.title,axis.text.x和axis.text.y。需要在中指定它们element_text()。如果要删除其中任何一个,请将其设置为element_blank(),它将完全消失。

调整图例标题有些棘手。如果您的图例是某个color属性的图例,并且根据因数而变化,则您需要设置scale_color_discrete(),其中颜色部分属于color属性,而离散部分属于离散值,因为图例是基于因数变量的。

gg1 <- gg + theme(plot.title=element_text(size=25, face="bold",hjust = 0.5), 
                  axis.text.x=element_text(size=10),   # X轴
                  axis.text.y=element_text(size=10),
                  axis.title.x=element_text(size=15),   # X标题
                  axis.title.y=element_text(size=15)) + 
                  scale_color_discrete(name="Cut of diamonds")  # add title and axis text, change legend title.
print(gg1)  # print the plot

如果图例显示基于因子变量的形状属性,则需要使用进行更改scale_shape_discrete(name="legend title")。如果它是一个连续变量,请scale_shape_continuous(name="legend title")改用。

所以现在,如果您的图例基于fill连续变量的属性,您能猜出要使用的函数吗?

答案是scale_fill_continuous(name="legend title")

5.分面

在上一张图表中,您在同一张图表中具有所有不同cut绘制值的散点图。如果您想要一张图表一张cut呢?

gg1
gg1 + 
  facet_wrap(~cut,nrow = 5) +
  theme(legend.position = "bottom")

gg1 + 
  facet_wrap(~cut,ncol = 3)

facet_wrap(formula)接受一个公式作为参数。RHS上的项目对应于该列。LHS上的项目定义行。

gg1 + facet_wrap(color ~ cut)  # row: color, column: cut

在中facet_wrap,X和Y轴的比例固定为默认容纳所有点。这将使属性的比较有意义,因为它们的规模相同。但是,可以通过设置参数使比例尺自由漫游,使图表看起来分布更均匀scales=free。

gg1 + facet_wrap(color ~ cut, scales="free")  # row: color, column: cut

为了进行比较,您也可以使用将所有图解放在一个网格中facet_grid(formula)

gg1 + facet_grid(color ~ cut,scales = "free")   # In a grid  # 相当于四个变量

请注意,各个图的标题已消失,为绘图区域留出更多空间。

6.常用功能

6.1 绘制时间序列图(使用ggfortify)

ggfortify软件包使直接从时间序列对象中绘制时间序列非常容易,而不必将其转换为数据框。下面的示例AirPassengers一步一步地绘制时间序列。

library(ggfortify)
library(forecast)
## Registered S3 method overwritten by 'xts':
##   method     from
##   as.zoo.xts zoo
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
## Registered S3 methods overwritten by 'forecast':
##   method                 from     
##   autoplot.Arima         ggfortify
##   autoplot.acf           ggfortify
##   autoplot.ar            ggfortify
##   autoplot.bats          ggfortify
##   autoplot.decomposed.ts ggfortify
##   autoplot.ets           ggfortify
##   autoplot.forecast      ggfortify
##   autoplot.stl           ggfortify
##   autoplot.ts            ggfortify
##   fitted.ar              ggfortify
##   fitted.fracdiff        fracdiff 
##   fortify.ts             ggfortify
##   residuals.ar           ggfortify
##   residuals.fracdiff     fracdiff
autoplot(AirPassengers) + 
  labs(title="AirPassengers")+  # where AirPassengers is a 'ts' object
  theme(plot.title = element_text(hjust = 0.5))

6.2 在同一ggplot上绘制多个时间序列

绘制多个时间序列要求您具有数据帧格式的数据,其中一列是将用于X轴的日期

  • 方法1:转换后,您只需要继续在一个之上叠加多个时间序列。

  • 方法2:通过tidyr将设置id为日期字段来融化数据框。然后只需添加一个geom_line并将颜色美感设置为variable(过程中创建)即可。

# Approach 1:
data(economics, package="ggplot2")  # init data
economics %>% head()
## # A tibble: 6 x 6
##   date         pce    pop psavert uempmed unemploy
##   <date>     <dbl>  <dbl>   <dbl>   <dbl>    <dbl>
## 1 1967-07-01  507. 198712    12.6     4.5     2944
## 2 1967-08-01  510. 198911    12.6     4.7     2945
## 3 1967-09-01  516. 199113    11.9     4.6     2958
## 4 1967-10-01  512. 199311    12.9     4.9     3143
## 5 1967-11-01  517. 199498    12.8     4.7     3066
## 6 1967-12-01  525. 199657    11.8     4.8     3018
ggplot(economics) + 
  geom_line(aes(x=date, y=pce, color="pcs")) + 
  geom_line(aes(x=date, y=unemploy, color="unemploy")) + 
  scale_color_discrete(name="Legend") +     
  labs(title="Economics") + # plot multiple time series using 'geom_line's
  theme(axis.text.x = element_text(size = 10),
        axis.text.y = element_text(size = 10),
        axis.title = element_text(size = 15)) +
  theme(plot.title = element_text(hjust = 0.5,size = 25))

economics %>% 
  select(date,pce,unemploy) %>% 
  tidyr::gather(key = id,value = value,-date) %>%
  ggplot(aes(date,value,color = id)) +
  geom_line() +
  scale_color_discrete("Color")

ggplot2的缺点是不可能在同一图上获得多个Y轴。以相同的比例绘制多个时间序列会使序列中的几个看起来很小。一个替代方法是facet_wrap设置它scales='free'

economics %>% 
  select("date", "pce", "unemploy", "psavert") %>% 
  tidyr::gather(key = id,value = value,-date) %>% 
  ggplot() +
  geom_line(aes(x=date, y=value, color=id)) +
  facet_wrap( ~ id, scales="free")

economics %>% 
  ggplot() +
  geom_point(aes(date,pce),col = "red") + xlab(label = NULL)-> p1

economics %>% 
  ggplot() +
  geom_line(aes(date,unemploy),col = 'blue') + xlab(label = NULL) -> p2

economics %>% 
  ggplot() +
  geom_line(aes(date,psavert),color = 'green') -> p3

gridExtra::grid.arrange(p1,p2,p3,nrow = 3)

6.3 条形图

默认情况下,ggplot会制作一个“计数”条形图,这意味着它会计算x美学指定的项目的频率并将其绘制出来。使用这种格式,您无需指定Y美学。但是,如果您要制作Y美学给出的绝对数的条形图,则需要geom_bar在内进行设置stat="identity"

plot1 <-
  ggplot(mtcars, aes(x = cyl)) + 
  geom_bar() + 
  labs(title = "Frequency bar chart") + # Y axis derived from counts of X item
  theme(plot.title = element_text(hjust = 0.5)) +
  theme(plot.title = element_text(size = 20),
        axis.text = element_text(size = 10),
        axis.title = element_text(size = 15)) 
print(plot1)

df <- data.frame(var=c("a", "b", "c"), nums=c(1:3))
plot2 <- ggplot(df, aes(x=var, y=nums)) + 
  geom_bar(stat = "identity") +  # Y axis is explicit. 'stat=identity'
  theme(plot.title = element_text(size = 20),
        axis.text = element_text(size = 10),
        axis.title = element_text(size = 15)) +
  theme(plot.title = element_text(hjust = 0.5)) +
  labs(title = "BarChart")
print(plot2)

6.4 自定义布局

gridExtra软件包提供了在单个网格中配置多个ggplots的功能。

library(gridExtra)
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
grid.arrange(plot1, plot2, ncol=2)

6.5 翻转坐标

df <- data.frame(var=c("a", "b", "c"), 
                 nums=c(1:3))
df
##   var nums
## 1   a    1
## 2   b    2
## 3   c    3
ggplot(df, aes(x=var, y=nums)) + 
  geom_bar(stat = "identity") + 
  coord_flip() + 
  labs(title="Coordinates are flipped") +
  theme(plot.title = element_text(hjust = 0.5))

6.6 调整X和Y轴限制

有3种方法可以更改X和Y轴限制。

  1. 使用coord_cartesian(xlim = c(x1,x2))
  2. 使用xlim(c(x1,x2))
  3. 使用scale_x_continuous(limits = c(x1,x2))

警告:第 2项和第3项将从数据本身中删除超出限制的数据点。因此,如果添加任何平滑线等,结果将失真。项1(coord_cartesian)不会删除任何数据点,而是会放大到图表的特定区域。

ggplot(diamonds,aes(x = carat, y = price, color = cut)) +
  geom_point() + 
  geom_smooth() +
  coord_cartesian(ylim = c(0, 10000)) + 
  labs(title = "Coord_cartesian zoomed in!") +
  theme(plot.title = element_text(hjust = 0.5))
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

ggplot(diamonds, aes(x=carat, y=price, color=cut)) + 
  geom_point() + 
  geom_smooth() + 
  ylim(c(0, 10000)) + 
  labs(title="Data points deleted: Note the change in smoothing lines!") +
  theme(plot.title = element_text(hjust = 0.5))
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
## Warning: Removed 5222 rows containing non-finite values (stat_smooth).
## Warning: Removed 5222 rows containing missing values (geom_point).
#> Warning messages:
#> 1: Removed 5222 rows containing non-finite values
#> (stat_smooth). 
#> 2: Removed 5222 rows containing missing values
#> (geom_point).

6.7 等坐标

添加coord_equal()到ggplot会将X和Y轴的限制设置为相等。以下是无意义的示例

ggplot(diamonds, aes(x=price, y=price+runif(nrow(diamonds), 100, 10000), color=cut)) +
  geom_point() + 
  geom_smooth() + 
  coord_equal()
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

6.8 变更主题

除了基本的ggplot2主题外,您还可以使用这些内置主题之一来更改绘图的外观。

  1. theme_gray()
  2. theme_bw()
  3. theme_linedraw()
  4. theme_light()
  5. theme_minimal()
  6. theme_classic()
  7. theme_void()

ggthemes软件包提供了模仿知名杂志和软件的其他ggplot主题。这是一个如何更改主题的示例。

ggplot(diamonds, aes(x=carat, y=price, color=cut)) +
  geom_point() +
  geom_smooth() +
  theme_bw() +
  labs(title="bw Theme") +
  theme(plot.title = element_text(hjust = 0.5))
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

6.9 图例-删除和更改位置

通过设置theme(legend.position="none"),您可以删除图例。通过将其设置为“top”,即theme(legend.position="top"),您可以在图上移动图例。通过legend.justification在绘图内设置坐标,可以将图例放置在绘图内

p1 <- ggplot(diamonds, aes(x=carat, y=price, color=cut)) + 
  geom_point() + 
  geom_smooth() + 
  theme(legend.position="none",
        plot.title = element_text(hjust = 0.5)) + 
  labs(title="legend.position='none'")  # remove legend

p2 <- ggplot(diamonds, aes(x=carat, y=price, color=cut)) + 
  geom_point() + 
  geom_smooth() + 
  theme(legend.position="top") +
  labs(title="legend.position='top'",
       plot.title = element_text(hjust = 0.5))  # legend at top

p3 <- ggplot(diamonds, aes(x=carat, y=price, color=cut)) +
  geom_point() + 
  geom_smooth() + 
  labs(title="legend.position='coords inside plot'") +
  theme(legend.justification=c(1,0), legend.position=c(1,0),
        plot.title = element_text(hjust = 0.5))  # legend inside the plot.

grid.arrange(p1, p2, p3, ncol=3)  # arrange
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

6.10 网格线

ggplot(mtcars, aes(x=cyl)) + 
  geom_bar(fill='darkgoldenrod2') +
  theme(panel.background = element_rect(fill = 'steelblue'))

ggplot(mtcars, aes(x=cyl)) + 
  geom_bar(fill='darkgoldenrod2') +
  theme(panel.background = element_rect(fill = 'steelblue'),
  panel.grid.major = element_line(colour = "firebrick", size=3),
  panel.grid.minor = element_line(colour = "blue", size=1))

6.11 图边距和背景

ggplot(mtcars, aes(x=cyl)) +
  geom_bar(fill="firebrick") 

ggplot(mtcars, aes(x=cyl)) + 
  geom_bar(fill="firebrick") + 
  theme(plot.background=element_rect(fill="steelblue"),
        plot.margin = unit(c(2, 4, 1, 3), "cm")) # top, right, bottom, left

6.12 注释

library(grid)
my_grob = grobTree(textGrob("This text is at x=0.1 and y=0.9, relative!\n Anchor point is at 0,0", x=0.1,  y=0.9, hjust=0,
  gp=gpar(col="firebrick", fontsize=25, fontface="bold")))

ggplot(mtcars, aes(x=cyl)) + 
  geom_bar() + 
  annotation_custom(my_grob) + 
  labs(title="Annotation Example")

6.13 保存ggplot

plot1 <- ggplot(mtcars, aes(x=cyl)) + 
  geom_bar()
# ggsave("myggplot.png")  # saves the last plot.
# ggsave("myggplot.png", plot=plot1)  # save a stored ggplot