You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ggplot2创建X轴分段长度比例不同的绘图?

问题:自定义X轴分段变换时geom_rect绘图报错(NA传入逆函数)

需求概述

需要创建包含两个geom_rect的ggplot2绘图,X轴分两段使用不同长度比例:0-10的物理长度与10-20的比例为10:1(例如0-10占1英寸,10-20占0.1英寸),每个geom_rect对应一个X轴分段。

尝试的代码

自定义变换函数:

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))  # 调试用
            return(y)
        },
        inverse = function(y){
            print(paste("Inverse input values:", y))  # 调试用
            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))  # 调试用
            return(z)
        },
        domain = c(0, 20)
    )

绘图代码:

gt <- tibble::tibble(start = c(0, 10), stop = c(10, 20))
p <- gt |>
    ggplot2::ggplot() + ggplot2::geom_rect(ggplot2::aes(xmin = start, xmax = stop, ymin = -1, ymax = 1))
p + ggplot2::scale_x_continuous(trans = mt2)

报错信息

[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

原因分析

ggplot2在内部计算轴刻度、扩展范围或绘图边界时,可能会传入NA值到变换的逆函数中。原逆函数没有处理NA的情况,当执行z[y <= boundary] <- y[y <= boundary]时,y <= boundary会生成包含NA的逻辑向量,而R不允许用含NA的下标进行赋值操作,因此触发报错。

修复方案

1. 在逆函数中处理NA值

修改逆函数,先对NA值做单独处理,再处理非NA的情况:

boundary <- 10
mt2 <- scales::trans_new(
        name = "my",
        transform = function(position){
            y <- numeric(length(position))
            y[position <= boundary] <- position[position <= boundary]
            y[position > boundary] <- boundary + (position[position > boundary] - boundary) / 10
            return(y)
        },
        inverse = function(y){
            z <- numeric(length(y))
            # 先保留输入中的NA值
            z[is.na(y)] <- NA
            # 筛选非NA的元素进行处理
            non_na_idx <- !is.na(y)
            z[non_na_idx & y[non_na_idx] <= boundary] <- y[non_na_idx & y[non_na_idx] <= boundary]
            z[non_na_idx & y[non_na_idx] > boundary] <- boundary + (y[non_na_idx & y[non_na_idx]] - boundary) * 10
            return(z)
        },
        domain = c(0, 20)
    )

2. 关闭轴范围扩展(可选)

默认情况下ggplot2会对轴范围做少量扩展,可能导致超出自定义变换的domain范围,可通过expand = c(0, 0)关闭扩展,进一步避免异常值:

p + ggplot2::scale_x_continuous(trans = mt2, expand = c(0, 0))

内容的提问来源于stack exchange,提问作者Fred Boehm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 09:30:53