0
votes

I have a ggplot graph defined like this:

x <- seq(0, 10, by = 0.1)
y1 <- cos(x)
y2 <- sin(x)
df1 <- data.frame(x = x, y = y1, type = "sin", id = 1)
df2 <- data.frame(x = x, y = y2, type = "cos", id = 2)
df3 <- data.frame(x = 2, y = 0.5, type = "constant", id = 3)
df4 <- data.frame(x = 4, y = 0.2, type = "constant", id = 4)

combined <- rbind(df1, df2, df3, df4)

ggplot(combined, aes(x, y, colour = interaction(type, id))) + geom_line() +
  geom_point(data = subset(combined, type == "constant"))

This works very well as illustrated below: beautiful image, ugly legend

Now I would like to extract the interaction in a variable to reuse it later (e.g. customize the legend style or labels).

I did that in a very naïve way:

my.interaction <- interaction(combined$type, combined$id)

ggplot(combined, aes(x, y, colour = my.interaction)) + geom_line() +
  geom_point(data = subset(combined, type == "constant"))

But then I have an error:

Error: Aesthetics must be either length 1 or the same as the data (2): x, y, colour

Edit: Here is the kind of manipulation I could do: edit the linetype of the legend

displayed <- levels(factor(my.interaction))
line.style <- rep(1, length.out = length(displayed))
line.style[grep("constant", displayed)] <- 0

That works:

ggplot(combined, aes(x, y, colour = interaction(type, id))) + geom_line() +
    geom_point(data = subset(combined, type == "constant")) +
    guides(colour=guide_legend(override.aes=list(linetype = line.style)))

beautiful image, better legend

That does not:

ggplot(combined, aes(x, y, colour = my.interation) + geom_line() +
    geom_point(data = subset(combined, type == "constant")) +
    guides(colour=guide_legend(override.aes=list(linetype = line.style)))

In the end, I could also edit the shapes or the legend labels (e.g. "Id: 1 / Type: sin" or any other advanced transformation of the labels based on the interaction values).

1
Are you opposed to adding my.interaction to the combined data.frame? You could do, combined$my.interaction <- interaction(combined$type, combined$id) and your approach will work.JasonAizkalns
Yes, I want to avoid this. Because depending on what I want to plot, I might use other interactions in different plots... Thus making my data frame grow with somewhat redundant information.Ben
Can you be more specific and provide an example of your comment? You may want to edit/update your question. I think this might be an XY problem.JasonAizkalns
I have updated the questionBen

1 Answers

0
votes

This'll work. What's wrong with adding a column to your data frame?

combined %>% mutate(my.interaction = paste(type, id, sep='.')) %>%
  ggplot(aes(x, y, colour = my.interaction)) + geom_line() +
  geom_point(data = subset(combined, type == "constant"))

image from ggplot