Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >「R」ggplot2在R包开发中的使用

「R」ggplot2在R包开发中的使用

作者头像
王诗翔呀
发布于 2022-03-30 00:47:54
发布于 2022-03-30 00:47:54
8.5K00
代码可运行
举报
文章被收录于专栏:优雅R优雅R
运行总次数:0
代码可运行

没有特别系统的学习 tidy evaluation 这方面的高级操作,最近有空准备补一补,学习下这方面的知识。

原英文:https://github.com/tidyverse/ggplot2/blob/HEAD/vignettes/ggplot2-in-packages.Rmd

这篇文章是为在包代码中使用ggplot2的包开发人员准备的。在撰写本文时,ggplot2涉及在CRAN上的超过2,000个包和其他地方的更多包!在包中使用ggplot2编程增加了几个约束,特别是如果你想将包提交给CRAN。尤其是在R包中编程改变了从ggplot2引用函数的方式,以及在aes()vars()中使用ggplot2的非标准求值的方式。

引用ggplot2函数

与引用其他包类似,你需要在DESCRIPTION文件下的Imports条目下列出ggplot2,并使用::访问ggplot2提供的函数。(例如, ggplot2::function_name):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mpg_drv_summary <- function() {
  ggplot2::ggplot(ggplot2::mpg) + 
    ggplot2::geom_bar(ggplot2::aes(x = .data$drv)) + 
    ggplot2::coord_flip()
}

如果你经常使用ggplot2,你可能希望将ggplot2的多个函数写入NAMESPACE文件。如果你使用roxygen2[1],那么你可以利用注释代码块 #' @importFrom ggplot2 <one or more object names> (注意,这对数据集mpg不起作用)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#' @importFrom ggplot2 ggplot aes geom_bar coord_flip
mpg_drv_summary <- function() {
  ggplot(ggplot2::mpg) + 
    geom_bar(aes(x = drv)) + 
    coord_flip()
}

即使你的包里使用了很多的ggplot2函数,将ggplot2列入Depends条目或者将它整个导入NAMESPACE(例如,通过#' @import ggplot2)都是不明智的。将ggplot2列入Depends会让你的包在被加载/测试的同时加载ggplot2。这会让其他想要使用你包的人通过::使用你的函数而无需加载它。同样地,导入ggplot2全部450个导出对象到你的命名空间会让分离你的包和ggplot2包的责任变得困难,特别是读者会搞不清这些函数到底来自哪里。

我个人碰到过很多这种情况。有时候在开发R包时为了保证正常运行,不得不将依赖包列入Depdens。实际上,如上所说,这一方面会让使用者懵逼,另一方面会造成开发病毒式感染,既不方便调试错误, 想要使用你的包开发的人又不得不将你的包列入Depends

在包函数中使用 aes()vars()

为了使用ggplot2创建图形,你很可能至少要使用一次aes()函数。如果你的图形使用了分面操作,你可能也会使用vars()用来指向绘图数据。而这两个函数都使用了非标准计算,如果你在包中直接使用它,后面再CMD check的使用会引入一个note。

所有的Error, warning和note都需要解决才能上传到CRAN。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mpg_drv_summary <- function() {
  ggplot(ggplot2::mpg) + 
    geom_bar(aes(x = drv)) + 
    coord_flip()
}
N  checking R code for possible problems (2.7s)
   mpg_drv_summary: no visible binding for global variable ‘drv’
   Undefined global functions or variables:
     drv

这大体又分为3种情况:

  • 你事先已经知道了列名和表达式。
  • 你用字符串向量来表示列名。
  • 由用户指定列名和表达式,而你想要你的函数能够有aes()同样的方式执行非标准计算。

如果你已经像上面的例子一样事先知道了列名,你可以使用来自rlang[2]的代词.data指代你要使用的图层数据。为了避免CMD check抛出note,你需要#' @importFrom rlang .data注释块引入该符号名。(通常你可以通过usethis::use_package_doc()生成包的注释块)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mpg_drv_summary <- function() {
  ggplot(ggplot2::mpg) + 
    geom_bar(aes(x = .data$drv)) + 
    coord_flip()
}

如果你的列名是字符串向量(例如, col = "drv"),使用 .data[[col]] 这种方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
col_summary <- function(df, col) {
  ggplot(df) + 
    geom_bar(aes(x = .data[[col]])) + 
    coord_flip()
}
col_summary(mpg, "drv")

如果列名或者表达式是由用户提供的,你可以以 {{ col }}的方式将其传入aes()vars()。这种tidy eval计算符号会捕捉用户提供的表达式,并将其传递给使用非标准计算的函数,如aes()vars()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
col_summary <- function(df, col) {
  ggplot(df) + 
    geom_bar(aes(x = {{ col }})) + 
    coord_flip()
}
col_summary(mpg, drv)

你可能看到了其他的一些方式可以达到相同的目的,但我们(ggplot2的作者)只会保证上述的用法在未来也是有效的。特别的,不要使用aes_()aes_string(),它们已经过时了,未来的版本中将不再支持。

这里有一些删减,没有特别的意义。

常规任务最佳实践

使用ggplot2可视化一个对象

ggplot2在包中通常用于可视化对象(例如,在一个plot()-风格的函数中)。例如,一个包可能定义了 如下一个S3类用于表达式不同离散值的概率:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mpg_drv_dist <- structure(
  c(
    "4" = 103 / 234,
    "f" = 106 / 234,
    "r" = 25 / 234
  ),
  class = "discrete_distr"
)

R中需要的类都有plot()方法,但想要依赖一个单一的plot()为你的每个用户都提供他们所需要的可视化需求是不现实的。然而,提供一个 plot()用于一个对象的可视化总结帮助用户理解该对象是有帮助的。为了满足你的所有用户,我们建议写一个函数将这个对象转换为一个数据框(如果更加复杂,可以是包含数据框的列表)。一个很好的例子是ggdendro[3],它创建系统树图但同时计算出数据以方便用户干自己想要做的事情。对于上面的例子,函数可能是这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
discrete_distr_data <- function(x) {
  tibble::tibble(
    value = names(x),
    probability = as.numeric(x)
  )
}
discrete_distr_data(mpg_drv_dist)
#> # A tibble: 3 x 2
#>   value probability
#>   <chr>       <dbl>
#> 1 4           0.440
#> 2 f           0.453
#> 3 r           0.107

通常,plot()的使用者调用它是为了它的副作用:它生成一个图形用于展示。这与ggplot()不同,除非交互使用或者显式地调用print(),否则是不是展示的。因为这个原因,ggplot2定义了一个自己的泛型函数autoplot(),调用它会返回一个ggplot()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#' @importFrom ggplot2 autoplot
autoplot.discrete_distr <- function(object, ...) {
  plot_data <- discrete_distr_data(object)
  ggplot(plot_data, aes(.data$value, .data$probability)) +
    geom_col() +
    coord_flip() +
    labs(x = "Value", y = "Probability")
}

一旦定义了 autoplot(),可以接着创建一个plot()方法包含(打印)绘图步骤:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#' @importFrom graphics plot
plot.discrete_distr <- function(x, ...) {
  print(autoplot(x, ...))
}

如果你不懂S3类,实现像plot()或者autoplot()这种泛型是一个不好的实践,因为这限制了包开发者自己控制S3用于实现自己的方法。不应该停止你创建自己的函数可视化对象!

创建一个新的主题

当创建一个新的主题时,从已有主题出发总是好的实践(例如,theme_grey()),然后使用%+replace%替换需要该包的元素。这是一种好的策略,哪怕几乎所有的元素都要替换,如果不这样做会让我们通过添加元素优化主题变得困难。ggthemes[4]包中有很多好的主题作为参考。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#' @importFrom ggplot2 %+replace%
theme_custom <- function(...) {
  theme_grey(...) %+replace% 
    theme(
      panel.border = element_rect(size = 1, fill = NA),
      panel.background = element_blank(),
      panel.grid = element_line(colour = "grey80")
    )
}
mpg_drv_summary() + theme_custom()

在加载包之后计算主题是很重要的。如果没有,则会将主题对象存储在编译后的包的字节码中,而该字节码可能与安装的ggplot2不一致!如果你的包有一个默认的可视化主题,正确的加载方法是使用一个返回默认主题的函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
default_theme <- function() {
  theme_custom()
}
mpg_drv_summary2 <- function() {
  mpg_drv_summary() + default_theme()
}

测试ggplot2输出

我们建议使用vdiffr[5]测试ggplot2的输出,这是一个管理可视化测试案例的工具(这是我们测试ggplot2的方式之一)。如果ggplot2或者你代码的改变对可视化输出引入了改变,当你在本地或者Travis运行测试时会失败。为了使用vdiffr,你需要将testthat[6](通过usethis::use_testthat()初始化)和vdiffr加入DESCRIPTIONSuggests条目。然后,使用 vdiffr::expect_doppleganger(<name of plot>, <ggplot object>)创建一个测试。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
test_that("output of ggplot() is stable", {
  vdiffr::expect_doppelganger("A blank plot", ggplot())
})

ggplot2在Suggests

