DeltaIV DeltaIV - 2 days ago 4
R Question

include data from different dataframes, combining different geoms and with a legend which identifies the data source

I have three dataframes, containing data for the same variables (

x
and
y
, grouped by variable
case
) but each dataframe contains data from a different source (
test
,
sim
and
model
). The levels of
case
are identical for
test
and
model
, but they are different for
sim
. For each value of
case
, I want all xy curves from different sources but with the same
case
to have the same color. I need to have a legend which clearly identifies the data source, but I would also like to use different geoms for different data sources. This is what I've been able to do:

rm(list=ls())
gc()
graphics.off()
library(ggplot2)

# build the dataframes
nx <- 10
x1 <- seq(0, 1, len = nx)
x2 <- x1+ 0.1
x3 <- x2+ 0.1
x4 <- x3+ 0.1
x <- c(x1, x2, x3, x4)
y1 <- 1 - x1
y2 <- 1.1 * y1
y3 <- 1.1 * y2
y4 <- 1.1 * y3
y <- c(y1, y2, y3, y4)
z1 <- (y1 + y2)/2
z2 <- (y2 + y3)/2
z3 <- (y3 + y4)/2
z4 <- (y4 + 1.1 * y4)/2
z <- c(z1, z2, z3, z4)
w <- y*1.01

case_y <- c("I-26_1", "I00", "I20_5", "I40_9")
case_z <- c("I-23_6", "I00", "I22_4", "I42_3")
case_y <- rep(case_y, each = nx)
case_z <- rep(case_z, each = nx)

foo <- data.frame(x = x, y = z, case = case_z, type = "test")
bar <- data.frame(x = x, y = y, case = case_y, type = "sim")
mod <- data.frame(x = x, y = w, case = case_z, type = "model")

# different data frames have different factor levels: to avoid this,
# I bind all dataframes and I reorder the levels of case
foobar <- rbind(foo, bar, mod)
case_levels <- c("I-26_1", "I-23_6", "I00", "I20_5", "I22_4", "I40_9", "I42_3")
foobar$case <- factor(foobar$case, levels = case_levels)

# now I can plot the resulting dataframe
p <- ggplot(data = foobar, aes(x = x, y = y, color = case)) +
geom_line(aes(linetype = type), size = 1)
p


enter image description here

The problem here is that it's difficult to discern
sim
and
model
. In order to make a more readable plot, I switch to
geom_point
for the
model
data:

foobar <- rbind(foo, bar)
case_levels <- c("I-26_1", "I-23_6", "I00", "I20_5", "I22_4", "I40_9", "I42_3")
foobar$case <- factor(foobar$case, levels = case_levels)
mod$case <- factor(mod$case, levels = case_levels)

# now I can plot the resulting dataframe
p <- ggplot(data = foobar, aes(x = x, y = y, color = case)) +
geom_line(aes(linetype = type), size = 1) +
geom_point(data = mod)


enter image description here

However, now I don't have a
model
label in the legend. How can I make sure that the
model
curves are clearly labeled in the legend, but they are also easy to discern visually from the
sim
and
test
curves?

EDIT Procrastinatus Maximus suggests an edit to Pierre Lafortune's code which should eliminate the space between the
model
label and the
type
legend, but apparently it eliminates the space between
model
and the
case
legend instead:

ggplot(data = foobar, aes(x = x, y = y, color = case)) +
geom_line(aes(linetype = type), size = 1) +
geom_point(data = mod, aes(shape=type)) +
scale_shape_discrete(name="") +
guides(colour = guide_legend(override.aes = list(linetype=c(1),
shape=c(NA)))) +
theme(legend.margin = margin(0,0,0,0), legend.spacing = unit(0, 'lines'))


The result is

enter image description here

Answer

This will get you closer to your goal. I will look to see if we can close the gap between the two legends.

ggplot(data = foobar, aes(x = x, y = y, color = case)) + 
  geom_line(aes(linetype = type), size = 1) +
  geom_point(data = mod, aes(shape=type)) + 
  scale_shape_discrete(name="") +
  guides(colour = guide_legend(override.aes = list(linetype=c(1),
                                                   shape=c(NA))))

Edit

#@ProcrastinatusMaximus
ggplot(data = foobar, aes(x = x, y = y, color = case)) +
  geom_line(aes(linetype = type), size = 1) +
  geom_point(data = mod, aes(shape = type)) +
  guides(color = guide_legend(override.aes = list(linetype = c(1), shape = c(NA)), order = 1),
         linetype = guide_legend(order = 2),
         shape = guide_legend(title = NULL, order = 3))+
  theme(legend.margin = margin(0,0,0,0), legend.spacing = unit(0, 'lines'))

enter image description here

Comments