Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >116-R可视化36-把你长长的坐标轴弄短

116-R可视化36-把你长长的坐标轴弄短

作者头像
北野茶缸子
发布于 2022-04-05 07:37:28
发布于 2022-04-05 07:37:28
1.3K00
代码可运行
举报
运行总次数:0
代码可运行
  • 参考:
    • Line segments and curves — geom_segment • ggplot2 (tidyverse.org)[1]

前言

最近发现一张有意思的umap 图:

看起来,比传统的umap 好看一点?

正好来复习一下前面[[111-R可视化35-结合grid与ggplot输出]] 的用法。

这里可以用任意的umap 结果作为绘图输入。

准备工作

我们先来把ggplot 给“脱光”:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pacman::p_load(ggplot2, tidyverse, grid)

median_df <- cell_reduction_df %>% group_by(cell_anno) %>%
  summarise(median.1 = median(UMAP_1),
            median.2 = median(UMAP_2))
(p1 <- ggplot() + scattermore::geom_scattermore(data = cell_reduction_df,
                                               aes_string(x = "UMAP_1", y = "UMAP_2", 
                                                          color = "cell_anno")) + 
  theme_bw() +
  theme(
    panel.grid = element_blank(),
    plot.background = element_blank(),
    panel.border = element_blank(),
    plot.title = element_text(hjust = 0.5,
                              size = 16),
    axis.ticks = element_blank(),
    axis.line = element_blank(),
    axis.text = element_blank(),
    legend.title = element_blank(),
    legend.text = element_text(size = 12)
  ) +
  labs(title = "Example_Umap", x = NULL, y = NULL)  + 
  guides(color = "none")
  + ggrepel::geom_text_repel(data = median_df,
             aes(median.1,
                 median.2, label = cell_anno),
             min.segment.length = 0, size = 5))

ggplot 自带方法

主要利用的是ggplot 自带的geom_segment 方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
umap1_range <- range(cell_reduction_df$UMAP_1)
umap2_range <- range(cell_reduction_df$UMAP_2)
segment.df <- data.frame(x=c(umap1_range[1] - 2, umap1_range[1] - 2),
                         xend=c(umap1_range[1] + 5, umap1_range[1] - 2),
                         y=c(umap2_range[1] - 2, umap2_range[1] - 2),
                         yend=c(umap2_range[1] - 2, umap2_range[1] + 5))
ggplot() + geom_segment(data = segment.df, 
                        mapping = aes(x=x,xend=xend,
                                      y=y,yend=yend), 
                        arrow = arrow(length=unit(0.3, "cm")),size=1)

得到了等长的线段。

这时候直接把这个geom_segment结果添加到原本的ggplot 图层上:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p1 + geom_segment(data = segment.df, 
                  mapping = aes(x=x,xend=xend,
                                y=y,yend=yend), 
                  arrow = arrow(length=unit(0.3, "cm")),size=1)

可见这个segment 映射到umap 的结果里,画出来的感觉就非常奇怪了。二者的长度忽然并不相等了。

我们来看看umap 坐标的范围:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
> range(cell_reduction_df$UMAP_1)
[1] -7.486754 11.550125
> range(cell_reduction_df$UMAP_2)
[1] -11.96239  15.23803

umap1的长度为18左右,而umap2 则为26左右。而因为二者的长度并不相同,如果在图上显示等长的线段,因为比例的差异,UMAP_1 上显示的长度相对较长,就会让我们错以为二者并非是等长的。

首先计算二者的长度:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
> umap1_len <- max(cell_reduction_df$UMAP_1)-min(cell_reduction_df$UMAP_1)
> umap2_len <- max(cell_reduction_df$UMAP_2)-min(cell_reduction_df$UMAP_2)
> umap1_len
[1] 19.03688
> umap2_len
[1] 27.20042

然后计算其比值,让其中一组segment数据乘这个比值,就可以让它们在同一比例下变化了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
segment.df <- data.frame(x=c(umap1_range[1] - 2, umap1_range[1] - 2),
                         xend=c(umap1_range[1] - 2 + 7*umap_prop, umap1_range[1] - 2),
                         y=c(umap2_range[1] - 2, umap2_range[1] - 2),
                         yend=c(umap2_range[1] - 2, umap2_range[1] + 5))

不难发现,这个方法还是蛮麻烦的。

