简体   繁体   中英

Making simple custom geom - variation of geom_rect() in ggplot2

I am trying to make a simple custom geom that will essentially place a 'frame' around ggplot panels. I am aware this is also possible to do within the theme, but I might like to map other aesthetics to it like color and so on. What I would like is to simply modify geom_rect so that by default it just has xmin, xmax, ymin, and ymax values of Inf and -Inf, a fill of NA, and a color like black or grey20.

However, I've tried to follow some of the code examples here to just update an existing geom, and this doesn't seem to work. It doesn't throw and error, but it simply doesn't plot anything.

library(tidyverse)

GeomFrame <- ggproto("GeomFrame",
                     GeomRect,
                     default_aes = aes(colour = "grey20",
                                       fill = NA,
                                       size = 1,
                                       linetype = 1,
                                       xmin = -Inf,
                                       xmax = Inf,
                                       ymin = -Inf,
                                       ymax = Inf)
)

geom_frame <- function(mapping = NULL, data = NULL, stat = "identity", position = "identity", 
                       ..., linejoin = "mitre", na.rm = FALSE, show.legend = NA, 
                       inherit.aes = TRUE) {
  layer(
    data = data, mapping = mapping, stat = stat, geom = GeomFrame, 
    position = position, show.legend = show.legend, inherit.aes = inherit.aes, 
    params = list(linejoin = linejoin, na.rm = na.rm, ...)
  )
}

ggplot() +
  scale_x_continuous(limits = c(1, 10)) +
  scale_y_continuous(limits = c(1, 10)) +
  geom_frame() 

You should see that this just doesn't seem to do anything. What I would like it to look like is this:

ggplot() +
  scale_x_continuous(limits = c(1, 10)) +
  scale_y_continuous(limits = c(1, 10)) +
  geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf), fill = NA, color = "black", size = 1) 

Any help on this would be great!

Your ggproto object could look like this:

GeomFrame <- ggproto("GeomFrame", GeomRect,
 default_aes = aes(colour = "grey20",
                   fill = NA,
                   size = 1,
                   linetype = 1,
                   alpha = 1,
                   xmin = -Inf, 
                   xmax = Inf, 
                   ymin = -Inf, 
                   ymax = Inf),
 
 required_aes = NULL
)

Your actual geom_frame function probably makes more sense as an annotation type geom, but as long as you give it some default data and an aesthetic mapping it should do what you need:

geom_frame <- function(mapping = NULL, data = NULL, stat = "identity", 
                       position = "identity", 
                       ..., linejoin = "mitre", na.rm = FALSE, show.legend = NA, 
                       inherit.aes = FALSE) {
  if(is.null(data)) {
    data <- data.frame(xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf)
    mapping <- structure(c(mapping, 
                 aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax)),
                 class = "uneval")
  }
  
  layer(
    data = data, mapping = mapping, stat = stat, geom = GeomFrame, 
    position = position, show.legend = show.legend, inherit.aes = inherit.aes, 
    params = list(linejoin = linejoin, na.rm = na.rm, ...)
  )
}

For example

ggplot() +
  scale_x_continuous(limits = c(1, 10)) +
  scale_y_continuous(limits = c(1, 10)) +
  geom_frame()

在此处输入图像描述

and

ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, color = Species)) + 
  geom_point() +
  geom_frame(size = 3, color = "red4") 

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM