如何使用 ggplot2 在 R 中制作不连续轴?

tas*_*nes 7 r ggplot2

我有一个dat包含两列 1)Month和 2)的数据框 ( ) Value。我想强调一下,箱线图中的 x 轴不是连续的,方法是用 x 轴上的两条有角度的线(在有角度的线之间是空的)中断 x 轴。

示例数据和箱线图

library(ggplot2)
set.seed(321)
dat <- data.frame(matrix(ncol = 2, nrow = 18))
x <- c("Month", "Value")
colnames(dat) <- x
dat$Month <- rep(c(1,2,3,10,11,12),3)
dat$Value <- rnorm(18,20,2)

ggplot(data = dat, aes(x = factor(Month), y = Value)) +
  geom_boxplot() +
  labs(x = "Month") +
  theme_bw() +
  theme(panel.grid = element_blank(),
        text = element_text(size = 16),
        axis.text.x = element_text(size = 14, color = "black"),
        axis.text.y = element_text(size = 14, color = "black"))
Run Code Online (Sandbox Code Playgroud)

理想的数字如下所示。如何在 ggplot 中制作这个不连续轴?

在此输入图像描述

Tje*_*ebo 13

您可以使用ggh4x包装中的延长轴导轨。唉,如果没有类似于用户王志强建议的黑客攻击,你将无法轻松创建“分隔符”

guide_axis_truncated接受向量来定义下树干和上树干。顺便说一句,这也适用于单位,然后你必须在单位函数内传递向量(例如,trunc_lower = unit(c(0,.45), "npc")

library(ggplot2)
library(ggh4x)

set.seed(321)
dat <- data.frame(matrix(ncol = 2, nrow = 18))
x <- c("Month", "Value")
colnames(dat) <- x
dat$Month <- rep(c(1,2,3,10,11,12),3)
dat$Value <- rnorm(18,20,2)

# this is to make it slightly more programmatic
x1end <- 3.45
x2start <- 3.55

p <-
ggplot(data = dat, aes(x = factor(Month), y = Value)) +
  geom_boxplot() +
  labs(x = "Month") +
  theme_classic() +
  theme(axis.line = element_line(colour = "black"))

p +
  guides(x = guide_axis_truncated(
    trunc_lower = c(-Inf, x2start),
    trunc_upper = c(x1end, Inf)
  ))
Run Code Online (Sandbox Code Playgroud)

由reprex 包于 2021 年 11 月 1 日创建(v2.0.1)

下面是用户Zhiqiang Wang 的黑客攻击的进一步进展。您会看到我正在使用简单的三角学来计算线段坐标。为了使角度实际上看起来像函数中定义的那样,您需要设置coord_equal.

# a simple function to help make the segments
add_separators <- function(x, y = 0, angle = 45, length = .1){
  add_y <-  length * sin(angle * pi/180)
  add_x <- length * cos(angle * pi/180)
  ## making the list for your segments
  myseg <- list(x = x - add_x, xend = x + add_x, 
                y = rep(y - add_y, length(x)), yend = rep(y + add_y, length(x)))
  ## this function returns an annotate layer with your segment coordinates
  annotate("segment", 
           x = myseg$x, xend = myseg$xend,
           y = myseg$y, yend = myseg$yend) 
}

# you will need to set limits for correct positioning of your separators
# I chose 0.05 because this is the expand factor by default 
y_sep <- min(dat$Value) -0.05*(min(dat$Value))

p +
  guides(x = guide_axis_truncated(
    trunc_lower = c(-Inf, x2start),
    trunc_upper = c(x1end, Inf)
  )) +
  add_separators(x = c(x1end, x2start), y = y_sep, angle = 70) +
  # you need to set expand to 0
  scale_y_continuous(expand = c(0,0)) +
  ## to make the angle look like specified, you would need to use coord_equal()
  coord_cartesian(clip = "off", ylim = c(y_sep, NA)) 
Run Code Online (Sandbox Code Playgroud)

  • 好的!我还发现了一个快速而肮脏的分隔符黑客:`+ annotate("text", y = -Inf, x = c(x1end, x2start), label = "/") + coord_cartesian(clip = "off")` :) (5认同)

Zhi*_*ang 8

我认为有可能得到你想要的。这可能需要一些工作。

这是你的图表:

library(ggplot2)
set.seed(321)
dat <- data.frame(matrix(ncol = 2, nrow = 18))
x <- c("Month", "Value")
colnames(dat) <- x
dat$Month <- rep(c(1,2,3,10,11,12),3)
dat$Value <- rnorm(18,20,2)

p <- ggplot(data = dat, aes(x = factor(Month), y = Value)) +
  geom_boxplot() +
  labs(x = "Month") +
  theme_bw() +
  theme(panel.grid = element_blank(),
        text = element_text(size = 16),
        axis.text.x = element_text(size = 14, color = "black"),
        axis.text.y = element_text(size = 14, color = "black"))
Run Code Online (Sandbox Code Playgroud)

这是我的努力:

p + annotate("segment", x = c(3.3, 3.5), xend = c(3.6, 3.8), y = c(14, 14), yend = c(15, 15))+
  coord_cartesian(clip = "off", ylim = c(15, 25)) 
Run Code Online (Sandbox Code Playgroud)

得到这样的东西:

在此输入图像描述

如果你想更进一步,可能需要多次尝试才能正确:

p + annotate("segment", x = c(3.3, 3.5), xend = c(3.6, 3.8), y = c(14, 14), yend = c(15, 15))+
  annotate("segment", x = c(0, 3.65), xend = c(3.45, 7), y = c(14.55, 14.55), yend = c(14.55, 14.55)) +
  coord_cartesian(clip = "off", ylim = c(15, 25)) +
  theme_classic()+
  theme(axis.line.x = element_blank())
  
Run Code Online (Sandbox Code Playgroud)

只需用两条新线替换 axis 即可。这是一个粗略的想法,可能需要一些时间才能使其完善。

在此输入图像描述