iembry
iembry

Reputation: 944

R - create legend and separate month plots with panel layers in ggplot

My goal is to create a separate 4-panel plot (right y-axis) for each of the 12 months (top x-axis) for the given years (top x-axis) in the data set. I also want to create a legend with the names of the points (V5 and V6) overlaid in 2 of the panels (V2 and V3). So instead of 1 large plot, there should be 12 plots.

After the reproducible example is my current plot.

Can you offer assistance on how to reach my goal?

Thank you.

library(ggplot2)
library(data.table)

startdate <- as.POSIXct("2008-09-12 10:00:00")
enddate <- as.POSIXct("2011-04-26 23:45:00")
interval <- 1296000
Time <- seq(from = startdate, by = interval/2, to = enddate)

set.seed(1)
timeframe <- data.frame(Time, V1 = abs(rnorm(length(Time))), V2 = 
abs(rnorm(length(Time))), V3 = abs(rnorm(length(Time))), V4 = 
abs(rnorm(length(Time))), V5 = abs(rnorm(length(Time))), V6 = 
abs(rnorm(length(Time))))

timeframe <- setDT(timeframe)

The following Month and Year functions are derived from the waterYear function in smwrBase.

Month <- function (x, numeric = FALSE) 
{
x <- as.POSIXlt(x)
yr <- x$year + 1900L
mn <- x$mon + 1L
if (numeric) 
return(mn)
ordered(mn)
}

Year <- function (x, numeric = FALSE) 
{
x <- as.POSIXlt(x)
yr <- x$year + 1900L
mn <- x$mon + 1L
if (numeric) 
return(yr)
ordered(yr)
}

# month
mn <- Month(timeframe$Time, numeric = TRUE)

# year
yr <- Year(timeframe$Time, numeric = TRUE)

The following plot method is derived from Add a geom layer for a single panel in a faceted plot

timeframe <- data.table(timeframe, mn, yr)
setnames(timeframe, 8:9, c("Month", "Year"))
setkey(timeframe, Time)

df1 <- setDF(timeframe[, list(Time, V1, Month, Year)])
df2 <- setDF(timeframe[, list(Time, V2, Month, Year)])
df3 <- setDF(timeframe[, list(Time, V3, Month, Year)])
df4 <- setDF(timeframe[, list(Time, V4, Month, Year)])
df5 <- setDF(timeframe[, list(Time, V5, Month, Year)])
df6 <- setDF(timeframe[, list(Time, V6, Month, Year)])

names(df1) <- c("Time", "value", "Month", "Year")
names(df2) <- c("Time", "value", "Month", "Year")
names(df3) <- c("Time", "value", "Month", "Year")
names(df4) <- c("Time", "value", "Month", "Year")
names(df5) <- c("Time", "value", "Month", "Year")
names(df6) <- c("Time", "value", "Month", "Year")

df1$panel <- "V1"
df2$panel <- "V2"
df3$panel <- "V3"
df4$panel <- "V4"
df5$panel <- "V2"
df6$panel <- "V3"

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

p <- ggplot(data = dff, mapping = aes(x = Time, y = value))
p <- p + facet_grid(panel ~ Month + Year, scale = "free")
p <- p + layer(data = df1, geom = "line")
p <- p + layer(data = df2, geom = "line")
p <- p + layer(data = df5, geom = "point", colour = "green")
p <- p + layer(data = df3, geom = "line")
p <- p + layer(data = df6, geom = "point", colour = "red")
p <- p + layer(data = df4, geom = "line") +  
scale_fill_manual(values=c("green", "red"), name="Legend",  
labels=c("v5", "v6")) # this last part is my attempt at creating the legend
p

Assistance with the facet_grid came from http://docs.ggplot2.org/current/facet_grid.html


enter image description here

Upvotes: 2

Views: 499

Answers (2)

iembry
iembry

Reputation: 944

This is the complete answer to my question above, most of it relying on Henrik's answer. Thank you Henrik.

library(ggplot2)
library(reshape2)

startdate <- as.POSIXct("2008-09-12 10:00:00")
enddate <- as.POSIXct("2011-04-26 23:45:00")
interval <- 1296000
Time <- seq(from = startdate, by = interval/2, to = enddate)

set.seed(1)
timeframe <- data.frame(Time, V1 = abs(rnorm(length(Time))), V2 = 
abs(rnorm(length(Time))), V3 = abs(rnorm(length(Time))), V4 = 
abs(rnorm(length(Time))), V5 = abs(rnorm(length(Time))), V6 = 
abs(rnorm(length(Time))))

df <- melt(timeframe, id.vars = "Time")

# create year and month variables 
df$year <- format(df$Time, "%Y")
df$month <- format(df$Time, "%b")

# select data for lines
d1 <- df[!df$variable %in% c("V5", "V6"), ]

# select data for points
d2 <- df[df$variable %in% c("V5", "V6"), ]

# rename V5 and V6 to place them in correct panels
d2$variable[d2$variable == "V5"] <- "V2"
d2$variable[d2$variable == "V6"] <- "V3"

Source for the code below: Selecting and plotting months in ggplot2

# separate plot for each month
for (u in unique(df$month)) {
p <- ggplot() + geom_line(data = d1[format(d1$Time,"%b")==u, ], aes(x = 
Time, y = value)) + geom_point(data = d2[format(d2$Time,"%b")==u, ], aes(x= Time, 
y = value, color = variable)) + facet_grid(variable ~ month + year, scale = "free") 
+ scale_color_manual(values = c("green", "red"), name = "Legend", 
labels = c("V5", "V6"))
print(p)
}

Upvotes: 1

Henrik
Henrik

Reputation: 67828

ggplot is generally much happier with the data in a long format. Thus, start by reshaping your data. Then it's rather straightforward to use one data set for the lines and one for the points, and map a variable to the color aesthetics for the points.

# melt data from wide to long format
library(reshape2)
df <- melt(timeframe, id.vars = "Time")

# create year and month variables 
df$year <- format(df$Time, "%Y")
df$month <- format(df$Time, "%m")

# select data for lines
d1 <- df[!df$variable %in% c("V5", "V6"), ]

# select data for points
d2 <- df[df$variable %in% c("V5", "V6"), ]

# rename V5 and V6 to place them in correct panels
d2$variable[d2$variable == "V5"] <- "V2"
d2$variable[d2$variable == "V6"] <- "V3"

# plot
ggplot() +
  geom_line(data = d1, aes(x = Time, y = value)) +
  geom_point(data = d2, aes(x = Time, y = value, color = variable)) +
  facet_grid(variable ~ month + year, scale = "free") +
  scale_color_manual(values = c("green", "red"), name = "Legend",  
                     labels = c("V5", "V6"))

enter image description here

Upvotes: 2

Related Questions