Home > Software design >  Why does the default shape of the points in ggplot change when including the legend label inside aes
Why does the default shape of the points in ggplot change when including the legend label inside aes

Time:10-05

I set the default point shape to 17:

update_geom_defaults("point", list(shape = 17))

When I plot without specifying the shape inside the aes(), the plot is as expected. But when I put the legend label inside the aes(), the point shape turns out completely different. How can I solve this so that the default shape repeats on all plots?

library(ggplot2)

update_geom_defaults("point", list(shape = 17))

X <- 1
Y <- 2

DF <- data.frame(X, Y)

# OK
ggplot(data = DF,
       aes(x = X,
           y = Y))  
  geom_point()

#Not OK
ggplot(data = DF,
       aes(x = X,
           y = Y))  
  geom_point(aes(shape = "Legend label"))

enter image description hereenter image description here

CodePudding user response:

update_geom_defaults only changes the single default shape that gets used when you call geom_point without mapping something to the shape aesthetic inside aes().

However, when you add a shape aesthetic, ggplot uses the default shape palette, which has shape 16 as its first value. The shape palette is what needs to be changed to get the desired shape 17 as the first value. You can do this for a single plot by adding, for example scale_shape_manual(values=c(17, 16)) to your plot code, which will make shape 17 the first shape and shape 16 the second (when you map a variable with two distinct values to the shape aesthetic`). But then you have to do this for every plot. Instead, you can change the default shape palette once and it will then automatically apply to every subsequent plot. In the examples below, I've augmented your sample data with a new categorical column for illustration.

library(ggplot2)
library(patchwork)
theme_set(theme_bw(base_size=9))

update_geom_defaults("point", list(shape = 17))

X <- 1:2
Y <- 2:3
group = c("A","B")

DF <- data.frame(X, Y, group)

p1 = ggplot(data = DF,
       aes(x = X,
           y = Y))  
  geom_point(size=3)  
  labs(title="No shape aesthetic")

p2 = ggplot(data = DF,
       aes(x = X,
           y = Y, 
           shape=group))  
  geom_point(size=3)  
  labs(title="Add shape aesthetic")

p3 = ggplot(data = DF,
       aes(x = X,
           y = Y))  
  geom_point(aes(shape = "Legend label"), size=3)  
  labs(title="Add dummy shape aesthetic")

p1   p2   p3

In the second and third plots below, note that the filled circle is still used as the first shape in the shape palette.

enter image description here

If we view the default shape palette, we can see that it still has shape 16 (the filled circle) as the first value.

# View default shape palette
scales:::shape_pal()
#> function (n) 
#> {
#>     if (n > 6) {
#>         msg <- paste("The shape palette can deal with a maximum of 6 discrete ", 
#>             "values because more than 6 becomes difficult to discriminate; ", 
#>             "you have ", n, ". Consider specifying shapes manually if you ", 
#>             "must have them.", sep = "")
#>         warning(paste(strwrap(msg), collapse = "\n"), call. = FALSE)
#>     }
#>     if (solid) {
#>         c(16, 17, 15, 3, 7, 8)[seq_len(n)]
#>     }
#>     else {
#>         c(1, 2, 0, 3, 7, 8)[seq_len(n)]
#>     }
#> }
#> <bytecode: 0x7fa674bbcfb8>
#> <environment: 0x7fa6762a8c60>

Below we'll redefine scale_shape_discrete (which is the default shape scale) to use shape 17 (the filled triangle) as the first value. Then when we redo the plots, we'll see that the filled triangle comes first when we use the shape aesthetic.

# Redefine default shape palette
scale_shape_discrete = function(...) {
  scale_shape_manual(values = c(17, 16, 15, 3, 7, 8))
}

p1 = ggplot(data = DF,
            aes(x = X,
                y = Y))  
  geom_point(size=3)  
  labs(title="No shape aesthetic")


p2 = ggplot(data = DF,
            aes(x = X,
                y = Y, 
                shape=group))  
  geom_point(size=3)  
  labs(title="Add shape aesthetic")

p3 = ggplot(data = DF,
            aes(x = X,
                y = Y))  
  geom_point(aes(shape = "Legend label"), size=3)  
  labs(title="Add dummy shape aesthetic")

p1   p2   p3

enter image description here

  • Related