Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >基于 R 语言的科研论文绘图技巧详解(1)

基于 R 语言的科研论文绘图技巧详解(1)

作者头像
庄闪闪
发布于 2022-05-24 07:42:50
发布于 2022-05-24 07:42:50
1.5K00
代码可运行
举报
运行总次数:0
代码可运行

简介

在查阅文献的过程中,看到了几幅非常不错的出版图,今天就跟着小编一起学习下,他们是怎么使用 R 绘制出来的。

今天主要介绍第一幅图(A),初步观察来看,改图是由两张照片合并而成,并且在上面加上了箭头、圆圈,来说明作者想表达的问题。

后面几幅图会一一介绍,读者在学习过程中,可以将内部学到的知识点应用到自己的图形绘制中。

那我们来看看,他是怎么实现这个功能的吧,对应代码可在 GitHub - marco-meer/scifig_plot_examples_R: Scientific publication figure plotting examples with R[1] 可以找到。

主要知识点

  • 学会如何导入图形,并将其并排展示;
  • 学会设置自定义主题,简化代码,统一主题,方便绘制其他图形使用;
  • 学会使用 ggplot2 包内置参数添加文字已经其他其他修饰图标。

绘图

加载包

首先加载一些需要使用到的包。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
library(ggplot2) # Grammar of graphics
library(cowplot) # Arranging multiple plots into a grid
library(png)     # Load JPEG, PNG and TIFF format 
library(scales)  # Generic plot scaling methods
library(viridis) # Default color maps from 'matplotlib'
library(grid)    # A rewrite of the graphics layout capabilities
library(magick)  # graphics and image processing
library(rsvg)    # Render svg image into a high quality bitmap
library(ggforce) # Collection of additional ggplot stats + geoms

设置主题

接下来,为了方便起见,作者在绘图前设置好了主题,并将该函数命名为 my_theme

这个主题并没有在第一幅图中使用,但是在后面几幅图中都会使用,这里先将其展示下。使用方式会在下一篇推文中进行介绍。

手动修改大部分面板,具体可以参考本篇文章[2]。或者观看我在 B 站发布的《R 语言可视化教程》,里面也有一些简单主题设置介绍。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 全局字体大小
base_size = 12 

# 手动修改大部分面板
# documentation: https://ggplot2.tidyverse.org/reference/theme.html
my_theme <-  function() {
  theme(
    aspect.ratio = 1,
    axis.line =element_line(colour = "black"),  
    
    # shift axis text closer to axis bc ticks are facing inwards
    axis.text.x = element_text(size = base_size*0.8, color = "black", 
                               lineheight = 0.9,
                               margin=unit(c(0.3,0.3,0.3,0.3), "cm")), 
    axis.text.y = element_text(size = base_size*0.8, color = "black", 
                               lineheight = 0.9,
                               margin=unit(c(0.3,0.3,0.3,0.3), "cm")),  
    
    axis.ticks = element_line(color = "black", size  =  0.2),  
    axis.title.x = element_text(size = base_size, 
                                color = "black", 
                                margin = margin(t = -5)), 
    # t (top), r (right), b (bottom), l (left)
    axis.title.y = element_text(size = base_size, 
                                color = "black", angle = 90,
                                margin = margin(r = -5)),  
    axis.ticks.length = unit(-0.3, "lines"),  
    legend.background = element_rect(color = NA, 
                                     fill = NA), 
    legend.key = element_rect(color = "black",  
                              fill = "white"),  
    legend.key.size = unit(0.5, "lines"),  
    legend.key.height = NULL,  
    legend.key.width = NULL,      
    legend.text = element_text(size = 0.6*base_size, 
                               color = "black"),  
    legend.title = element_text(size = 0.6*base_size, 
                                face = "bold", 
                                hjust = 0, 
                                color = "black"),  
    legend.text.align = NULL,  
    legend.title.align = NULL,  
    legend.direction = "vertical",  
    legend.box = NULL, 
    panel.background = element_rect(fill = "white", 
                                    color  =  NA),  
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    plot.title = element_text(size = base_size, 
                              color = "black"), 
  ) 
}

