Brian
Brian

Reputation: 427

How to create custom legend in R using ggplot2 for horizontal lines

I am trying to add a customized legend that labels the horizontal lines in my plot. I need the legend to state the following and also needs to be positioned out of the way of the blue lines that are plotted:

Acceptance Criteria:

Red line: "FoS = 1"

Orange line: "Anchor Uplift"

Steelblue line: "FoS = 2"

Green line: "FoS = 2.5"

Plot without legend

Here is my R code. Thanks so much!!

## Plot all Hs values
colfunc <- colorRampPalette(c("cyan", "blue"))
plotColors <- colfunc(length(unique(data$Wave.Height)))
# Initialize plot
plot1 <- ggplot(data = hedron_1kt_180deg_1ft, aes(Wind.Speed, Total.Force)) + 
  geom_line(color = plotColors[1], size = 1) + xlab("Wind Speed [knots]") + ylab("Total Force [MT]") + ggtitle("Current Speed 1 knot / Head Seas") + 
  scale_x_continuous(breaks = c(10,20,30,40,50,60,70)) + coord_cartesian(xlim = c(10,75)) + theme_bw(base_size = 20) +
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_1ft$Total.Force), label = "1 ft", size = 6)
# Add all other lines
plot1 <- plot1 + geom_line(data = hedron_1kt_180deg_1.75ft, aes(Wind.Speed, Total.Force), color = plotColors[2], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_1.75ft$Total.Force), label = "1.75 ft", size = 6) +
  geom_line(data = hedron_1kt_180deg_2.5ft, aes(Wind.Speed, Total.Force), color = plotColors[3], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_2.5ft$Total.Force), label = "2.5 ft", size = 6) +
  geom_line(data = hedron_1kt_180deg_3.25ft, aes(Wind.Speed, Total.Force), color = plotColors[4], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_3.25ft$Total.Force), label = "3.25 ft", size = 6) +
  geom_line(data = hedron_1kt_180deg_4ft, aes(Wind.Speed, Total.Force), color = plotColors[5], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_4ft$Total.Force), label = "4 ft", size = 6) +
  geom_line(data = hedron_1kt_180deg_4.75ft, aes(Wind.Speed, Total.Force), color = plotColors[6], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_4.75ft$Total.Force), label = "4.75 ft", size = 6) +
  geom_line(data = hedron_1kt_180deg_5.5ft, aes(Wind.Speed, Total.Force), color = plotColors[7], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_5.5ft$Total.Force), label = "5.5 ft", size = 6) +
  geom_line(data = hedron_1kt_180deg_6.25ft, aes(Wind.Speed, Total.Force), color = plotColors[8], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_6.25ft$Total.Force), label = "6.25 ft", size = 6) + 
  geom_line(data = hedron_1kt_180deg_7ft, aes(Wind.Speed, Total.Force), color = plotColors[9], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_7ft$Total.Force), label = "7 ft", size = 6) + 
  geom_line(data = hedron_1kt_180deg_7.75ft, aes(Wind.Speed, Total.Force), color = plotColors[10], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_7.75ft$Total.Force), label = "7.75 ft", size = 6) + 
  geom_line(data = hedron_1kt_180deg_8.5ft, aes(Wind.Speed, Total.Force), color = plotColors[11], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_8.5ft$Total.Force), label = "8.5 ft", size = 6) + 
  geom_line(data = hedron_1kt_180deg_9.25ft, aes(Wind.Speed, Total.Force), color = plotColors[12], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_9.25ft$Total.Force), label = "9.25 ft", size = 6) + 
  geom_line(data = hedron_1kt_180deg_10ft, aes(Wind.Speed, Total.Force), color = plotColors[13], size = 1) + 
  annotate("text", x = 73.5, y = max(hedron_1kt_180deg_10ft$Total.Force), label = "10 ft", size = 6) + 
  geom_hline(yintercept = 506, color = "red", size = 1) + geom_hline(yintercept = 202, color = "lawngreen", size = 1) +
  geom_hline(yintercept = 253, color = "steelblue", size = 1) + geom_hline(yintercept = 432, color = "orange", size = 1)
