Sometimes it is helpful to use a technique of adding a gray semi-transparent layer to an image and then cutting a keyhole into that layer to highlight a certain portion of the image below. Here is an example from a youtube vide:
I do this with plots sometimes but use Inkscape to add a semitransparent layer and then use the eraser to cut a hole in that layer. This (a) looks less than professional (b) requires extra time and a separate program and (c) possible loss in quality.
I want to do it in R. I'm asking about ggplot2 because this is my tool of choice but I think any grid answer would be good (I know base probably has a very different approach).
So here is a MWE where I've added a geom_rect
to show where we'd want to cut the keyhole/window:
ggplot(mtcars, aes(mpg, wt)) +
geom_point(size=3) +
geom_rect(mapping=aes(xmin=20, xmax=25,
ymin=3, ymax=3.3), color="black", alpha=.01)
How can I use R to make a plot that looks something like this:
Method 1: Using rect with theme() In this approach, after the plot has been created normally, theme() function is added to it with rect parameter. To rect, element_rect() function is passed with parameter fill set to transparent.
To remove a particular panel grid, use element_blank() for the corresponding theme argument. For example to remove the major grid lines for the x axis, use this: p + theme(panel.
Turns out you can do this with grid.path(...)
in grid
package. Read the documentation to see how to create a path with a hole in it.
library(gridExtra)
library(ggplot2)
ggp <- ggplot(mtcars, aes(mpg, wt)) + geom_point(size=3)
grid.newpage()
grid.draw(arrangeGrob(ggp))
grid.path(c(0,0,1,1,.48,.48,.62,.62),
c(0,1,1,0,.43,.50,.50,.43),
id=rep(1:2, each=4),
rule="evenodd",gp=gpar(fill="black", alpha=0.6))
NB: grid.draw(...)
and grid.path(...)
are in the grid
package; arrangeGrob(...)
is in the gridExtra
package. Loading gridExtra
causes grid
to be loaded. Thanks to @MartinBel for suggesting the edit.
In response to @BrandonBertelsen comment: grid.path(...)
is agnostic about shape; you just have to supply the coordinates.
center <- c(x=0.55,y=0.48)
r <- 0.1
circle <- do.call(rbind,lapply(seq(0,2*pi,length=36),
function(th)c(x=r*cos(th),y=r*sin(th))))
circle <- data.frame(circle)
circle$x <- circle$x + center["x"]
circle$y <- circle$y + center["y"]
ggp <- ggplot(mtcars, aes(mpg, wt)) + geom_point(size=3)
grid.newpage()
grid.draw(arrangeGrob(ggp))
grid.path(c(0,0,1,1,circle[,1]),
c(0,1,1,0,circle[,2]),
id=c(1,1,1,1,rep(2,nrow(circle))),
rule="evenodd",gp=gpar(fill="black", alpha=0.6))
The "circle" is an ellipse because of the plot window's aspect ratio.
Further reading: It’s Not What You Draw, It’s What You Don’t Draw by Paul Murrell in the R Journal
How about the following?
P <- ggplot(mtcars, aes(mpg, wt)) + geom_point(size=3)
## Set the limits for x & y
xlims <- c(20, 25)
ylims <- c(3, 3.3)
# Where P is the original plot
P + geom_rect(mapping=aes(xmin=-Inf, xmax=min(xlims), ymin=-Inf, ymax=+Inf), fill="black", alpha=.01) +
geom_rect(mapping=aes(xmin=min(xlims), xmax=+Inf, ymin=max(ylims), ymax=+Inf), fill="black", alpha=.01) +
geom_rect(mapping=aes(xmin=min(xlims), xmax=+Inf, ymin=-Inf, ymax=min(ylims)), fill="black", alpha=.01) +
geom_rect(mapping=aes(xmin=max(xlims), xmax=+Inf, ymin=min(ylims), ymax=max(ylims)), fill="black", alpha=.01)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With