绘图步骤详解

由于代码复杂,知识点较多,为了读者更好理解代码逻辑和含义,小编将其分布讲解。最后再将完整代码放到本节末。

导入图片

首先使用 magick 包中的 image_read() 导入两幅图,并通过image_flip()进行转化。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
img1 <- magick::image_flip(magick::image_read("./image1.jpg"))
img2 <-  magick::image_flip(magick::image_read("./image2.png"))

接下来,将两幅图并行合并,放置到一幅图中。这里的代码,小编也是第一次见。通过 grid 包中的 grid.raster() 设置光栅(raster)对象,并使用 annotation_custom()设置摆放位置。这时候得到的结果是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ggplot() +
  annotation_custom(rasterGrob(image =  img1, 
                               x=0.27,
                               y=0.49,
                               width = unit(0.45,"npc"),
                               height = unit(0.87,"npc")), 
                    -Inf, Inf, -Inf, Inf) +
  annotation_custom(rasterGrob(image = img2, 
                               x=0.73,
                               y=0.49,
                               width = unit(0.45,"npc"),
                               height = unit(0.87,"npc")), 
                    -Inf, Inf, -Inf, Inf) 

其他修饰图标

加入修饰图标,来说明问题。主要使用 geom_ellipse() 构建椭圆形,geom_segment() 增加线段(箭头设置,在内部参数 arrow 中)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
geom_ellipse(aes(x0 = 0.25, 
                 y0 = 0.3,
                 a = 0.1, 
                 b = 0.04, 
                 angle = 0),
              color="yellow",
              size=1) +
  scale_x_continuous(limits = c(0,1))+ # 设置 x 轴坐标范围
  scale_y_continuous(limits=c(0,1)) +
  geom_segment(aes(x=0.15,
                   xend=0.2,
                   y=0.75,
                   yend=0.7),
               arrow = arrow(length=unit(0.30,"cm"),
                             ends="last", 
                             type = "closed"),
               size = 1,
               color="white") +
  geom_segment(aes(x=0.3,
                   xend=0.9,
                   y=0.7,
                   yend=0.7),
               arrow = arrow(length=unit(0.30,"cm"),
                             ends="both", 
                             type = "closed"),
               size = 1,
               color="red") 

添加文字

使用 annotate() 添加文字("text"),使用 geom_segment() 添加线段(右下角白色的线段),这里没有设置箭头。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
annotate("text", x = 0.25, y = 0.5, label = "PNG",color="white") +
  annotate("text", x = 0.75, y = 0.5, label = "JPEG",color="white") +
  annotate("text", x = 0.25, y = 1, label = "image 1",color="black") +
  annotate("text", x = 0.75, y = 1, label = "image 2",color="black") +
  annotate("text", x = 0.39, y = 0.07, label = "20~mu*m",color="white",parse=T) +
  annotate("text", x = 0.89, y = 0.07, label = "20~mu*m",color="white",parse=T) +
  geom_segment(aes(x=0.33,xend=0.45,y=0.03,yend=0.03), size = 2,color="white") +
  geom_segment(aes(x=0.83,xend=0.95,y=0.03,yend=0.03),size = 2,color="white") 

这时候得到的结果为:

微调主题

去除主题,并修改图形边界。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  theme_void() +# blank plot w/o axes etc.
  theme(plot.margin = unit(c(-0,0,1,0), "cm"),
        aspect.ratio = 1)

完整代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
library(ggplot2) # Grammar of graphics
library(cowplot) # Arranging multiple plots into a grid
library(png)     # Load JPEG, PNG and TIFF format 
library(scales)  # Generic plot scaling methods
library(viridis) # Default color maps from 'matplotlib'
library(grid)    # A rewrite of the graphics layout capabilities
library(magick)  # graphics and image processing
library(rsvg)    # Render svg image into a high quality bitmap
library(ggforce) # Collection of additional ggplot stats + geoms

