玩转数据可视化之R语言ggplot2:(七)对图形添加注释和标签(包含标题、坐标轴、参考线和高亮等注释方法)

玩转数据可视化之R语言ggplot2


  • 🌸个人主页:JoJo的数据分析历险记
  • 📝个人介绍:小编大四统计在读,目前保研到统计学top3高校继续攻读统计研究生
  • 💌如果文章对你有帮助,欢迎关注、点赞、收藏、订阅专栏

本系列主要介绍R语言ggplot2的使用
参考资料:
ggplot2: Elegant Graphics for Data Analysis

🎄7.ggplot2对图形加注释标签

在我们数据可视化时,一个好的注释能使图形更好的传递信息,ggplot2本身和一些扩展包都提供了一些给图形加注释的技巧

🌲7.1 图形、坐标轴和图例等标题

在我们画图时,需要给图形、坐标轴和图例加标题。在ggplot2中,我们可以使用labs()函数完成这一系列的设置

我们还是以ggplot2中的mpg数据集为例

library(ggplot2)
head(mpg)
A tibble: 6 × 11
manufacturermodeldisplyearcyltransdrvctyhwyflclass
<chr><chr><dbl><int><int><chr><chr><int><int><chr><chr>
audia41.819994auto(l5) f1829pcompact
audia41.819994manual(m5)f2129pcompact
audia42.020084manual(m6)f2031pcompact
audia42.020084auto(av) f2130pcompact
audia42.819996auto(l5) f1626pcompact
audia42.819996manual(m5)f1826pcompact

🌿7.1.1 文本注释

下面我们要绘制发动机排量(displ)和每加仑里程(hwy)散点图,并定义颜色为cyl

ggplot(mpg, aes(displ, hwy)) +
    geom_point(aes(col=factor(cyl)))+#因为cyl是数值新数据,在这里我们将其转换为分类型数据
    labs(
        x='发动机排放量(displ)/L',
        y='每加仑行驶里程',
        colour = "Number of cylinders",
        title = "Mileage by engine size and cylinders",
        subtitle = '数据来源:http://fueleconomy.gov'
    )

png

☘️7.1.2 数学表达式注释

labs()一般是增加文本数据,但也可以使用quote()函数定义数学表达式,下面这个例子可以说明

values <- seq(from = -2, to = 2, by = .01)
df <- data.frame(x = values, y = exp(values ))
ggplot(df, aes(x, y)) + 
  geom_line() + 
  labs(y = quote(f(x) == e^x))

png

🍀7.1.3 markdown语法注释

同时,labs还支持markdown语法,例如有时我们需要加粗或者倾斜某些文字,我们需要指定相关theme为ggtext:element_markdown

library(ggtext)
df <- data.frame(x = 1:3, y = 1:3)
p <- ggplot(df, aes(x, y)) + 
  geom_point() + 
  labs(x = "x轴**加粗**")

p 
p + theme(axis.title.x = ggtext::element_markdown())

png

png

🌳7.2 添加文本标签

向绘图中添加文本是最常见的注释形式之一。在标记异常值和其他重要点非常有用。使用geom_text()来添加指定文本,在指定的x和y位置添加标签文本。

  • family美学设置字体的款式,例如sans(默认),serif,momo等,来看下面这个例子
df <- data.frame(x=1, y = 3:1, family = c('sans','serif','mono'))
ggplot(df,aes(x,y))+
    geom_text(aes(label = family,family=family))

png

  • fontface设置字体,包括三个值:‘plain’,‘bold’,‘italic’
df <- data.frame(x=1, y = 3:1, face = c('plain','bold','italic'))
ggplot(df,aes(x,y))+
    geom_text(aes(label = face,fontface=face))

png

  • 我们还可以使用hjust和vjust来调整文本对齐方式,hjust可以选择(‘left’,‘right’,‘center’,‘inward’,‘outward’)
    vjust选择(‘bottom’,‘middle’,‘top’,‘inward’,‘outward’),默认是居中对齐,但有时候我们需要调整。最常用的是inward。它将文本对齐到图形内部,从而确保标签保持在绘图限制内:
df <- data.frame(
  x = c(1, 1, 2, 2, 1.5),
  y = c(1, 2, 1, 2, 1.5),
  text = c(
    "bottom-left", "bottom-right", 
    "top-left", "top-right", "center"
  )
)
ggplot(df, aes(x, y)) +
  geom_text(aes(label = text))
