R语言 为不同的x轴段创建具有不同长度尺度的“ggplot2”图

unhi4e5o  于 5个月前  发布在  其他
关注(0)|答案(2)|浏览(98)

我想用多个geom_rect对象创建一个ggplot2图。现在,我尝试用两个geom_rect对象创建一个图。我需要x轴的分段是两个“刻度”之一。例如,x轴上0到10之间的物理长度可能是1英寸,而10到20之间的物理长度是0.1英寸。
间隔的实际物理长度(1英寸或0.1英寸)并不重要,但我需要保持它们的比例相同。因此,“0到10的距离”与“10到20的距离”是10:1。
每一个geom_rect对象将恰好占据x轴上的一段,也就是说,第一个geom_rect对象将跨越(在x轴上)0到10的区间,第二个将跨越10到20的区间。
到目前为止,我已经尝试使用ggplot2函数scale_x_continuous和一个自定义转换,这个自定义转换是通过scales包中的trans_new定义的。

boundary <- 10
mt2 <- scales::trans_new(
        name = "my",
        transform = function(position){
            y <- numeric(length(position))
            print(paste0("position: ", position))
            print(paste0("boundary: ", boundary))
            y[position <= boundary] <- position[position <= boundary]
            y[position > boundary] <- boundary + (position[position > boundary] - boundary) / 10
            print(paste("Transformed values:", y))  # Add this line for debugging
            return(y)
        },
        inverse = function(y){
            print(paste("Inverse input values:", y))  # Add this line for debugging
            print(paste0("boundary: ", boundary))
            z <- numeric(length(y))
            z[y <= boundary] <- y[y <= boundary]
            z[y > boundary] <- boundary + (y[y > boundary] - boundary) * 10
            print(paste("Inverse output values:", z))  # Add this line for debugging
            return(z)
        },
        domain = c(0, 20)
    )

个字符
当我运行我的代码时,我看到这样的输出:

[1] "position: 0"
[1] "boundary: 10"
[1] "Transformed values: 0"
[1] "position: 10"
[1] "boundary: 10"
[1] "Transformed values: 10"
[1] "Inverse input values: NA" "Inverse input values: NA"
[1] "boundary: 10"
Error in z[y <= boundary] <- y[y <= boundary] : 
  NAs are not allowed in subscripted assignments


似乎当scale_x_continuous调用变换mt2的逆时,逆函数得到两个NA s的向量作为输入。
你对我如何解决这个问题有什么建议吗?为什么逆运算得到的是c(NA, NA)

axkjgtzd

axkjgtzd1#

看起来你把这件事弄得比它需要的要难得多。你的transobject可以是:

mt2 <- scales::trans_new("my_trans",
  transform = function(x) ifelse(x > 10, (x - 10) / 10 + 10, x),
  inverse   = function(y) ifelse(y > 10, (y - 10) * 10 + 10, y),
  domain    = c(0, 20)
)

字符串
测试,我们有

library(ggplot2)

tibble::tibble(start = c(0, 10), stop = c(10, 20), fill = c('A', 'B')) |>
  ggplot() + 
  geom_rect(aes(xmin = start, xmax = stop, ymin = -1, ymax = 1, fill = fill)) +
  scale_x_continuous(trans = mt2)


的数据
如果您计划经常这样做并更改阈值和压缩因子,则可以定义一个函数,该函数创建一个transm对象,以便在scale_x_continuous中直接调用

trans_vary <- function(threshold, factor, domain) {
  scales::trans_new("my_trans",
    transform = function(x) {
      ifelse(x > threshold, (x - threshold) / factor + threshold, x)
      },
    inverse   = function(y) {
      ifelse(y > threshold, (y - threshold) * factor + threshold, y)
      },
    domain    = domain
  )
}


例如,

tibble(start = c(0, 10), stop = c(10, 20), fill = c('A', 'B')) |>
  ggplot() + 
  geom_rect(aes(xmin = start, xmax = stop, ymin = -1, ymax = 1, fill = fill)) +
  scale_x_continuous(trans = trans_vary(threshold = 5, factor = 5, domain = c(0, 20)))


brqmpdu1

brqmpdu12#

如果数据的预处理对你有用,我们可以创建新的开始和停止,这将遵循你的“转换规模”,然后绘制这些。

library(dplyr)
library(ggplot2)

## data
gt <- tibble::tibble(start = c(0, 10, 20, 30), 
                     stop = c(10, 20, 30, 40), 
                     reg = factor(c(1, 2, 3, 4)))

## scaling factor for your axis
myscale <- 2   # in your case it'd be 10; I chose 2 to better illustrate
boundary <- 10  # width of your rectangles

## creating new starts and stops with the new scale
gt %>% 
  mutate(start_new = c(0, cumsum(boundary/myscale^(seq_len(n()-1) - 1))), 
         stop_new = cumsum(boundary/myscale^(seq_len(n()) - 1))) -> gt_new

## plotting with the new starts and stops
## x-axis labels are based on original values
gt_new %>% 
  ggplot() + 
  geom_rect(aes(xmin = start_new, xmax = stop_new, 
                         ymin = -1, ymax = 1, 
                         fill = reg)) + 
  scale_x_continuous(breaks = unique(c(gt_new$start_new,gt_new$stop_new)), 
                     labels = unique(c(gt_new$start,gt_new$stop)))

字符串
x1c 0d1x的数据
创建于2023-12-12带有reprex v2.0.2

相关问题