而且如果我想要给小坐标图坐标轴加点文字,就得用geom_text 在坐标里寻找它们的位置了。

如果是拼图呢?

可直接拼接的话,是没有办法得到这种覆盖的效果。

把图层叠加上去

在[[111-R可视化35-结合grid与ggplot输出]] 我们提过结合不同输出的各种方法,同时也提到了可以通过annotation_custom 或是grid_panel的方法直接实现不同ggplot 图层的叠加:

但问题是,这种方法是无法在坐标框以外的位置添加的。

看来只能是使用newpage = F 的思路。

因为只需要把新的图层堆上去,我们也无需有坐标长度的负担,直接建立一个 1,1 长度的segment 即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
segment.df <- data.frame(x=c(0,0),
                         xend=c(1,0),
                         y=c(0,0),
                         yend=c(0,1))

(p2 <- ggplot() + geom_segment(data = segment.df, 
                              mapping = aes(x=x,xend=xend,
                                            y=y,yend=yend), 
                              arrow = arrow(length=unit(0.3, "cm")),size=1) + 
  theme_bw() +
  theme(
    panel.grid = element_blank(),
    plot.background = element_blank(),
    panel.border = element_blank(),
    axis.ticks = element_blank(),
    axis.line = element_blank(),
    axis.text = element_blank(),
    axis.title = element_text(size = 30)
  ) + labs(x = "UMAP1", y = "UMAP2"))

先让字稍微大点吧,防近视。

其实这里x,y 距离看着蛮难受的,但反正p2 是用来堆上去的。无所谓。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
segment.df <- data.frame(x=c(0,0),
                         xend=c(1,0),
                         y=c(0,0),
                         yend=c(0,1))

(p2 <- ggplot() + geom_segment(data = segment.df, 
                              mapping = aes(x=x,xend=xend,
                                            y=y,yend=yend), 
                              arrow = arrow(length=unit(0.3, "cm")),size=1) + 
  theme_bw() +
  theme(
    panel.grid = element_blank(),
    plot.background = element_blank(),
    panel.border = element_blank(),
    axis.ticks = element_blank(),
    axis.line = element_blank(),
    axis.text = element_blank(),
    axis.title = element_text(size = 10)
  ) + labs(x = "UMAP1", y = "UMAP2"))

p1
md_inset <- viewport(x = 0.02, y = 0.02, 
                     just = c("left", "bottom"),
                     width = 0.15, height = 0.15)
pushViewport(md_inset)
print(p2, newpage = F)

不过这个也有问题,如果存在细胞分群在下面的位置呢?

直接压上去似乎也并不好看。

改善一下位置

其实使用[[57-R可视化6-ggplot2三部曲最终之进阶为菜鸟]] 就多次提及的coord_cartesian 调整坐标轴的操作即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
expand_y <- c(umap2_range[1]*1.3,umap2_range[2])
expand_x <- c(umap1_range[1]*1.3,umap2_range[2])
pp1 <- p1 + theme_bw()
pp2 <- p1 + coord_cartesian(ylim = expand_y, xlim = expand_x) + theme_bw()
cowplot::plot_grid(pp1, pp2)

这位置不就空出来给segment 了吗?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p1_expand <- p1 + coord_cartesian(ylim = expand_y, xlim = expand_x)
(p2 <- ggplot() + geom_segment(data = segment.df, 
                               mapping = aes(x=x,xend=xend,
                                             y=y,yend=yend), 
                               arrow = arrow(length=unit(0.3, "cm")),size=1) + 
    theme_bw() +
    theme(
      panel.grid = element_blank(),
      plot.background = element_blank(),
      panel.border = element_blank(),
      axis.ticks = element_blank(),
      axis.line = element_blank(),
      axis.text = element_blank(),
      axis.title = element_text(size = 10)
    ) + labs(x = "UMAP1", y = "UMAP2"))

p1_expand
md_inset <- viewport(x = 0.02, y = 0.02, 
                     just = c("left", "bottom"),
                     width = 0.15, height = 0.15)
pushViewport(md_inset)
print(p2, newpage = F)

唯一的麻烦就在于,不能快乐的使用ggsave 保存对象了。

似乎左下角的箭头被遮住了似的。

用图层叠放函数方法

反正坐标空隙都已经出来了,即使是在坐标轴的图层位置叠放,也不难看的。

