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

如何在R的grid包中组合grob以创建闭合可填充图形?

问题描述

我正在编写一个ggplot2扩展,过程中尝试用grid包创建填充形状,其中部分边由functionGrob定义。我不清楚如何将grob树转换为闭合形状以进行填充。我查阅了《R Graphics v3》但没有找到解决方法,想了解这在grid中是否可行?或是在gridSVG或gridGeometry中可行?

以下是最简示例:

library(grid)
grid.newpage()
pushViewport(viewport(xscale=c(0, 2*pi), yscale=c(0,1.1), default.units = "native"))
bottom <- linesGrob(x=c(pi/4, (3/4)*pi), y=c(0.1, 0.1), default.units = "native")
top <- functionGrob(function(x) list(x=x, y=sin(x)),
             range=c(pi/4, 3*pi/4))
right <- linesGrob(x=c(3*pi/4, 3*pi/4), y=c(0.1, sin(pi/4)), default.units = "native")
left <- linesGrob(x=c(pi/4, pi/4), y=c(sin(pi/4), 0.1), default.units = "native")
all <- grobTree(bottom,right,top,left)

grid.fill(all, gp=gpar(fill=rgb(1,0,0)))             # 仅填充了正弦曲线的路径
grid.stroke(all, gp=gpar(lwd = 2, col=rgb(0,1,0)))   # 所有路径被描边

目前grid.fill是对每个grob单独填充,而非组合形成的闭合形状。我要绘制的图形更复杂,无法简单通过组合functionGrob和rectGrob来填充。

解决方案

方法一:手动合并坐标生成闭合路径Grob

grid本身无法直接将grob树中的多个独立路径合并为单一闭合区域,但可以通过提取所有路径的坐标,按闭合顺序拼接后生成pathGrob来实现填充:

library(grid)
grid.newpage()
pushViewport(viewport(xscale=c(0, 2*pi), yscale=c(0,1.1), default.units = "native"))

# 生成functionGrob对应的坐标序列(用足够多的点保证曲线平滑)
x_range <- c(pi/4, 3*pi/4)
x_seq <- seq(x_range[1], x_range[2], length.out = 200)
top_y <- sin(x_seq)

# 按闭合顺序拼接所有边的坐标:左竖边起点 → 顶部曲线 → 右竖边 → 底部横边 → 回到起点
path_x <- c(
  x_range[1],          # 左竖边顶端
  x_seq,               # 顶部曲线x坐标
  x_range[2],          # 右竖边顶端
  x_range[2],          # 右竖边底端
  x_range[1],          # 左竖边底端
  x_range[1]           # 回到起点闭合
)
path_y <- c(
  sin(x_range[1]),     # 左竖边顶端y值
  top_y,               # 顶部曲线y坐标
  sin(x_range[2]),     # 右竖边顶端y值
  0.1,                 # 右竖边底端y值
  0.1,                 # 左竖边底端y值
  sin(x_range[1])      # 回到起点闭合
)

# 创建闭合路径Grob并绘制
filled_shape <- pathGrob(
  x = path_x, y = path_y,
  default.units = "native",
  gp = gpar(fill = rgb(1,0,0), col = rgb(0,1,0), lwd = 2)
)
grid.draw(filled_shape)

这种方法的核心是将所有边的坐标按顺时针/逆时针的闭合顺序拼接,确保路径首尾相连,这样pathGrob就能识别为单一闭合区域进行填充。

方法二:使用gridGeometry包合并图形

如果图形过于复杂,手动提取坐标难度大,可以借助gridGeometry包的多边形处理功能,将多个grob转换为多边形后合并:

library(grid)
library(gridGeometry)
grid.newpage()
pushViewport(viewport(xscale=c(0, 2*pi), yscale=c(0,1.1), default.units = "native"))

# 定义原grob树
bottom <- linesGrob(x=c(pi/4, (3/4)*pi), y=c(0.1, 0.1), default.units = "native")
top <- functionGrob(function(x) list(x=x, y=sin(x)), range=c(pi/4, 3*pi/4))
right <- linesGrob(x=c(3*pi/4, 3*pi/4), y=c(0.1, sin(pi/4)), default.units = "native")
left <- linesGrob(x=c(pi/4, pi/4), y=c(sin(pi/4), 0.1), default.units = "native")
all <- grobTree(bottom, right, top, left)

# 将grob转换为多边形(需先渲染grob获取坐标)
grid.draw(all)
polys <- grobToPolygons(all)

# 合并多边形为单一闭合区域(需确保多边形能组成闭合形状)
merged_poly <- polyclipGrob(polys, op = "union")

# 绘制合并后的填充形状
grid.fill(merged_poly, gp = gpar(fill = rgb(1,0,0)))
grid.stroke(merged_poly, gp = gpar(lwd = 2, col = rgb(0,1,0)))

注意:grobToPolygons需要先绘制grob才能提取坐标,且合并效果依赖于原grob的路径是否能形成连续的闭合边界,复杂场景下可能需要调整参数。

关于gridSVG

gridSVG主要用于将grid图形导出为SVG格式,本身并不直接提供合并路径填充的功能,因此更推荐上述两种方法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:40:26