如何在ggplot中将剪贴蒙版应用于geom?

Hob*_*eep 9 r clipping mask ggplot2 grob

我正在尝试将剪贴蒙版应用于ggplot中的geom以遮盖部分数据,但保持轴,网格,其他geom和图例可见.我不想创建一个特定的情节,因此我不是在寻找一个处理阴影的某些部分的多边形.

这是我想要模仿的设计(面具,不一定是主题,我现在该怎么做):

在一些图层上使用中央圆形剪贴蒙版进行映射

(来源)

另请参见此示例

有人可能会争辩说我可以过滤未定义掩码的多边形中包含的数据.但是,虽然它适用于点,并且可以用于多边形/线状对象,但它适用于栅格(边框不会完全遵循非垂直或非水平线).所以我尝试了以下方法:

library(ggplot2)
library(gridSVG)
library(grImport)

# Create a plot
p <- ggplot(diamonds[1:300,], aes(carat, price)) + geom_point(aes(colour = cut))

# And a clipping mask
pg <- polygonGrob(c(.7, 0, 0, 1, 1),
              c(0, .7, 1, 1, 0))
cp <- clipPath(pg)
Run Code Online (Sandbox Code Playgroud)

我能够使用包gridSVG定义剪贴蒙版,但我必须将它ggplot对象上的困难,甚至提取GROB后(见资源在这里)有ggplotGrob().我无法将剪贴蒙版应用于grob:

g <-  ggplotGrob(p) # store the plot as a grob

registerClipPath("mask", cp)
g_clipped <- clipPath(g)

gridsvg(name = "test_c2.svg")
grid.draw(clipPathGrob(g_clipped, cp)$grob)
dev.off()
Run Code Online (Sandbox Code Playgroud)

我的直觉是g_clipped应该绘制,但我不能grid.draw(),因为它是一个clipPath对象.grid.draw() 这里写的线显示没有掩盖的情节.我想我不太了解clipPath对象的功能.

该功能grobify()听起来有助于替代没有gridSVG的appraoch,请参阅此处的详细信息,但我不明白相当简约的文档.

由于我甚至无法将剪贴蒙版应用于整个情节,所以我的目标远远不够.

如果您可以帮助我了解如何应用剪贴蒙版gridSVG或者有替代解决方案将剪贴蒙版应用于特定的宝石,请告诉我.

San*_*att 2

以下是一个网格解决方案,但很大程度上是一个解决方法。它展示了如何将非矩形剪切区域应用于 ggplot,以便剪切图中的一组点。你的尝试并没有错得太离谱。有几点需要注意:

  1. 您需要grid.force()ggplotGrob 对象,以便可以grid看到 grobs。
  2. 不要将 ggplot grob 定义为剪切路径 - 剪切路径是多边形。
  3. 剪切路径应用于 ggplot 绘图面板内的点集。这意味着绘图面板中的其他对象、面板背景和网格线不会被剪切。仅剪切数据点。

我在图中添加了一条蓝线,以表明该线也不需要被剪裁;但如果需要的话可以剪掉。

还有注释的代码行,当取消注释时,将绘制剪切区域,并将网格线和点移动到前面(即,在深灰色剪切区域的前面)。

library(ggplot2)
library(gridSVG)
library(grid)

# Open the graphics device
gridsvg(name = "test.svg")

# Create a plot
p <- ggplot(diamonds[1:300, ], aes(carat, price)) + 
       geom_point(aes(colour = cut)) +
       geom_line(data = data.frame(x = c(.3, .9), y = c(500, 2500)), aes(x,y), col = "skyblue", size = 2)
g <- ggplotGrob(p) # Store the plot as a grob


g = grid.force(g)  # So that grid sees all grobs
grid.draw(g)       # Draw the plot

# Define the clipping path
pg <- polygonGrob(c(.7, 0, 0, 1, 1),
                  c(0, .7, 1, 1, 0))
# The clipping path can be nearly any shape you desire. 
# Try this for a circular region
# pg = circleGrob(x = .5, y = .6, r = .5)
cp <- clipPath(pg)

