如何用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
相关产品推荐
相关产品推荐

