Legend with geom_line and geom_smooth using same grouping variable

1,969 views
Skip to first unread message

Dave Auty

unread,
May 17, 2012, 2:19:41 PM5/17/12
to ggp...@googlegroups.com
Dear List,

Is it possible to specify different linetypes for geom_line and geom_smooth using the same grouping variable, and have them appear separately in the legend?

The following toy example gets me almost what I want using manual scales, but I would like to integrate the smooth line into the legend as a separate row:

DF <- data.frame(group = factor(rep(1:3, each = 100)),
            weight = c(rnorm(100, 20, 10), rnorm(100, 30, 15), rnorm(100, 15, 10)),
                                 height= c(rnorm(100, 20, 6), rnorm(100, 40, 8), rnorm(100, 60, 5)))

library(ggplot2)
ggplot(DF, aes(x = weight, y=height)) +
    geom_line(aes(linetype = group)) +
    geom_smooth(data=subset(DF, group==1), aes(fill=group, linetype=group, size=group, colour=group), method='loess', se=T, show_guide=T) +
    scale_linetype_manual('Legend', breaks = levels(DF$group),
    values = c('solid', 'dashed', 'longdash')) +
    scale_fill_manual(drop=F, 'Legend', breaks = levels(DF$group), values = c('steelblue', NA, NA)) +
    scale_size_manual(drop=F, 'Legend', breaks = levels(DF$group), values = c(1, 0.5, 0.5)) +
    scale_colour_manual(drop=F, 'Legend', breaks = levels(DF$group), values = c('red', 'black', 'black'))

So, I would like the legend to have 4 rows labelled '1', 'Smoothed predictions', '2' and '3'. The row for 'Smoothed predictions' would have a red line and ribbon shading.
I experimented with drop=T in the manual scales but couldn't quite get what I wanted.

Does anyone know if this is possible in ggplot2 0.9.1?

Many thanks in advance for any help or suggestions.

Dave Auty
Postdoctoral research fellow
Université Laval
Wood Research Centre
Québec, QC









Dennis Murphy

unread,
May 17, 2012, 4:14:34 PM5/17/12
to Dave Auty, ggp...@googlegroups.com
Hi:

One way to do it is to create and save the plot, extract out the loess
info, do a few simple modifications, concatenate the loess data with
the original data, make a couple of adjustments and do the plot...it's
a little easier than it sounds. The game is to hook in the loess data
with the original. Here's my approach:

DF <- data.frame(group = factor(rep(1:3, each = 100)),
weight = c(rnorm(100, 20, 10), rnorm(100, 30, 15),
rnorm(100, 15, 10)),
height= c(rnorm(100, 20, 6), rnorm(100, 40, 8), rnorm(100, 60, 5)))

# Initial plot
# The linetypes aren't really necessary, but they do no harm.
p <- ggplot(DF, aes(x = weight, y=height)) +
geom_line(aes(linetype = group)) +
geom_smooth(data = subset(DF, group==1),
aes(linetype=group),
method='loess', se = TRUE)

## do str(ggplot_build(p)) to see what it returns; the second component of
## $data returns info regarding the loess smooth
d1 <- ggplot_build(p)$data[[2]]
# Keep the height, weight, ymin and ymax variables
d1 <- d1[, 2:5]
# Rename x and y to weight and height
names(d1)[1:2] <- c('weight', 'height')
# Create a group variable with a single value
d1 <- transform(d1, group = 'Smoothed\npredictions')

# Add ymin and ymax variables to DF with NA values
DF <- transform(DF, ymin = NA, ymax = NA)
# Now concatenate DF and d1
DF2 <- rbind(DF, d1)
# Redefine group in the new data frame and set its levels
DF2$group <- factor(DF2$group, levels = c('1',
'Smoothed\npredictions', '2', '3'))

# Revised plot:
ggplot(DF2, aes(x = weight, y = height, linetype = group)) +
geom_line(aes(color = group, size = group)) +
geom_ribbon(aes(ymin = ymin, ymax = ymax, fill = group), alpha = 0.2) +
scale_linetype_manual('Legend', breaks = levels(DF2$group),
values = c('solid', 'solid', 'dashed', 'longdash')) +
scale_colour_manual('Legend', breaks = levels(DF2$group),
values = c('black', 'red', 'black', 'black')) +
scale_size_manual('Legend', breaks = levels(DF2$group),
values = c(0.5, 1, 0.5, 0.5)) +
scale_fill_manual('Legend', breaks = levels(DF2$group),
values = c(NA, 'red', NA, NA))

I used \n in the 'Smoothed predictions' label so that the legend takes
up less horizontal space. If you don't want that, remove the \n in the
two places where it appears.

You could do the same thing with a little more work by fitting a loess
model to the data first and then creating a data frame of predictions,
but ggplot_build() does this more quickly and efficiently so that's
why I did it this way.

HTH,
Dennis
> --
> You received this message because you are subscribed to the ggplot2 mailing
> list.
> Please provide a reproducible example:
> https://github.com/hadley/devtools/wiki/Reproducibility
>
> To post: email ggp...@googlegroups.com
> To unsubscribe: email ggplot2+u...@googlegroups.com
> More options: http://groups.google.com/group/ggplot2
datest.png

Dave Auty

unread,
May 17, 2012, 4:53:41 PM5/17/12
to Dennis Murphy, ggp...@googlegroups.com
Hi Dennis,

Many thanks for the helpful reply. This works really well on the toy data - just what I was looking for.

Regards,

Dave
Reply all
Reply to author
Forward
0 new messages