1

I am wondering if there are any additional fillable shapes to plot in ggplot, other than the default ones (which can be viewed running ggpubr::show_point_shapes(), or seen here).

According to those sources, the only shapes that can be filled are a square, circle, diamond, and triangle. I would like the ability to plot a fillable cross or "x" shape. By "fillable", I mean the shape should have enough thickness to it where a label could be added inside.

enter image description here

The yellow and green shapes are what I would like to be plottable. Is this possible, or should I look at other options?

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • apart from the unicode way - there would be two other ways I could think of, both I guess more stable and less platform - / device - dependent 1) plot svg files as points https://stackoverflow.com/questions/61387217/use-svg-images-as-symbols-in-gglot2 2) create a new geom – tjebo Mar 15 '21 at 21:59

2 Answers2

2

If you find a Unicode symbol you like then you can use that as a label:

library(ggplot2)
ggplot(mtcars, aes(x=wt, y=mpg)) +
    geom_text(label = ifelse(mtcars$gear >3, "\u2716", "\u271A"),
              aes(vjust=.5, hjust=.5, family="DejaVu Sans"), 
              size=12, 
              col = ifelse(mtcars$gear >3, "lightgreen", "yellow"))+
    geom_text(aes(label=gear, vjust=.5, hjust=.5))+
    theme_bw()

Created on 2021-03-15 by the reprex package (v1.0.0)

You could also use \u2727, \u271C or other characters you like.

user12728748
  • 8,106
  • 2
  • 9
  • 14
  • Although this is a good idea, +1, I personally find plotting with unicode very frustrating because it never works on my computer. Lots of threads in Stackoverflow show - I am not alone – tjebo Mar 15 '21 at 21:54
  • I'm also looking for the ability to easily outline each plot in black or red, depending on another column in my table. To do that with unicode, you need to put another geom_plot with slightly larger shapes in your ggplot function - and it usually doesn't fit. – davidbaseball Mar 15 '21 at 23:19
1

Here a very crude stat using GeomPolygon for a horizontal cross. This is just to demonstrate a very simple and straight forward approach how to implement this. It is not a great stat, because

  1. the proper proportions depend on the scale (you basically need to set coord_equal),
  2. You need to be very specific with the groups

but it might be a good start...

library(tidyverse)
StatCross <- ggproto("StatCross", Stat,
                     compute_group = function(data, scales, width = .1, params) {
                       x <- data$x
                       y <- data$y
                       new_x <- c(rep(x + width, 2),
                                      rep(x + 4 * width, 2),
                                      rep(x + width, 2),
                                      rep(x - width, 2),
                                      rep(x - 4 * width, 2),
                                      rep(x - width, 2))
                       new_y <- c(y + 4* width,
                                        rep(y + width, 2),
                                        rep(y - width, 2),
                                        rep(y - 4*width, 2),
                                        rep(y - width, 2),
                                        rep(y + width, 2),
                                        y + 4*width)
                       cross_data <- data.frame(x = new_x, y = new_y)
                       cross_data
                     },
                     
                     required_aes = c("x", "y")
)
stat_cross <- function(mapping = NULL, data = NULL, geom = "polygon",
                       position = "identity", na.rm = FALSE, show.legend = NA, 
                       inherit.aes = TRUE, width = 0.1, ...) {
  layer(
    stat = StatCross, data = data, mapping = mapping, geom = geom, 
    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
    params = list(na.rm = na.rm, width = width, ...)
  )
}
iris %>% 
  mutate(index = row_number()) %>%
ggplot(aes(Sepal.Length, Sepal.Width, group = index)) +
  stat_cross(width = .01,  fill = "yellow", color = "black")

Created on 2021-03-15 by the reprex package (v1.0.0)

tjebo
  • 21,977
  • 7
  • 58
  • 94
  • This is interesting, and could work. How do you control the width of the black outline? – davidbaseball Mar 15 '21 at 23:47
  • as this is based on GeomPolygon, you can control it with the size argument – tjebo Mar 15 '21 at 23:52
  • 1
    This works for me, so I will checkmark this answer. For future readers, the `size` argument should be written within the `stat_cross()` function (I put it right after the `fill` and `color` arguments). Please note that my dataset is small (<50 rows), so I don't know how well this will scale. – davidbaseball Mar 15 '21 at 23:56