ggplot(df, aes(x, y)) +
  geom_text(aes(label = text), vjust = "inward", hjust = "inward")

png

png

从上图可以看出使用inword可以叫四个角落的文本全部保证在图形内部显示

  • size来控制文本的大小,但是ggplot2默认的单位是mm,和大多数默认的pt不同,1pt = 72.27/25.4mm

  • angle指定文本的旋转角度(以度为单位)。

  • 通常我们希望标记图形中的点,为了避免文本与点重叠,我们可以使用nudeg_x和nudeg_y来设置文本偏移

df <- data.frame(trt = c("a", "b", "c"), resp = c(1.2, 3.4, 2.5))
ggplot(df, aes(resp, trt)) + 
  geom_point() + 
  geom_text(aes(label = paste('(',resp,')')) ,nudge_y = -0.15) + 
  xlim(1, 3.6)

png

  • 还有一个参数是check_overlap,从英语意思来看,是检查重叠图形,当check_overlap=TRUE,
    重叠标签将自动从绘图中删除。算法很简单:标签按照它们在数据框中出现的顺序绘制;如果标签将与现有点重叠,则忽略该标签。
ggplot(mpg, aes(displ, hwy)) + 
  geom_text(aes(label = model)) + 
  xlim(1, 8)
ggplot(mpg, aes(displ, hwy)) + 
  geom_text(aes(label = model), check_overlap = TRUE) + 
  xlim(1, 8)

png

png

虽然看起来这个功能似乎没有什么用,但是当我们是按优先级顺序对数据进行排序,结果是一个带标签的图形,那么显示的就是重要的树数据点

  • geom_label()是geom_text()的一个替代,它绘制一个文本框文本,当在一些有复制背景图的时候建议使用geom_label()
label <- data.frame(
  waiting = c(55, 80), 
  eruptions = c(2, 4.3), 
  label = c("peak one", "peak two")
)
ggplot(faithfuld, aes(waiting, eruptions)) +
  geom_raster(aes(fill = density)) + 
  geom_label(data = label, aes(label = label))

png

给数据加标签需要注意一下问题:

  • 1.虽然文本标签不会影响绘图,但它仍然需要占一定的位置,此时我们需要调整xlim()和ylim()使得我们的图形美观=
  • 2.如果我们要标记很多数据,我们很难避免数据点重叠,此时使用check_overlap = TRUE有用,但是我们不能控制哪些数据被去除。因此另一个较好的方法在我的R语言数据分析从入门到高级中也介绍过,使用ggrepel包中的geom_text_repel(),会自动避免重叠。
  • 3.有时很难确保文本标签适合您想要的空间。ggfittext包可以实现这一点,其中包括一些函数可以在条形图的列中放置文本标签。
ggplot(mpg, aes(displ, hwy)) + geom_point(colour = "red") + 
ggrepel::geom_text_repel(data = mpg, aes(label = class))
Warning message:
"ggrepel: 164 unlabeled data points (too many overlaps). Consider increasing max.overlaps"

png

🌴7.3 绘制自定义注释

上述我们用文本标记单个点是一种重要的注释,ggplot2软件包还提供了其他方法,可以使用与显示数据相同的几何图形对绘图进行注释。具体如下:

  • geom_text()和geom_label()和上述讲的一样,添加文本
  • geom_rect(),矩形图,其中有xmin,xmax,ymin,ymax参数
  • geom_line(),geom_path()和geom_segment(),所有这些几何图形都有一个arrow参数,可以添加箭头,
  • geom_vline(),geom_hline(),geom_abline(),添加横跨整个绘图范围的参照线

下面我们距离说明一下这些方法的用法,本案例使用economics数据,我们先来看一下economics数据包括哪些变量

head(economics)
A spec_tbl_df: 6 × 6
datepcepoppsavertuempmedunemploy
<date><dbl><dbl><dbl><dbl><dbl>
1967-07-01506.719871212.64.52944
1967-08-01509.819891112.64.72945
1967-09-01515.619911311.94.62958
1967-10-01512.219931112.94.93143
1967-11-01517.419949812.84.73066
1967-12-01525.119965711.84.83018

