如何将剪贴蒙版应用到 ggplot 中的几何图形?
How to apply a clipping mask to geom in a ggplot?
我正在尝试将剪贴蒙版应用于 ggplot 中的几何图形以屏蔽部分数据,但保持轴、网格、其他几何图形和图例可见。我不想创建一个特定的情节,因此我不是在寻找使用多边形掩盖情节的某些部分的解决方法。
这是我想效仿的设计(遮罩,不一定是主题,我现在该怎么做):
(source)
另见 this example
有人可能会争辩说我可以过滤不包含在定义掩码的多边形中的数据。但是,虽然它适用于点,并且可以适用于 polygon/line-like 对象,但它适用于栅格(边界不会完全遵循非垂直或非水平线)。
所以我尝试了以下方法:
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)
我能够使用包 gridSVG
定义 clipping mask, but I have difficulties applying it on a ggplot object, even after extracting the grob (see resource here) 和 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()
我的直觉是应该绘制 g_clipped
,但我不能 grid.draw()
,因为它是一个 clipPath 对象。还有 grid.draw()
此处写的行显示未屏蔽的情节。我想我不太了解 clipPath 对象的功能。
函数 grobify()
听起来它可以帮助替代没有 gridSVG 的方法,请参阅 details here,但我不理解非常简约的文档。
由于我什至无法将剪贴蒙版应用于整个情节,所以我的 objective。
如果您可以帮助我了解如何应用 gridSVG
中的剪贴蒙版,或者有其他解决方案可以将剪贴蒙版应用于特定几何体,请告诉我。
由于您是从 ggplot 对象开始的,因此将蒙版本身创建为几何图层可能更简单,而不是将所有内容都转换为 grob 并在那里的网格系统中工作。
这里可以使用ggpolypath包中的geom_polypath()
函数。与 ggplot2 中的标准 geom_polygon
不同,它能够处理带孔的多边形(参见 vignette):
# sample data frame for clipping. The first four x & y coordinates are for the outer ends;
# the next four are for the hole in the polygon.
clipping.df <- data.frame(x = c(0, 1.5, 1.5, 0, 0.2, 1, 0.7, 0.3),
y = c(0, 0, 3000, 3000, 250, 2000, 2800, 1500),
hole = rep(c(FALSE, TRUE), each = 4),
group = rep(c("1", "2"), each = 4))
library(ggpolypath)
p +
geom_polypath(data = clipping.df,
aes(x = x, y = y, group = group),
colour = NA, fill = "black", alpha = 0.5,
inherit.aes = FALSE) +
scale_x_continuous(expand = c(0, 0)) + # don't show edges beyond the extent
scale_y_continuous(expand = c(0, 0)) # of the polygon
以下是一个网格解决方案,但在很大程度上是一种变通方法。它展示了如何将非矩形裁剪区域应用于 ggplot,以便裁剪绘图中的一组点。你的尝试并没有错太多。有几点需要注意:
- 您需要
grid.force()
ggplotGrob 对象以便 grid
可以看到 grob。
- 不要将 ggplot grob 定义为剪切路径 - 剪切路径是多边形。
- 剪切路径应用于 ggplot 绘图面板中的点 grob。这意味着绘图面板中的其他对象、面板背景和网格线不会被剪裁。仅裁剪数据点。
我在绘图中添加了一条蓝线,以表明这条线也不需要剪裁;但如果需要可以剪掉。
也有注释的代码行,当取消注释时,将绘制裁剪区域,并将网格线和点移动到前面(即在较暗的灰色裁剪区域前面)。
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
编辑 使用绘制数据点的坐标系定义剪辑区域。
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
我正在尝试将剪贴蒙版应用于 ggplot 中的几何图形以屏蔽部分数据,但保持轴、网格、其他几何图形和图例可见。我不想创建一个特定的情节,因此我不是在寻找使用多边形掩盖情节的某些部分的解决方法。
这是我想效仿的设计(遮罩,不一定是主题,我现在该怎么做):
(source)
另见 this example
有人可能会争辩说我可以过滤不包含在定义掩码的多边形中的数据。但是,虽然它适用于点,并且可以适用于 polygon/line-like 对象,但它适用于栅格(边界不会完全遵循非垂直或非水平线)。 所以我尝试了以下方法:
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)
我能够使用包 gridSVG
定义 clipping mask, but I have difficulties applying it on a ggplot object, even after extracting the grob (see resource here) 和 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()
我的直觉是应该绘制 g_clipped
,但我不能 grid.draw()
,因为它是一个 clipPath 对象。还有 grid.draw()
此处写的行显示未屏蔽的情节。我想我不太了解 clipPath 对象的功能。
函数 grobify()
听起来它可以帮助替代没有 gridSVG 的方法,请参阅 details here,但我不理解非常简约的文档。
由于我什至无法将剪贴蒙版应用于整个情节,所以我的 objective。
如果您可以帮助我了解如何应用 gridSVG
中的剪贴蒙版,或者有其他解决方案可以将剪贴蒙版应用于特定几何体,请告诉我。
由于您是从 ggplot 对象开始的,因此将蒙版本身创建为几何图层可能更简单,而不是将所有内容都转换为 grob 并在那里的网格系统中工作。
这里可以使用ggpolypath包中的geom_polypath()
函数。与 ggplot2 中的标准 geom_polygon
不同,它能够处理带孔的多边形(参见 vignette):
# sample data frame for clipping. The first four x & y coordinates are for the outer ends;
# the next four are for the hole in the polygon.
clipping.df <- data.frame(x = c(0, 1.5, 1.5, 0, 0.2, 1, 0.7, 0.3),
y = c(0, 0, 3000, 3000, 250, 2000, 2800, 1500),
hole = rep(c(FALSE, TRUE), each = 4),
group = rep(c("1", "2"), each = 4))
library(ggpolypath)
p +
geom_polypath(data = clipping.df,
aes(x = x, y = y, group = group),
colour = NA, fill = "black", alpha = 0.5,
inherit.aes = FALSE) +
scale_x_continuous(expand = c(0, 0)) + # don't show edges beyond the extent
scale_y_continuous(expand = c(0, 0)) # of the polygon
以下是一个网格解决方案,但在很大程度上是一种变通方法。它展示了如何将非矩形裁剪区域应用于 ggplot,以便裁剪绘图中的一组点。你的尝试并没有错太多。有几点需要注意:
- 您需要
grid.force()
ggplotGrob 对象以便grid
可以看到 grob。 - 不要将 ggplot grob 定义为剪切路径 - 剪切路径是多边形。
- 剪切路径应用于 ggplot 绘图面板中的点 grob。这意味着绘图面板中的其他对象、面板背景和网格线不会被剪裁。仅裁剪数据点。
我在绘图中添加了一条蓝线,以表明这条线也不需要剪裁;但如果需要可以剪掉。
也有注释的代码行,当取消注释时,将绘制裁剪区域,并将网格线和点移动到前面(即在较暗的灰色裁剪区域前面)。
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
编辑 使用绘制数据点的坐标系定义剪辑区域。
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