Ian Krumanocker
Ian Krumanocker

Reputation: 53

How can I define line plotting order in ggplot2 for grouped lines?

I have a dataframe similar to the following:

set.seed(1)
df = data.frame(group = sort(rep(1:15,5)), x = rep(1:5,15), 
y = c(runif(25,-1,1), runif(25, -.5,.5),runif(25,-1,1)),
flag = c(rep('false', 25), rep('true',25),rep('false', 25)))

where x and y are coordinates for plotting, group is an identifier for distinct lines, and flag is a boolean indicating a special subset of the line groups. I would like to use ggplot to plot these lines so the lines with flag = 'true' appear on top. However, the plotting order seems to be determined only by the group name. In my example df, since the values with flag = 'true' correspond to groups 6-10, they are plotted above groups 1-5 but below groups 11-15. This happens even if I try to use the order aesthetic in the following manner:

ggplot(data = df, aes(x = x, y = y, colour = flag,
group = group, order = flag)) + geom_line(size = 3)

I am able to get the plotting order I desire if I rename the group labels (for example if the examples with flag = true are groups 11-15 instead of 6-10) but I would assume there is a better way to do this. Is there some way to override the ordering by group name?

Upvotes: 5

Views: 4840

Answers (2)

Pierre Gramme
Pierre Gramme

Reputation: 1254

Reviving a 5-year-old question, but might be helpful for others...

As mentioned by the OP, the z-order of the lines (and of many other geom's in ggplot2) is determined by the group aesthetic. The order aesthetic is not mentioned in the doc of geom_line, not sure it exists.

By default, groups are sorted numerically (or alphabetically if strings), but if they are factors they will be sorted by their levels. So the trick is to make them a factor with a specific levels ordering ensuring that the first levels (bottom z-order) correspond to flag false. This can be done with forcats::fct_reorder():

library(tidyverse)
df %>% 
  mutate(group = forcats::fct_reorder(as_factor(group), flag, .fun=first)) %>% 
  ggplot(aes(x = x, y = y, colour = flag, group = group)) + 
  geom_line(size = 3)

This solution also works on cases with several colors. You might need to first factor() the coloring variable with a proper ordering of the levels (bottom layer to top layer)

Upvotes: 2

jazzurro
jazzurro

Reputation: 23574

One way would be to subset your data when you draw lines. You want to draw lines for the false group first, then the true group.

ggplot(data = df, aes(x = x, y = y, colour = flag,
       group = group)) +
geom_line(data = subset(df, flag == "false"), size = 3) +
geom_line(data = subset(df, flag == "true"), size = 3)

enter image description here

Upvotes: 6

Related Questions