下面我们绘制一下失业率的时间序列曲线

ggplot(economics, aes(date, unemploy)) + 
  geom_line()

png

假设我们现在想要展示各个总统在任的时候失业率的情况,我们可以先使用geom_rect()引入背景颜色,然后使用geom_vline()引入分隔符,再使用geom_text()添加标签,presidential数据集如下

head(presidential)
A tibble: 6 × 4
namestartendparty
<chr><date><date><chr>
Eisenhower1953-01-201961-01-20Republican
Kennedy 1961-01-201963-11-22Democratic
Johnson 1963-11-221969-01-20Democratic
Nixon 1969-01-201974-08-09Republican
Ford 1974-08-091977-01-20Republican
Carter 1977-01-201981-01-20Democratic
# 选取presidential子集
presidential <- subset(presidential, start > economics$date[1])
ggplot(economics) + 
#使用geom_rect()增加矩形背景
  geom_rect(
    aes(xmin = start, xmax = end, fill = party), 
    ymin = -Inf, ymax = Inf, alpha = 0.2, 
    data = presidential
  )+
#使用geom_vline()增加垂直分割线
geom_vline(
    aes(xintercept = as.numeric(start)),
    data=presidential,
    col = 'grey',alpha=0.5
    )+
#使用geom_text()添加文本标签
geom_text(
    aes(x=start,y=2500,label=name),
    data=presidential,
    size = 3,nudge_x=50
)+
# 使用geom_line()绘制时间序列曲线
  geom_line(aes(date, unemploy)) + 
  scale_fill_manual(values = c("blue", "red")) +#颜色设置
  xlab("date") + 
  ylab("unemployment")

png

这里没有什么新内容:在大多数情况下,在ggplot2中注释绘图是对现有几何图形的直接操作。注意在geom_rect()使用-Inf和Inf作为位置。这些是指绘图的左侧和右侧的限制

  • annotate(),有时候在绘制图形时,我们需要在一个新的数据库上进行绘制,我们可以选择每次绘图先定义这个数据库,但是太繁琐了,我们使用annotate()可以直接实现这一点,annotate()有一个参数是geom,指定我们要添加注释的对象是文本还是点等其他的