# Save plot
png(filename = "Hedron-WD=40ft-Heading=180deg-Uc=1knot.png", width = 800, height = 600)
plot1
dev.off()

Here is a link to sample data. You just need to change the working directory for the code to work

https://www.dropbox.com/s/htfm3h9s2rcajd4/Hedron%20and%20Arapaho%20Forces.csv?dl=0

Upvotes: 1

Views: 945

Answers (1)

eipi10
eipi10

Reputation: 93811

You can create a plot like this with a lot less effort by putting your data frame in "long" format and then using aesthetic mappings to get the colors and legends.

You haven't provided sample data, so here's an example with fake data:

## Create some fake data

# Fake data
dat = do.call(rbind, 
              lapply(seq(1,10, length.out=8), function(i) {
  data.frame(level=i, x=1:100, y= 1:100 + 10*i)
}))

# Fake criteria lines
dat2 = data.frame(yint = c(40, 60, 149, 180), 
                  slope=c(-0.01,-0.05,-0.1, -0.08), Criteria=LETTERS[1:4])

library(dplyr)

ggplot() + 
  geom_line(data=dat, aes(x,y, group=level), 
            colour=rep(hcl(210,100,seq(20,90,length.out=8)), each=100)) +
  geom_text(data=dat %>% group_by(level) %>% filter(x==max(x)),
            aes(label=round(level,2), x=x+1, y=y), hjust=0) +
  geom_abline(data=dat2, aes(intercept=yint, slope=slope, color=Criteria)) +
  theme_bw() +
  scale_color_manual(values=c("red","orange","green","purple"))

Here's what's going on the code above:

  1. dat contains the data we want to plot. dat2 contains the data for the criteria lines for which we want to have a legend. Note that the data are in "long" format. For example, in dat the level column tells us to which grouping the x and y values belong.

  2. geom_line plots the data. By setting group=level we get a separate line for each value of level with just one call to geom_line. Normally, we'd also add color=level inside aes to get a different color for each line. However, we want a legend for just the criteria lines, so we need to map colors to the data lines "by hand". That's what colour=rep(hcl(210,100,seq(20,90,length.out=8)), each=100) does (note that it's outside of aes).

  3. geom_text places the value labels at the right end of each curve. Note that we filter the data so that we keep only right-most (x,y) value for each level, and we use that to place the text right next to each line.

  4. geom_abline plots the Criteria lines. We use color=Criteria inside aes so that that the Criteria lines are plotted in different colors and we get a color legend.

Here's what the graph looks like:

enter image description here

UPDATE: Here's another example with the data you posted. I loaded your data file into a data frame called df. It looks like you subsetted your data, and I think the subset below is the same as the one in your question. Hopefully, you'll be able to generalize the examples below to whichever subset(s) you wish to include:

# Subset data
df.sub = df %>% filter(Barge.Name=="Hedron",
                       Heading==180,
                       Current.Speed==1,
                       Water.Depth==40)

ggplot(data = df.sub, 
       aes(Wind.Speed, Total.Force, group=Wave.Height, color=Wave.Height)) + 
  geom_line(size = 1) +
  geom_text(data=df.sub %>% filter(Wind.Speed==max(Wind.Speed)),
            aes(label=Wave.Height, y=Total.Force, x=Wind.Speed + 0.5), hjust=0) +
  theme_bw() + 
  guides(color=FALSE)

enter image description here

You can also use faceting to include more variables in the visualization:

df.sub = df %>% filter(Current.Speed==1,
                       Water.Depth==40)

ggplot(data = df.sub, 
       aes(Wind.Speed, Total.Force, group=Wave.Height, color=Wave.Height)) + 
  geom_line(size = 1) +
  geom_text(data=df.sub %>% filter(Wind.Speed==max(Wind.Speed)),
            aes(label=Wave.Height, y=Total.Force, x=Wind.Speed + 0.5), hjust=0) +
  theme_bw() + 
  guides(color=FALSE) +
  facet_grid(Barge.Name ~ Heading) + 
  scale_x_continuous(limits=c(10,78))

enter image description here

Upvotes: 1

Related Questions