再尝试一下annotation_custom 方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(p2 <- ggplot() + geom_segment(data = segment.df, 
                               mapping = aes(x=x,xend=xend,
                                             y=y,yend=yend), 
                               arrow = arrow(length=unit(0.3, "cm")),size=1) + 
   theme_bw() +
   theme(
     panel.grid = element_blank(),
     plot.background = element_blank(),
     panel.border = element_blank(),
     axis.ticks = element_blank(),
     axis.line = element_blank(),
     axis.text = element_blank(),
     axis.title = element_text(size = 10)
   ) + labs(x = "UMAP1", y = "UMAP2"))
p2 <- ggplotGrob(p2)

p1_expand <- p1 + coord_cartesian(ylim = expand_y, xlim = expand_x)
(p_all <- p1_expand + annotation_custom(p2,                        xmin=0.02,xmax=0.17,ymin=0.02,ymax=0.17))

似乎annotation_custom 并不吃这一套。

而没有位置参数的grid_panel 也吃瘪了。

拆成grob是我最后的倔强

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(p1_expand <- p1 + coord_cartesian(ylim = expand_y, xlim = expand_x))
md_inset <- viewport(x = 0.02, y = 0.02, 
                     just = c("left", "bottom"),
                     width = 0.15, height = 0.15)
pushViewport(md_inset)
grid.draw(ggplotGrob(p2))

另外也发现,上面的箭头遮挡问题,仅仅是Rstudio 预览视图的相对压缩造成的。

所以newpage 方法,也没问题。

其他包

之前也看过一个 magick 包。

The magick package: Advanced Image-Processing in R • magick (ropensci.org)[2]

直接从图片而非绘图对象的层面把内容添加上去:

也是一个比较自由的解决方案。

实在不行,还是ppt吧

你懂我意思吧。

好久没有像今天这样专注于写推送了,真快乐。

参考资料

[1]

Line segments and curves — geom_segment • ggplot2 (tidyverse.org): https://ggplot2.tidyverse.org/reference/geom_segment.html

[2]

The magick package: Advanced Image-Processing in R • magick (ropensci.org): https://docs.ropensci.org/magick/articles/intro.html

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

