R/ggplot2:从散点图中折叠或移除y轴的线段

Jon*_*Jon 5 r scatter-plot ggplot2

我正在尝试使用ggplot2在R中制作散点图,其中y轴的中间被折叠或移除,因为那里没有数据.我在下面的photoshop中做过,但有没有办法用ggplot创建类似的情节?这是具有连续比例的数据:在此输入图像描述

但我正试图做这样的事情: 在此输入图像描述

这是代码:

ggplot(data=distance_data) +
    geom_point(
        aes(
            x = mdistance,
            y = maxZ,
            shape = factor(subj),
            color = factor(side),
            size = (cSA)
        )
    ) +
    scale_size_continuous(range = c(4, 10)) +
    theme(
        axis.text.x = element_text(colour = "black", size = 15),
        axis.text.y = element_text(colour = "black", size = 15),
        axis.title.x = element_text(colour = "black", size= 20, vjust = 0),
        axis.title.y = element_text(colour = "black", size= 20),
        legend.position = "none"
    ) +
    ylab("Z-score") +
    xlab("Distance")
Run Code Online (Sandbox Code Playgroud)

Sti*_*ibu 8

您可以通过定义坐标转换来完成此操作.标准示例是对数坐标,可以ggplot通过使用来实现scale_y_log10().

但您也可以通过提供trans参数来定义自定义转换函数scale_y_continuous()(并且类似地scale_x_continuous()).为此,您可以使用函数trans_new()scales包.它将变换函数及其逆函数作为参数.

我首先讨论了OP示例的特殊解决方案,然后还展示了如何推广它.

OP的例子

OP希望缩小-2和2之间的间隔.以下定义了一个函数(及其反函数),将该间隔缩小了4倍:

library(scales)
trans <- function(x) {
  ifelse(x > 2, x - 1.5, ifelse(x < -2, x + 1.5, x/4))
}
inv <- function(x) {
  ifelse(x > 0.5, x + 1.5, ifelse(x < -0.5, x - 1.5, x*4))
}
my_trans <- trans_new("my_trans", trans, inv)
Run Code Online (Sandbox Code Playgroud)

这定义了转换.为了看到它的实际效果,我定义了一些示例数据:

x_val <- 0:250
y_val <- c(-6:-2, 2:6)
set.seed(1234)
data <- data.frame(x = sample(x_val, 30, replace = TRUE),
                   y = sample(y_val, 30, replace = TRUE))
Run Code Online (Sandbox Code Playgroud)

我首先绘制它而不进行转换:

p <- ggplot(data, aes(x, y)) + geom_point()
p + scale_y_continuous(breaks = seq(-6, 6, by = 2))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在我使用scale_y_continuous()转换:

p + scale_y_continuous(trans = my_trans,
                       breaks = seq(-6, 6, by = 2))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

如果要进行其他转换,则必须更改和的定义,trans()然后再次inv()运行trans_new().你必须确保这inv()确实是相反的inv().我检查了如下:

x <- runif(100, -100, 100)
identical(x, trans(inv(x)))
## [1] TRUE
Run Code Online (Sandbox Code Playgroud)

一般解决方案

下面的函数定义了一个转换,您可以在其中选择要压缩的区域的下端和上端,以及要使用的因子.它直接返回trans可以在里面使用的对象scale_y_continuous:

library(scales)
squish_trans <- function(from, to, factor) {

  trans <- function(x) {

    # get indices for the relevant regions
    isq <- x > from & x < to
    ito <- x >= to

    # apply transformation
    x[isq] <- from + (x[isq] - from)/factor
    x[ito] <- from + (to - from)/factor + (x[ito] - to)

    return(x)
  }

  inv <- function(x) {

    # get indices for the relevant regions
    isq <- x > from & x < from + (to - from)/factor
    ito <- x >= from + (to - from)/factor

    # apply transformation
    x[isq] <- from + (x[isq] - from) * factor
    x[ito] <- to + (x[ito] - (from + (to - from)/factor))

    return(x)
  }

  # return the transformation
  return(trans_new("squished", trans, inv))
}
Run Code Online (Sandbox Code Playgroud)

此功能现在可用于方便地重做第一部分的绘图:

p + scale_y_continuous(trans = squish_trans(-2, 2, 4),
                       breaks = seq(-6, 6, by = 2))
Run Code Online (Sandbox Code Playgroud)

以下示例显示您可以将刻度压缩到任意位置,这也适用于除点之外的其他geom:

df <- data.frame(class = LETTERS[1:4],
                 val = c(1, 2, 101, 102))
ggplot(df, aes(x = class, y = val)) + geom_bar(stat = "identity") +
  scale_y_continuous(trans = squish_trans(3, 100, 50),
                     breaks = c(0, 1, 2, 3, 50, 100, 101, 102))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

让我最后强调评论中已经提到的其他内容:这种情节可能会产生误导,应谨慎使用!