2

I see from here (http://sape.inf.usi.ch/quick-reference/ggplot2/shape) the set of possible shapes. If I wanted to define new shapes, is it possible? For example, suppose I wanted to use a 7-sided polygon with an optional fill aesthetic -- is there a way to tell ggplot about that shape?

I feel constrained by this set of possibilities:

library(tidyverse)
dat <- tibble(p = c(0:25, 32:127),
              x = p %% 16,
              y = p %/% 16)
ggplot(dat, aes(x, y)) +
  geom_text(aes(label = p), size = 3, nudge_y = -.25) +
  geom_point(aes(shape = p), size = 5, fill = "red") +
  scale_shape_identity() +
  theme_void()

enter image description here

Alex Coppock
  • 2,122
  • 3
  • 15
  • 31

2 Answers2

5

Yes, it's possible to do this in one of several ways. Unless you have an svg file of a 7-sided polygon available, one quick solution would be to define this shape as a grob and plot it using geom_grob from package ggpmisc. This keeps things in vector format.

Creating the heptagon is the hard part:

library(ggplot2)
library(dplyr)
library(grid)
library(ggpmisc)

# Make heptagon
septs    <- seq(0, 2 * pi, length.out = 8)
devratio <- dev.size()[2]/dev.size()[1]
heptagon <- linesGrob(x = unit(0.5 + 0.2 * devratio * sin(septs), "npc"), 
                      y = unit(0.5 + 0.2 * cos(septs), "npc"),
                      gp = gpar(lwd = 2))

The plot itself is straightforward:

# Plot 10 random points with the heptagon
set.seed(69)

tibble(x = rnorm(10), y = rnorm(10), shape = list(heptagon)) %>%
  ggplot() + 
  geom_grob(aes(x, y, label = shape))

enter image description here

As you can see from this example, custom shapes aren't necessarily all that easy to use, since the shape has to be defined pointwise by the user, it is difficult to match its size and lineweight to existing points, and the user would have to define what/where their fill is, etc. I don't think it's an omission from ggplot to not have a simple interface for creating custom shapes - ggplot has great extensibility for advanced users, and it's not clear that you could have a useful shape-creating interface for beginners. Meanwhile there are more than enough shapes to provide informative plots for all but the most niche applications.

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
  • Thanks for the creative approach -- the limitations you outline are real! I didn't mean to say that the ggplot package should have included such functionality for beginners. Some smart person should figure out how to make shapes of particular types (polygons, rectangles and ovals should all be tractable enough!) – Alex Coppock Sep 25 '20 at 18:42
  • @AlexCoppock there are packages out there that can do all of these things. You can see a regular polygon is very easy to make. It is possible to make new geoms in ggplot if what's available doesn't meet your needs. If you check out [this answer of mine](https://stackoverflow.com/questions/60446727/alpha-aesthetic-shows-arrows-skeleton-instead-of-plain-shape-how-to-prevent-i/60587296#60587296) you'll get a feel for what's involved. – Allan Cameron Sep 25 '20 at 19:00
1

Maybe not exactly what you're looking for but let me suggest three packages:

ggimage - allows you to use images, like a .png file, for your points. See https://mran.microsoft.com/snapshot/2018-04-02/web/packages/ggimage/vignettes/ggimage.html

ggpattern - allows you to add different fills to your graphics. See https://github.com/coolbutuseless/ggpattern

emoGG - uses emojis for your points. See https://github.com/dill/emoGG

eugene100hickey
  • 351
  • 1
  • 3
  • These are great -- I'd seen image but not the other two. Thank you! images would be an OK workaround, but the inability to define new shapes seems like a missing piece in the gg-scape! – Alex Coppock Sep 23 '20 at 17:34