本文分享自 北野茶缸子 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
RGB格式详解(三)-----RGB像素格式
根据RGB565的存储方式,即可得到获取R,G,B分量的值。现假设计算机中存储某一个像素点的变量为color, 数据类型为short. 那么则有:
视界音你而不同
2020/04/10
5.9K1
RGB格式详解(三)-----RGB像素格式
UGL之颜色表
计算机里通常使用RGB色彩模式,例如RGB565,就是用两个字节表示一个像素的颜色,其中红绿蓝分别用5、6、5个bit。还有一些RGB555、RGB666、ARGB4444之类的。而所谓的真彩色,使用4个字节表示一个像素,通常是RGB888,或者ARGB8888,其中A的全称是Alpha通道,指的是透明度 WindML5的显卡驱动基本都已经支持RGB888的真彩色
Taishan3721
2020/01/02
1.4K0
【专业技术】图像格式转化规律探秘
存在问题: 搞视频编解码的童鞋对此深刻理解,但是好多小伙伴在andriod或其他嵌入上做启动动画时候图像是如何转化存在一定的疑惑。 解决方案: 针对这些问题我们来简单了解了解。 在视频等相关的应用中,YUV是一个经常出现的格式。本文主要以图解的资料的形式详细描述YUV和RGB格式的来由,相互关系以及转换方式,并对C语言实现的YUV转为RGB程序进行介绍。 人类眼睛的色觉,具有特殊的特性,早在上世纪初,Young(1809)和 Helmholtz(1824)就提出了视觉的三原色学说,即:视网膜存在三种视锥细胞
程序员互动联盟
2018/03/15
8550
【专业技术】图像格式转化规律探秘
色彩空间RGB/CMYK/HSL/HSB/HSV/Lab/YUV基础理论及转换方法:RGB与YUV
之前做个设计,现在从事IT,脑子里面关于RGB,RGBA,CMY,CMYK,YUV,但是具体理论还是不扎实。若干年前之前写过《水煮RGB与CMYK色彩模型—色彩与光学相关物理理论浅叙》《三色视者与四色视者身后的理论基础:色彩原理》
周陆军博客
2023/04/22
1K0
常见图像格式总结
raw数据是sensor输出的原始数据,一般有raw8, raw10, raw12等,分别表示一个像素点有8bit、10bit、12bit数据。是sensor将光信号转化为电信号时的电平高低的原始记录,单纯地没有进行任何处理的图像数据,即摄像元件直接得到的电信号进行数字化处理而得到的。
刘盼
2023/09/11
2.6K0
常见图像格式总结
Camera驱动 | YUV和RGB格式转化相关
RGB的分类相较YUV来说就比较简单和直观,总体来说遵循“怎么取样就怎么存储的”分类方式
Abalone
2022/10/05
6330
Camera驱动 | YUV和RGB格式转化相关
RGB格式详解(二)----RGB索引格式
关于调色板,可以简单理解为通过编号映射到颜色的一张二维表。如01索引,表示红色。采用索引格式的RGB,红色的像素对应存储的值便是索引01.
视界音你而不同
2020/04/10
1.7K0
深入探索视频帧中的颜色空间—— RGB 和 YUV
接触前端音视频之后,需要掌握大量音视频和多媒体相关的基础知识。在使用 FFmpeg + WASM 进行视频帧提取时,涉及到视频帧和颜色编码等相关概念。本文将对视频帧中的颜色空间进行介绍。 一、视频帧 对于视频,我们都知道是由一系列的画面在一个较短的时间内(通常是 1/24 或 1/30 秒)不停地下一个画面替换上一个画面形成连贯的画面变化。这些画面称之为视频帧。 对于视频帧,在现代视频技术里面,通常都是用 RGB 颜色空间或者 YUV 颜色空间的像素矩阵来表示。在 ffmpeg 里面,我们可以看到源码 li
用户1097444
2022/06/29
2.1K0
深入探索视频帧中的颜色空间—— RGB 和 YUV
浅谈彩色图像、灰度图像、二值图像和索引图像区别
彩色图像:每个像素由R、G、B三个分量表示,每个通道取值范围0~255。数据类型一般为8位无符号整形。
种花家的奋斗兔
2020/11/12
6.1K0
UGL之颜色处理
计算机里通常使用RGB色彩模式,例如RGB565,就是用两个字节表示一个像素的颜色,其中红绿蓝分别用5、6、5个bit。还有一些RGB555、RGB666、ARGB4444之类的。而所谓的真彩色,使用4个字节表示一个像素,通常是RGB888,或者ARGB8888,其中A的全称是Alpha通道,指的是透明度
Taishan3721
2021/11/04
1.1K0
数字视频基础知识---颜色空间
在显示器发明之后,从黑白显示器发展到彩色显示器,人们开始使用发出不同颜色的光的荧光粉(CRT,等离子体显示器),或者不同颜色的滤色片(LCD),或者不同颜色的半导体发光器件(OLED和LED大型全彩显示牌)来形成色彩,无一例外的选择了Red,Green,Blue这3种颜色的发光体作为基本的发光单元。通过控制他们发光强度,组合出了人眼睛能够感受到的大多数的自然色彩。 不过这里面的YUV TO RGB的算法,效率实在是低,因为里面有了浮点运算,解一帧176*144的图像大概需要400ms左右,这是无法忍受的,如果消除浮点运算,只需要10ms左右,效率的提升真是无法想象.所以大家还是避免在手机上面进行浮点运算.
lcyw
2022/06/10
7800
数字视频基础知识---颜色空间
LCD屏幕操作原理_嵌入式Linux
在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。Frame 是帧的意思,buffer 是缓冲的意思,这意味着 Framebuffer 就是一块内存,里面保存着一帧图像。Framebuffer 中保存着一帧图像的每一个像素颜色值,假设 LCD 的分辨率是 1024x768,每一个像素的颜色用 32 位来表示,那么 Framebuffer 的大小就是:
韦东山
2022/05/05
2.5K0
LCD屏幕操作原理_嵌入式Linux
音视频平凡之路之YUV像素介绍
了解过计算机图形图像学的同学应该知道,有两种方式表示图像,RGB和YUV,视频由一帧一帧的图像组成,每一张图片是由一个一个的像素点组成,既然有两种表示像素的方法,那肯定要了解一下两种表示方式的异同以及优缺点。
马上就说
2020/11/11
1.2K0
ffmpeg 生成高质量 gif
GIF(Graphics Interchange Format)是网络中常见的一种图像交互格式,普遍用于表情包。GIF 有很多特点:
xiaoxia
2024/11/29
7190
HDR关键技术:色度学,颜色空间及转换
HDR技术的第二个理论基础是色度学。从前面的文章中我们了解到,光学以及人类视觉感知模型为人类提供了解释与分析人类感知亮度的理论基础,但是HDR技术不仅仅关注于提升图像与视频的亮度范围,同时也关注于提供更加丰富的色彩。因此,在本文中,我们将首先介绍人眼与色度学相关的生理特征以及人类对颜色的识别方式,然后介绍颜色空间的概念,最后再回到HDR,介绍与HDR相关的颜色标准。
用户1324186
2018/09/21
5.3K0
HDR关键技术:色度学,颜色空间及转换
色彩空间与像素格式
颜色是不同波长的光对人眼刺激产生的色彩感觉。色彩空间(Color Space)是颜色的数学表示,根据不同的表示方法分为不同的色彩模型。最常用的色彩模型有三类:RGB(用于计算机图形学), YUV(用于视频系统), CMYK(用于彩色印刷)。后文对色彩空间与色彩模型的叫法不作区分。本文仅讨论视频图像处理领域常用的RGB色彩空间和YUV色彩空间。
叶余
2019/04/02
1.3K0
色彩空间与像素格式
CSS3的颜色特性
CSS3颜色特性 “佛靠金装,人靠衣装”,网页也是如此。随着互联网的迅速发展,一个网页给人们留下的第一印象,既不是它的内容,也不是它的设计, 而是整体颜色。为了能够达到人们的需求,Web设计师除了需要掌握网站制作的技术之外,还必须能够很好地应用 Web颜色。换句话说,网站颜色的使用好坏, 直接影响网站的生存力。 网页色彩的表现原理: 我们知道有256种Web安全颜色,其实这256种颜色是指8位颜色的表现能力,随着科技的发展,现在颜色不局限于8位,16位色彩的总数是65536色,也就是2的16次方,而新增了24位元色彩,也就是2的24次方,即16777216种颜色。32位色就是2的32次方的发色数,即16777216种颜色,不过它增加了256阶颜色的灰度。 32位色和16位色肉眼分辨不出来吗? 如果用两台品牌型号都一样 的显示器, 分别调不同的颜色, 就能看出区别。 而在Web页面的设计中, 颜色主要运用16 进制数值的表示方法, 为了用HTML表现RGB颜色, 使用十六进制数 0 ~ 255, 改为十六进制就是 00 ~ FF, 用RGB的顺序罗列就成为HTML颜色编码。 例如, 在 HTML 编码中“ 000000” 就是指红色( R)、绿色( G) 和蓝色( B) 都没有,就是0状态,也就是黑色。相反“ FFFFFF” 就是就是 红色( R)、 绿色( G) 和蓝色( B)都是 255,也就是白色。显示器是由一个个像素构成,利用电子束来表现色彩。像素把光的三原色: 红色( R)、绿色( G)、蓝色( B) 组合成的色彩 按照科学原理表现出来。 一 像素包含 8 位元色彩的信息量, 有 从 0 ~ 255 的256个单元, 其中 0 是 完全 无光 状态, 255 是最 亮 状态。
py3study
2020/01/09
1.3K0
色彩空间RGB/CMYK/HSL/HSB/HSV/Lab/YUV基础理论及转换方法:RGB与YUV
之前做个设计,现在从事IT,脑子里面关于RGB,RGBA,CMY,CMYK,YUV,但是具体理论还是不扎实。若干年前之前写过《水煮RGB与CMYK色彩模型—色彩与光学相关物理理论浅叙》《三色视者与四色视者身后的理论基础:色彩原理》
周陆军
2019/08/11
4.6K0
Android高效内存2:让图片占用尽可能少的内存
Android高效内存:让图片占用尽可能少的内存 一、让你的图片最小化 1.1 大图小图内存使用情况对比 大图:440 * 336    小图:220 * 168 资源目录:xhdpi 小图的高宽都是
用户1155943
2018/01/04
1.8K0
Android高效内存2:让图片占用尽可能少的内存
色彩知识
色深用 2 的幂指数来表示,bit 数愈高,色深值便愈高,影像所能表现的色彩也愈多。
Kiba518
2020/07/21
2.3K0
推荐阅读
相关推荐
RGB格式详解(三)-----RGB像素格式
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验