如果你在包中使用ggplot2,大概率你会想要将它列入Imports。如果你想要将它列入Suggests,那么你不能使用#' @importFrom ggplot2 ...载入函数,但是如果你仍然想要使用ggplot2的像%+replace%这样的中缀操作符号,你可以在函数中进行赋值,然后再使用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
theme_custom <- function(...) {
  `%+replace%` <- ggplot2::`%+replace%`
  
  ggplot2::theme_grey(...) %+replace% 
    ggplot2::theme(panel.background = ggplot2::element_blank())
}

通过,如果你为ggplot2的autoplot()等泛型创建了新的方法,ggplot2应该列入Imports。如果出于一些原因你想要将其保留在Suggests,那么可以利用vctrs::s3_register()仅当ggplot2被安装时才注册你的泛型函数。为了达到这样的目的,你需要拷贝和粘贴vctrs::s3_register()的源代码,以避免引入vctrs[7]作为依赖。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.onLoad <- function(...) {
  if (requireNamespace("ggplot2", quietly = TRUE)) {
    vctrs::s3_register("ggplot2::autoplot", "discrete_distr")
  }
}

参考资料

[1]roxygen2: https://cran.r-project.org/package=roxygen2

[2]rlang: https://rlang.r-lib.org/

[3]ggdendro: https://cran.r-project.org/package=ggdendro

[4]ggthemes: https://cran.r-project.org/package=ggthemes

[5]vdiffr: https://cran.r-project.org/package=vdiffr

[6]testthat: https://testthat.r-lib.org/

