2
votes

I want to create a plot with the ggplot2 package, which combines lines and points. The points should have colors and shapes according to a group indicator. A legend should be created, which displays colors and shapes according to the plot.

This part worked fine. However, all points should have a white fill and I cannot find the right code for that.

A google search suggests to use fill = "white", but this is not working.

Consider the following example data and plot:

library("ggplot2")

# Example data
df <- data.frame(y = 1:100,
                 x = 1:100,
                 group = as.factor(c(rep(1, 33), rep(2, 33), rep(3, 34))))

# Create plot --> fill = "white" doesnt work
ggplot(df, aes(x = x, y = y)) + 
  geom_line(aes(colour = factor(group, labels = c("a", "b", "c")))) +
  geom_point(aes(colour = factor(group, labels = c("a", "b", "c")),
                 shape = factor(group, labels = c("a", "b", "c"))),
             fill = "white") +              ##### This line is not working #####
  theme(legend.title = element_blank())

enter image description here

Question: How could I fill the points of this plot with white (both in the plot and the legend)?

3

3 Answers

2
votes

You can use scale_shape_discrete to set solid = FALSE:

ggplot(df, aes(x = x, y = y)) + 
  geom_line(aes(colour = factor(group, labels = c("a", "b", "c")))) +
  scale_shape_discrete(solid = F) +
  geom_point(aes(colour = factor(group, labels = c("a", "b", "c")),
                 shape = factor(group, labels = c("a", "b", "c")))) +              
theme(legend.title = element_blank())

enter image description here

2
votes

The default shapes used by ggplot2 only have a colour: to get both a colour and a fill, you have to use point shapes from 21 to 25. Then setting fill = "white" will work:

library(ggplot2)

df <- data.frame(
  y = 1:10, x = 1:10,
  group = factor(rep(1:3, c(3, 3, 4)), labels = letters[1:3])
)

ggplot(df, aes(x = x, y = y, colour = group)) +
  geom_line() +
  geom_point(aes(shape = group), fill = "white", size = 3) +
  theme(legend.title = element_blank()) +
  scale_shape_manual(values = 20 + seq_along(unique(df$group)))

1
votes

Coming up with a solution if you are not using standard shapes 21:25. The trick is to call geom_point twice, one with shape 21 to clean up the overlapping line, and another to overlay the desired shapes.

library(ggplot2)
library(RColorBrewer)
Paired = brewer.pal(n=10, name="Paired")
unicodeShapes = -10122:-10131

df = data.frame(y = 1:10, x = 1:10, labels = LETTERS[1:10])

ggplot(data=df,aes(x=x, y=y)) +
  geom_line(color="gray50") + 
  geom_point(aes(x=x, y=y), color="white", shape=21, fill="white", size=5.0,show.legend=FALSE) + 
  geom_point(aes(color=labels, shape=labels), size=6.5) + 
  scale_shape_manual(name="Labels",values=unicodeShapes) +
  scale_color_manual(name="Labels",values=Paired) +
  theme_classic()+
  theme(axis.line.x=element_line(color="gray20", size=1.0),
        axis.line.y=element_line(color="gray20", size=0.5),
        panel.grid.major.x=element_blank(),
        panel.grid.minor=element_blank(), 
        panel.border=element_rect(colour="gray50",fill=NA,size=1.0),
        panel.background = element_rect(colour = "gray50", size=1.0),
        legend.position="bottom",
        text=element_text(size=18))

Shapes on top of line