# global font size
base_size = 12 

# Manual theme for most panels
# documentation: https://ggplot2.tidyverse.org/reference/theme.html
my_theme <-  function() {
  theme(
    aspect.ratio = 1,
    axis.line =element_line(colour = "black"),  
    
    # shift axis text closer to axis bc ticks are facing inwards
    axis.text.x = element_text(size = base_size*0.8, color = "black", 
                               lineheight = 0.9,
                               margin=unit(c(0.3,0.3,0.3,0.3), "cm")), 
    axis.text.y = element_text(size = base_size*0.8, color = "black", 
                               lineheight = 0.9,
                               margin=unit(c(0.3,0.3,0.3,0.3), "cm")),  
    
    axis.ticks = element_line(color = "black", size  =  0.2),  
    axis.title.x = element_text(size = base_size, 
                                color = "black", 
                                margin = margin(t = -5)), 
    # t (top), r (right), b (bottom), l (left)
    axis.title.y = element_text(size = base_size, 
                                color = "black", angle = 90,
                                margin = margin(r = -5)),  
    axis.ticks.length = unit(-0.3, "lines"),  
    legend.background = element_rect(color = NA, 
                                     fill = NA), 
    legend.key = element_rect(color = "black",  
                              fill = "white"),  
    legend.key.size = unit(0.5, "lines"),  
    legend.key.height =NULL,  
    legend.key.width = NULL,      
    legend.text = element_text(size = 0.6*base_size, 
                               color = "black"),  
    legend.title = element_text(size = 0.6*base_size, 
                                face = "bold", 
                                hjust = 0, 
                                color = "black"),  
    legend.text.align = NULL,  
    legend.title.align = NULL,  
    legend.direction = "vertical",  
    legend.box = NULL, 
    panel.background = element_rect(fill = "white", 
                                    color  =  NA),  
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    plot.title = element_text(size = base_size, 
                              color = "black"), 
  ) 
  
  
}

# Panel A ----

img1 <- magick::image_flip(magick::image_read("./image1.jpg"))
img2 <-  magick::image_flip(magick::image_read("./image2.png"))

panel_A <- ggplot() +
  annotation_custom(rasterGrob(image =  img1, 
                               x=0.27,
                               y=0.49,
                               width = unit(0.45,"npc"),
                               height = unit(0.87,"npc")), 
                    -Inf, Inf, -Inf, Inf) +
  annotation_custom(rasterGrob(image = img2, 
                               x=0.73,
                               y=0.49,
                               width = unit(0.45,"npc"),
                               height = unit(0.87,"npc")), 
                    -Inf, Inf, -Inf, Inf) +
  
  geom_ellipse(aes(x0 = 0.25, 
                            y0 = 0.3,
                            a = 0.1, 
                            b = 0.04, 
                            angle = 0),
                        color="yellow",
                        size=1)+
  scale_x_continuous(limits = c(0,1))+
  scale_y_continuous(limits=c(0,1)) +
  geom_segment(aes(x=0.15,
                   xend=0.2,
                   y=0.75,
                   yend=0.7),
               arrow = arrow(length=unit(0.30,"cm"),
                             ends="last", 
                             type = "closed"),
               size = 1,
               color="white") +
  geom_segment(aes(x=0.3,
                   xend=0.9,
                   y=0.7,
                   yend=0.7),
               arrow = arrow(length=unit(0.30,"cm"),
                             ends="both", 
                             type = "closed"),
               size = 1,
               color="red") +

  annotate("text", x = 0.25, y = 0.5, label = "PNG",color="white") +
  annotate("text", x = 0.75, y = 0.5, label = "JPEG",color="white") +
  annotate("text", x = 0.25, y = 1, label = "image 1",color="black") +
  annotate("text", x = 0.75, y = 1, label = "image 2",color="black") +
  annotate("text", x = 0.39, y = 0.07, label = "20~mu*m",color="white",parse=T) +
  annotate("text", x = 0.89, y = 0.07, label = "20~mu*m",color="white",parse=T) +
  geom_segment(aes(x=0.33,xend=0.45,y=0.03,yend=0.03), size = 2,color="white") +
  geom_segment(aes(x=0.83,xend=0.95,y=0.03,yend=0.03),size = 2,color="white")  + 
  theme_void() +# blank plot w/o axes etc.
  theme(plot.margin = unit(c(-0,0,1,0), "cm"),
        aspect.ratio = 1)