[7]vctrs: https://vctrs.r-lib.org/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 优雅R 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
跟着Molecular Systems Biology学作图:R语言ggplot2多图组合到一起
https://www.embopress.org/doi/full/10.15252/msb.202110625
用户7010445
2021/12/09
6690
跟着Molecular Systems Biology学作图:R语言ggplot2多图组合到一起
高阶可视化绘图系统:ggplot2入门
ggplot2是《The Grammar of Graphics》/《图形的语法》中提出了一套图形语法,将图形元素抽象成可以自由组合的要素,类似Photoshop中的图层累加,ggplot2将指定的元素/映射关系逐层叠加,最终形成所图形。更加深入学习ggplot2,请参考《ggplot2: 数据分析与图形艺术》。
1480
2019/07/22
1.9K0
高阶可视化绘图系统:ggplot2入门
从零开始的异世界生信学习 R语言部分 05 作图-1
ggplot2的特殊语法规则:列名不带引号,行末写加号(加号表示不同函数之间的连接)
用户10361520
2023/03/05
8410
独特的箱型图版式,你学会了吗?
ggeconodist是开发者受Economist杂志独特风格的启发,开发的一款与普通绘制的箱型图不同风格的R包。
作图丫
2022/03/29
9720
独特的箱型图版式,你学会了吗?
ggplot2 3.3.0版本更新内容
原来ggplot只有两种scale的类型,即continuous和discrete,在新版本中加了一种新的类型,可以将连续型的数据根据bin变成离散型的。如下所示:
生信编程日常
2020/04/01
7690
ggplot2 3.3.0版本更新内容
目前最全的R语言-图片的组合与拼接
李誉辉,四川大学硕士在读,研究数据分析与可视化,以及网络爬虫。誉辉兄最近出的文章都是很系统的,从R ggplot2的基础讲解到三维数据可视化plot3D,文章都整理讲解得很全面系统,我本人也是很喜欢这样的文章,故而推荐给大家。
生信宝典
2019/09/29
5.7K0
目前最全的R语言-图片的组合与拼接
美美的商务范儿——ggplot2蝴蝶图
一个小案例,使用ggplot2绘制蝴蝶图,在巩固温习条形图坐标轴翻转的同时,重新熟悉一下如何利用grid系统进行版式布局。 原图如下: 该图表思路很简单,就是两个条形图通过坐标轴翻转,使用grid包
数据小磨坊
2018/04/11
1.7K0
美美的商务范儿——ggplot2蝴蝶图
ggplot2画KEGG富集柱形图
在做项目分析的时候遇到过一个问题,就是有个老师想将好几张功能富集结果中的柱状图的横坐标的范围全部调整为一样的,一般画这个柱状图都是用Y叔的clusterprofiler包中的barplot函数对使用这个包的功能富集结果进行一键绘图,超级简单方便。但是当我去查找这个函数的调整坐标的参数时:
生信交流平台
2020/08/05
6.2K0
ggplot2|发散性“正负”图
前面介绍了一些ggplot绘图,ggplot2|从0开始绘制直方图,ggplot2|从0开始绘制箱线图,ggplot2|从0开始绘制折线图,这次介绍一下当数据为发散性正负值的时候,几种比较合适的展示方式。
生信补给站
2020/08/06
1.1K0
阿榜的生信笔记6-R作图
哈喽,我是学习生物信息学的阿榜!非常感谢您能够点击进来查看我的笔记。我致力于通过笔记,将生物信息学知识分享给更多的人。如果有任何纰漏或谬误,欢迎指正。让我们一起加油,一起学习进步鸭? 这份思维导图可以
用户10480134
2023/04/30
6360
ggplot2|详解八大基本绘图要素
ggplot2是由Hadley Wickham创建的一个十分强大的可视化R包。按照ggplot2的绘图理念,Plot(图)= data(数据集)+ Aesthetics(美学映射)+ Geometry(几何对象)。本文将从ggplot2的八大基本要素逐步介绍这个强大的R可视化包。
生信补给站
2020/08/05
7.5K0
ggplot2|详解八大基本绘图要素
ggplot2修改坐标轴详细介绍
ggplot2的每个细节都是可以修改的,非常推荐大家系统学习一下,用到再学确实是一种不错的方式,但是如果要提高进阶,还是有必要系统学习的。
医学和生信笔记
2022/11/15
12.2K0
ggplot2修改坐标轴详细介绍
R绘图-ggplot2 (2)
#这一小节介绍标尺,在对图形属性进行映射之后,使用标尺可以控制这些属性的显示方式,
生信补给站
2020/08/06
9780
R语言绘图之ggplot2包「建议收藏」
6月份一直在忙期末考试,今天来迅速的学习下ggplot2包的简单绘图。 R的基础包里面也有很多画图函数,例如plot();barplot();qqplot(); 但是还有大名鼎鼎的ggplot2包,用这个包的函数画出的图比较漂亮,而且使用灵活。
全栈程序员站长
2022/07/23
2.4K0
R语言绘图之ggplot2包「建议收藏」
全网最全的R语言基础图形合集
直方图是一种对数据分布情况进行可视化的图形,它是二维统计图表,对应两个坐标分别是统计样本以及该样本对应的某个属性如频率等度量。
生信学习者
2024/06/12
1230
全网最全的R语言基础图形合集
gganimate动画GIF | 让你的图形跳动起来!!!
随着互联网+和大数据科技的发展,VFX可视化和数据可视化越来越受到人们的喜爱,在R语言中,绘制GIF动图主要是在gganimate包中运行,制作视频主要是在av包,gganimate是图形语法的扩展,由ggplot2包实现,它增加了对使用ggplot2用户熟悉的API声明动画的支持
黑妹的小屋
2020/08/06
1.8K0
ggplot2绘图
ggplot2 包提供了一个基于全面而连贯的语法的绘图系统。它弥补了 R 中创建图形缺乏一致性的缺点,使得用户可以创建有创新性的、新颖的图形类型。ggplot2 是 R 语言绘图一个重要特性和优势。通过 ggplot2,只需少量的代码,就可以绘制出高质量的图形,满足出版需要。ggplot2 语法简介,逻辑清晰,功能强大,可以快速上手。在 R 语言中自成一派,目前也有越来越多的绘图包基于 ggplot2 进行二次开发,一般都是以“gg”开头,例如 ggpubr,ggtree,ggvis,ggtree,ggstatsplot 等。
生信喵实验柴
2022/10/25
8500
ggplot2散点图直方图条形图
熟悉ggplot2绘图,有一本书,可以介绍大家使用,《R数据可视化手册》第二版
生信喵实验柴
2022/10/25
6090
ggplot2散点图直方图条形图
R 语言柱状图示例笔记
柱状图的介绍就先到这里,其他可替代柱状图的图形包含棒棒糖图(Lollipop)、环形柱状图等未在本文中展开介绍,有兴趣的小伙伴可参考文章最后的参考资料。
章鱼猫先生
2021/10/15
1.7K0
R 语言柱状图示例笔记
跟小洁老师学习R语言的第六天
图片 图片 常用可视化R包 作图 base ggplot2(特殊语法:列名不带引号,行末写加号) 图片 颜色:color 大小:size 形状:shape 图片 透明度:alpha 填充颜色:fill(既有边框又有内心的,才需要color和fill两个参数) 映射和手动设置的区别 图片 自行指定映射的具体颜色 ggplot(data = iris)+ geom_point(mapping = aes(x = Sepal.Length, y = Pe
贝诺酯
2023/03/16
5690
推荐阅读
相关推荐
跟着Molecular Systems Biology学作图:R语言ggplot2多图组合到一起
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验