# Add the clipping path to the points grob.
# That is, only the points inside the polygon will be visible,
# but the background and grid lines will not be clipped. 
# Nor will the blue line be clipped.
# grid.ls(g)     # names of the grobs
seekViewport(grep("panel.[0-9]", grid.ls(g)$name, value = TRUE))
grid.clipPath("points", cp, grep = TRUE)   

# To clip the blue line, uncomment the next line
# grid.clipPath("GRID.polyline", cp, grep = TRUE)       

# To show the clipping region,    
# uncomment the next two lines.
# showcp = editGrob(pg, gp = gpar(fill = rgb(0, 0, 0, 0.05), col = "transparent"))
# grid.draw(showcp)

# And to move the grid lines, remaining data points, and blue line in front of the clipping region,
# uncomment the next five lines
# panel = grid.get("panel", grep = TRUE)   # Get the panel, and remove the background grob
# panel = removeGrob(panel, "background", grep = TRUE)

# grid.remove("points", grep = TRUE)     # Remove points and grid lines from the rendered plot
# grid.remove("line", grep = TRUE, global = TRUE)

# grid.draw(panel)     # Draw the edited panel - on top of the clipping region 


# Turn off the graphics device
dev.off()

# Find text.svg in your working directory
Run Code Online (Sandbox Code Playgroud)




编辑使用绘制数据点的坐标系定义剪切区域。

library(ggplot2)
library(gridSVG)
library(grid)

# Open the graphics device
gridsvg(name = "test.svg")

# Create a plot
p <- ggplot(diamonds[1:300, ], aes(carat, price)) + 
       geom_point(aes(colour = cut)) +
       geom_line(data = data.frame(x = c(.3, .9), y = c(500, 2500)), aes(x,y), col = "skyblue", size = 2)
g <- ggplotGrob(p) # Store the plot as a grob


g = grid.force(g)  # So that grid sees all grobs
grid.draw(g)       # Draw the plot

# Get axis limits (including any expansion)
axis.limits = summarise_layout(ggplot_build(p))[1, c('xmin', 'xmax', 'ymin', 'ymax')]

# Find the 'panel' viewport,
# then push to a new viewport, 
# one that exactly overlaps the 'panel' viewport,
# but with limits on the x and y scales that are the same
# as the limits for the original ggplot. 
seekViewport(grep("panel.[0-9]", grid.ls(g)$name, value = TRUE))
pushViewport(dataViewport(xscale = axis.limits[1, 1:2],
                          yscale = axis.limits[1, 3:4]))

# Define the clipping path
 pg <- polygonGrob(x = c(.6,   0.3, .3,   .8,   1.2), 
                   y = c(500, 1500, 2900, 2900, 1500), 
                   default.units="native")
cp <- clipPath(pg)

# Add the clipping path to the points grob.
# That is, only the points inside the polygon will be visible,
# but the background and grid lines will not be clipped. 
# Nor will the blue line be clipped.
# grid.ls(g)     # names of the grobs

grid.clipPath("points", cp, grep = TRUE)   

# To clip the blue line, uncomment the next line
 grid.clipPath("GRID.polyline", cp, grep = TRUE)       

# To show the clipping region. 
 showcp = editGrob(pg, gp = gpar(fill = rgb(0, 0, 0, 0.05), col = "transparent"))
 grid.draw(showcp)

# And to move the grid lines and remaining data points in front of the clipping region.
 panel = grid.get("panel", grep = TRUE)   # Get the panel, and remove the background grob
 panel = removeGrob(panel, "background", grep = TRUE)

 grid.remove("points", grep = TRUE)     # Remove points and grid lines from the rendered plot
 grid.remove("line", grep = TRUE, global = TRUE)

 grid.draw(panel)     # Draw the edited panel - on top of the clipping region 


# Turn off the graphics device
dev.off()

# Find text.svg in your working directory
Run Code Online (Sandbox Code Playgroud)