rggplot2aesthetics

ggplot2::scale_shape_manual removes geom_point fill


I am trying to make a plot of the concentration-discharge regimes for rivers as a function of its agricultural and urban land use. Here is my example data:

df.tri<-structure(list(site_no = c("01312000", "01349150", "01349840", 
"01349950", "01356190", "01357500", "013621955", "01362200", 
"0136230002", "01362370", "01362497", "01362500", "01413088", 
"01415460", "01421618", "01422738", "01422747", "0143400680", 
"01434021", "01434025", "01435000", "04213500", "04214500", "04215000", 
"04215500", "04218000", "04218518", "0422026250", "04229500", 
"04230500", "04231000", "04231600", "04232034", "04232050", "0423205010", 
"04232100", "04240180", "04249000", "04250200", "04250750", "04260500", 
"04269000"), Slope = c(0.19, 0.1, -0.01, 0.42, 0.11, 0.19, 0.61, 
0.48, 0.69, 0.69, 0.43, 1.08, -0.14, 0.24, 0.29, 0.26, 0.52, 
0.24, 0.17, 0.28, 0.46, 1.31, 0.87, 0.64, 0.81, 0.26, 0.58, 0.3, 
0.11, 0.37, 0.07, 0.68, 0.24, 0.21, 0.5, 0.1, 0.2, -0.01, 0.06, 
-0.09, 0.27, 0.27), Type = c("Mobilization", "Mobilization", 
"Stationary", "Mobilization", "Stationary", "Mobilization", "Mobilization", 
"Mobilization", "Mobilization", "Mobilization", "Mobilization", 
"Mobilization", "Dilution", "Mobilization", "Mobilization", "Mobilization", 
"Mobilization", "Mobilization", "Mobilization", "Mobilization", 
"Mobilization", "Mobilization", "Mobilization", "Mobilization", 
"Mobilization", "Mobilization", "Mobilization", "Mobilization", 
"Mobilization", "Mobilization", "Mobilization", "Mobilization", 
"Mobilization", "Mobilization", "Mobilization", "Stationary", 
"Stationary", "Stationary", "Stationary", "Stationary", "Mobilization", 
"Mobilization"), DEVNLCD06 = c(0.68, 6.16, 0, 4.72, 55.42, 7.65, 
6.07, 2.18, 0.71, 1.23, 2.16, 2.03, 2.32, 1.54, 1.93, 3.35, 2.97, 
0, 0.08, 0, 0.6, 4.06, 7.15, 5.48, 10.27, 6.75, 17.32, 22.77, 
4.92, 6.51, 8.57, 6.17, 10.47, 63.05, 38.18, 4, 4.48, 8.06, 0.34, 
2.98, 1.34, 1.19), PLANTNLCD06 = c(0.01, 59.75, 0, 5.34, 3.22, 
24.25, 0.23, 0.19, 0.03, 0.07, 1.51, 0.5, 9.48, 19.08, 32.62, 
26.9, 31.24, 0, 0, 0, 0.23, 34.57, 45.19, 46.45, 25.32, 49.94, 
33.19, 33.73, 34.8, 62.4, 64.81, 45.91, 50.93, 18.72, 32.62, 
40.93, 42.55, 39.55, 1.87, 33.51, 11.05, 2.65)), row.names = c(NA, 
-42L), class = "data.frame")

I have percent agriculture is on the yaxis, percent urban on the xaxis, and I need to have the different levels of the Type column to be different shapes and the shapes to be colored based on the magnitude in the Slope column. This code does that:

ggplot(df.tri, aes(x=DEVNLCD06, y=PLANTNLCD06)) +
  geom_point(aes(shape=as.factor(Type), color=abs(Slope)), size = 4)

However, when I use scale_shape_manual to change the shape of the Type column to up arrows for mobilization, down arrows for dilutionary, and circles for stationary, the fill of the points are removed from the plot:

ggplot(df.tri, aes(x=DEVNLCD06, y=PLANTNLCD06)) +
  geom_point(aes(shape=as.factor(Type), color=abs(Slope)), size = 4)+
  scale_shape_manual(values = c("Mobilization" = 2, "Dilution" = 6, "Stationary" = 1))

I have tried lot of combinations of the vairous scale_ ggplot functions (e.g. scale_color_manual and scale_fill_manual:

ggplot(df.tri, aes(x=DEVNLCD06, y=PLANTNLCD06)) +
  geom_point(aes(shape=as.factor(Type), color=abs(Slope)), size = 4)+
  scale_shape_manual(values = c("Mobilization" = 2, "Dilution" = 6, "Stationary" = 1))+
  scale_color_manual(values=df.tri$Slope)

without success.

My question is how can I keep the points filled when using scale_shape_manual?

Any help is much appreciated.


Solution

    1. Most shapes (of R's "number" shapes) support color of the line (shapes 0-14) and color of the whole shape (shapes 15-20). Only a handful support both color and fill (21-25). For example (ggpubr here used solely for convenience, not required for the answer):

      ggpubr::show_point_shapes()
      

      R's numbers plot shapes

    2. If you want to change the fill of a shape, you need to assign its aesthetic, as in aes(fill=..).

    If you are intending to change the fill color, we can either use the solid shapes (only solid color, no fill), or we can use the color+fill shapes.

    solid shapes

    Unfortunately, while there is an upright solid triangle, there is no inverted triangle, so we'll need to shift to another; I'll demo with 18 (diamond).

    ggplot(df.tri, aes(x=DEVNLCD06, y=PLANTNLCD06)) +
      geom_point(aes(shape=as.factor(Type), color=abs(Slope)), size = 4)+
      scale_shape_manual(values = c("Mobilization" = 17, "Dilution" = 18, "Stationary" = 15))
    

    solid shapes, color only

    filled shapes

    We have both. You've only identified abs(Slope) as your desired fill color. I'll demo with both a static color ("black") and one of the other variables (just for fun). Note we're using different shape numbers again.

    ggplot(df.tri, aes(x=DEVNLCD06, y=PLANTNLCD06)) +
      geom_point(aes(shape=as.factor(Type), fill=abs(Slope)), size = 4) +
      scale_shape_manual(values = c("Mobilization" = 24, "Dilution" = 25, "Stationary" = 22))
    

    filled shapes, color fill, black boundaries

    ggplot(df.tri, aes(x=DEVNLCD06, y=PLANTNLCD06)) +
      geom_point(aes(shape=as.factor(Type), color=DEVNLCD06, fill=abs(Slope)), size = 4) +
      scale_shape_manual(values = c("Mobilization" = 24, "Dilution" = 25, "Stationary" = 22))
    

    filled shapes, color plus fill

    Going back to the "fill only", we can choose a color for the legend shapes if you don't like the hollow look.

    ggplot(df.tri, aes(x=DEVNLCD06, y=PLANTNLCD06)) +
      geom_point(aes(shape=as.factor(Type), fill=abs(Slope)), size = 4) +
      scale_shape_manual(values = c("Mobilization" = 24, "Dilution" = 25, "Stationary" = 22),
                         guide = guide_legend(override.aes = list(fill = "pink")))
    

    change the fill for the legend only

    You have full control over the fill color, I chose one.

    Also, you mentioned a gradient in your attempted code, you might choose to use scale_fill_gradient (same mechanism as for color gradient).