panel_A

小编有话说

本文主要学到的知识点如下:

  1. 使用 magick 包中的 image_read() 导入两幅图,并通过image_flip()进行转化;
  2. 设置自定义主题 my_theme,方便绘制其他图形使用;
  3. 使用 annotate() 添加文字("text"),使用 geom_segment() 添加线段。

参考资料

[1]

GitHub: https://github.com/marco-meer/scifig_plot_examples_R

[2]

文章: https://ggplot2.tidyverse.org/reference/theme.html

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

本文分享自 庄闪闪的R语言手册 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【动手学深度学习笔记】之多层感知机实现
Fashion-MNIST数据集中的图像为28*28像素,也就是由784个特征值。Fashion-MNIST数据集一共有十个类别。因此模型需要784个输入,10个输出。假设隐藏单元为256(超参数,可调节)。
树枝990
2020/08/19
6420
【动手学深度学习笔记】之PyTorch实现多层感知机
上一步最终得到的数据为tensor(x)的形式,为了得到最终的pytorch number,需要对其进行下一步操作
树枝990
2020/08/20
7840
动手学深度学习(三) 多层感知机
深度学习主要关注多层模型。在这里,我们将以多层感知机(multilayer perceptron,MLP)为例,介绍多层神经网络的概念。
致Great
2020/02/24
1.1K0
从零开始学Pytorch(三)之多层感知机的实现
我们将以多层感知机(multilayer perceptron,MLP)为例,介绍多层神经网络的概念。
墨明棋妙27
2022/08/24
1.2K0
从零开始学Pytorch(三)之多层感知机的实现
pytorch学习笔记(十):MLP[通俗易懂]
多层感知机(multilayer perceptron, MLP) 在单层神经网络的基础上引入了一到多个隐藏层(hidden layer)。隐藏层位于输入层和输出层之间。图3.3展示了一个多层感知机的神经网络图,它含有一个隐藏层,该层中有5个隐藏单元。
全栈程序员站长
2022/07/04
1.6K0
pytorch学习笔记(十):MLP[通俗易懂]
多层感知机实现(单层感知器和多层感知器)
前面利用了softmax来对图像进行分类,也可以使用多层感知机的方法对图像进行分类。
全栈程序员站长
2022/07/31
1.2K0
多层感知机实现(单层感知器和多层感知器)
【动手学深度学习笔记】之实现softmax回归模型
设置小批量数目为256。这一部分与之前的线性回归的读取数据大同小异,都是转换类型-->生成迭代器。
树枝990
2020/08/20
8740
【深度学习基础】多层感知机 | 多层感知机的实现
深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重要的技术特征是具有自动提取特征的能力。神经网络算法、算力和数据是开展深度学习的三要素。深度学习在计算机视觉、自然语言处理、多模态数据分析、科学探索等领域都取得了很多成果。本专栏介绍基于PyTorch的深度学习算法实现。 【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/PyTorch_deep_learning。
Francek Chen
2025/01/22
1570
【深度学习基础】多层感知机 | 多层感知机的实现
【动手学深度学习笔记】之PyTorch实现softmax回归
由softmax回归模型的定义可知,softmax回归模型只有权重参数和偏差参数。因此可以使用神经网络子模块中的线性模块。
树枝990
2020/08/20
1.8K0
【动手学深度学习】多层感知机之暂退法问题研究详情
如果更改第一层和第二层的暂退法概率,会发生什么情况?具体地说,如果交换这两个层,会发生什么情况?设计一个实验来回答这些问题,定量描述该结果,并总结定性的结论
SarPro
2024/06/06
1640
【动手学深度学习】多层感知机之暂退法问题研究详情
[MXNet逐梦之旅]练习三·使用MXNetFashionMNIST数据集分类手动实现
[MXNet逐梦之旅]练习三·使用MXNetFashionMNIST数据集分类手动实现 code #%% import sys import time from mxnet import gluon as gl import mxnet as mx from matplotlib import pyplot as plt from mxnet import autograd, nd import numpy as np mnist_train = gl.data.vision.FashionMNIST(r
小宋是呢
2019/06/27
4240
多层感知机
多层感知机就是含有至少一个隐藏层的由全连接层组成的神经网络,且每个隐藏层的输出通过激活函数进行变换,多层感知机的层数个各个隐藏层中隐藏单元个数都是超参数,输出可以通过以下公式计算得出:
村雨遥
2022/06/15
6400
多层感知机
从零开始学Pytorch(四)softmax及其实现
softmax运算符(softmax operator)解决了以上两个问题。它通过下式将输出值变换成值为正且和为1的概率分布:
墨明棋妙27
2022/09/23
1.3K0
【动手学深度学习笔记】之通过丢弃法缓解过拟合问题
除了上一篇文章介绍的权重衰减法,深度学习常用的缓解过拟合问题的方法还有丢弃法。本文介绍倒置丢弃法及其实现。
树枝990
2020/08/19
1K0
动手学深度学习(二) Softmax与分类模型
softmax运算符(softmax operator)解决了以上两个问题。它通过下式将输出值变换成值为正且和为1的概率分布:
致Great
2020/02/24
8480
动手学DL——MLP多层感知机【深度学习】【PyTorch】
加入一个或多个隐藏层+激活函数来克服线性模型的限制, 使其能处理更普遍的函数关系类型,这种架构通常称为多层感知机(multilayer perceptron)。
来杯Sherry
2023/08/10
1.6K0
动手学DL——MLP多层感知机【深度学习】【PyTorch】
机器学习(ML)三之多层感知机
多层感知机深度学习主要关注多层模型,现在以多层感知机(multilayerperceptron,MLP)为例,介绍多层神经网络的概念。隐藏层多层感知机在单层神经网络的基础上引入了一到多个隐藏层
Java架构师必看
2022/01/11
8720
机器学习(ML)三之多层感知机
【现代深度学习技术】循环神经网络05:循环神经网络的从零开始实现
  本节将根据循环神经网络中的描述, 从头开始基于循环神经网络实现字符级语言模型。 这样的模型将在H.G.Wells的时光机器数据集上训练。 和前面语言模型和数据集中介绍过的一样, 我们先读取数据集。
Francek Chen
2025/04/22
1040
【现代深度学习技术】循环神经网络05:循环神经网络的从零开始实现
【现代深度学习技术】卷积神经网络06:卷积神经网络(LeNet)
深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重要的技术特征是具有自动提取特征的能力。神经网络算法、算力和数据是开展深度学习的三要素。深度学习在计算机视觉、自然语言处理、多模态数据分析、科学探索等领域都取得了很多成果。本专栏介绍基于PyTorch的深度学习算法实现。 【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/PyTorch_deep_learning。
Francek Chen
2025/03/12
1750
【现代深度学习技术】卷积神经网络06:卷积神经网络(LeNet)
BN层pytorch实现[通俗易懂]
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/04
3200
推荐阅读
相关推荐
【动手学深度学习笔记】之多层感知机实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验