yrng <- range(economics$unemploy)
xrng <- range(economics$date)
caption <- paste(strwrap("Unemployment rates in the US have 
  varied a lot over the years", 40), collapse = "\n")

ggplot(economics, aes(date, unemploy)) + 
  geom_line() +
  annotate(
    geom = "text", x = xrng[1], y = yrng[2], 
    label = caption, hjust = 0, vjust = 1, size = 4
  )

png

annotate()函数的便利性在其他情况下也很有用。例如,注释的一种常见形式是通过在主数据集下方绘制不同颜色的较大点来突出显示点的子集。要突出显示subaru制造的车辆,我们可以使用以下内容创建基本绘图:

library(dplyr)
p <- ggplot(mpg, aes(displ, hwy)) +
# 绘制突出点  
geom_point(
    data = filter(mpg, manufacturer == "subaru"), 
    colour = "orange",
    size = 3
  ) +
  geom_point() 

下面我们希望在图形右上侧展示该突出点,使用annotate变得很方便

p + 
  annotate(geom = "point", x = 5.5, y = 40, colour = "orange", size = 3) + 
  annotate(geom = "point", x = 5.5, y = 40) + 
  annotate(geom = "text", x = 5.6, y = 40, label = "subaru", hjust = "left")

png

这种方法的优点是在绘图区域内创建标签,但缺点是标签与它选择的点距离较远,另一种方法是使用不同的几何图形来完成这项工作。我们之前说过,geom_curve()和geom_segment()可用于绘制带箭头的曲线和直线,并可与annotate()结合使用,如下所示:

# 添加直线箭头
p + 
annotate(
geom = "segment", x = 4, y = 35, xend = 2.65, yend = 27, 
 arrow = arrow(length = unit(5, "mm"))
   ) +
annotate(geom = "text", x = 4.1, y = 35, label = "subaru", hjust = "left")

png

注意:annotate(geom=‘segment’) 等价于 geom_segment(),annotate(geom=‘text’)等价于geom_text(),但是使用annotate会相对更灵活,下面我们来验证一下

p + 
geom_segment( x = 4, y = 35, xend = 2.65, yend = 27, 
 arrow = arrow(length = unit(5, "mm"))
   ) +
geom_text(, x = 4.1, y = 35, label = "subaru", hjust = "left")

png

得到的图形一样

🌵7.4 直接在图形内标记分组标签

上面图提供了“直接标记”的示例,其中打印区域本身包含不同组的标签,而不是使用图例。
这通常使绘图更容易阅读,因为它使标签更接近数据。directlabels软件包提供了许多函数是的其更容易实现:

ggplot(mpg, aes(displ, hwy, colour = class)) + 
  geom_point()

ggplot(mpg, aes(displ, hwy, colour = class)) + 
  geom_point(show.legend = FALSE) +
  directlabels::geom_dl(aes(label = class), method = "smart.grid")

png

png

directlabels提供了一系列直接标签的定位方法,我们一般使用smart.grid即可。还有一个ggplot2的拓展包很有意思,ggforce,例如使用geom_mark_ellipse,就可以通过椭圆来选择不同类型的点

ggplot(mpg, aes(displ, hwy)) +
  geom_point() + 
  ggforce::geom_mark_ellipse(aes(label = cyl, group = cyl))

png

  • 还有一个加标签的方法是gghighlight包,用于突出显示绘图中的点或线(或各种不同的几何图形),一般在纵向数据使用的较多
data(Oxboys, package = "nlme")
ggplot(Oxboys, aes(age, height, group = Subject)) + 
  geom_line() + 
  geom_point() + 
gghighlight::gghighlight(Subject %in% 1:3)
Warning message:
"Tried to calculate with group_by(), but the calculation failed.
Falling back to ungrouped filter operation..."
Warning message:
"Tried to calculate with group_by(), but the calculation failed.
Falling back to ungrouped filter operation..."
label_key: Subject

png

🌾7.5 对分面图增加注释

一张好的图胜过1000个字,那么一个好的注释胜过任何技巧。
如果使用得当,注释可以成为帮助读者理解数据的强大工具。
例如,当我们想比较不同方面的数据时。
例如,在下面的图中,很容易看到每个方面之间的关系,但各个方面之间的细微差异不会显现出来:

ggplot(diamonds, aes(log10(carat), log10(price))) + 
  geom_bin2d() + 
  facet_wrap(vars(cut), nrow = 1)

png

下面我们可以考虑增加一条参考线,来比较各个方面的细微区别,由于上述每个方面的2维散点图都显示出明显的线性关系,我们考虑用所有数据的回归曲线作为参考线

# 计算回归系数
coef <- coef(lm(log10(price)~log10(carat), data = diamonds))
ggplot(diamonds, aes(log10(carat), log10(price))) + 
  geom_bin2d() +
  geom_abline(intercept = coef[1], slope=coef[2],col='white',size=3)+
  facet_wrap(~cut, nrow = 1)

png

在这个图中,每个分面图都以相同的回归线显示一个类别的数据。这样可以更容易地相互比较面,因为有共享的参考线比较。

  • 我们有时候希望绘图的每个方面都显示来自单个组的数据,但是在每个分面图中以不显眼的方式绘制完整的数据集,以便于我们进行比较,此时需要对背景进行修改。我们之前的策略是先对所有数据进行绘制,但是调整颜色和透明度,使得其不显眼,再对我们分面组的数据进行绘制这种方法较繁琐gghighlight软件包在这种情况下特别有用:
ggplot(mpg, aes(displ, hwy, colour = factor(cyl))) +
  geom_point() + 
  gghighlight::gghighlight() + 
  facet_wrap(~cyl)

png

可以看出不同的cyl的displ和hwy关系不同

💟文章推荐

如果想了解更多ggplot2数据可视化技巧,欢迎访问下列文章

🌝玩转数据可视化之R语言ggplot2:(三)ggplot2实现将多张图放在一起,包括并排和插图绘制(快速入门)
🌜玩转数据可视化之R语言ggplot2::(四)单一基础几何图形绘制
🌟玩转数据可视化之R语言ggplot2:(五)分组画图
☀️玩转数据可视化之R语言ggplot2:(六)统计变换绘图:包括加权绘图、数据分布图、曲面图、图形重叠处理等

posted @ 2022-08-27 11:08  JOJO数据科学  阅读(3057)  评论(0编辑  收藏  举报