ggplot adding legend

Hello,

I have hard time adding legend to my ggplot:

library(ggplot2)
MonthData <- as.data.frame(c(1:11))

MonthData$Previous <- c(1:11)
MonthData$Current <- c(12:22)
MonthData$Dynamic <- MonthData$Current/MonthData$Previous
MonthData <- MonthData[,-1]
MonthData$MonthNames <- as.character(as.roman(MonthData$Previous))
MonthData$MonthNames <- factor(MonthData$MonthNames, levels = MonthData$MonthNames) 

currentYear <- 2020
previousYear <- 2019

 ggplot(data = MonthData, aes(x=MonthNames)) +
  coord_cartesian(ylim = c(1,30)) +

  geom_line(aes(y = Previous, group = 1), color = '#feb24c', size = 0.65, linetype = "dashed")+
  geom_line(aes(y = Current, group = 1), color = '#f03b20', size = 0.65, linetype = "dashed")+

  geom_point(aes(y = Previous), size = 2, color = '#feb24c', pch = 17)+
  geom_point(aes(y = Current), size = 2, color = '#f03b20') +

  geom_col(aes(y = Dynamic/2.5 ), colour = '#bdbdbd', size = 0.65, fill = NA) +

  scale_y_continuous(sec.axis = sec_axis(~.*2.5)) +

  labs(
    title = paste("Title"),
    subtitle = paste("Circle - ", currentYear, ", Triangle - ", previousYear, ", Boxes - Dynamics."),
    x = "",
    y = "Title"
    ) +

theme_bw()

since adding legend function seems not to work properly with ggplot:

 ggplot(data = MonthData, aes(x=MonthNames)) +
  coord_cartesian(ylim = c(1,30)) +

  geom_line(aes(y = Previous, group = 1), color = '#feb24c', size = 0.65, linetype = "dashed")+
  geom_line(aes(y = Current, group = 1), color = '#f03b20', size = 0.65, linetype = "dashed")+

  geom_point(aes(y = Previous), size = 2, color = '#feb24c', pch = 17)+
  geom_point(aes(y = Current), size = 2, color = '#f03b20') +

  geom_col(aes(y = Dynamic/2.5 ), colour = '#bdbdbd', size = 0.65, fill = NA) +

  scale_y_continuous(sec.axis = sec_axis(~.*2.5)) +

  labs(
    title = paste("Title"),
    subtitle = paste("Circle - ", currentYear, ", Triangle - ", previousYear, ", Boxes - Dynamics."),
    x = "",
    y = "Title"
    ) +

theme_bw() +
   legend("bottomleft", 
  legend = c(currentYear, previousYear), 
  col = c('#feb24c', '#f03b20'), 
  pch = c(1,17))

giving me an error:

'strwidth(legend, units = "user", cex = cex, font = text.font)': plot.new has not been called yet

I have also tried adding shape, or colour atribute to different functions.

The legend that I'm looking at is covering caption under the Title. What I would like to see is a triangle drawing with caption, circle drawing with caption and if possible boxes drawing with caption.

I would be grateful for help,
and merry Christmas :).

Hi @Ricoo,
First of all, kudos on making a good reproducible example! It was really easy to copy and paste your code into my R session to play around with your plot.

I'm guessing that you've plotted before in base R, is that right? You're approaching this plot as if it were a base R plot instead of a ggplot, by adding each data series as a separate call to geom_line() and geom_point().

ggplot2 actually thinks about data differently. Instead of plotting one column of data and then another one and coloring each one separately, like you might do in base R, you should reshape your data into "long" format, such that there's one variable to "color by" and another variable for the x values and another for the y values. In your case, it looks like you'll want to combine "Current" and "Previous" into one variable, maybe called "Type" (or whatever makes more sense). Then you can use that to map to the colors and points.

I've reworked your example above to put the data in long format and re-created the graph to the best of my ability.

# Load libraries. Note that I'm also loading tidyr and dplyr to help with data manipulation.
library(ggplot2)
library(tidyr)
library(dplyr)

# Create the data
MonthData <- as.data.frame(c(1:11))

MonthData$Previous <- c(1:11)
MonthData$Current <- c(12:22)
MonthData$Dynamic <- MonthData$Current/MonthData$Previous
MonthData <- MonthData[,-1]
MonthData$MonthNames <- as.character(as.roman(MonthData$Previous))
MonthData$MonthNames <- factor(MonthData$MonthNames, levels = MonthData$MonthNames) 

# Transform the data from wide to long format using the wonderful pivot_longer() function
long <- MonthData %>%
  pivot_longer(cols = c("Previous", "Current"), names_to = "Title", values_to = "Value")

currentYear <- 2020
previousYear <- 2019

# Build the plot. Note that I'm only using one call to each of geom_line and geom_point, but I specify which variable to map the colors and shapes to.
ggplot(data = long, aes(x = MonthNames))+
  coord_cartesian(ylim = c(1,30))+
  geom_line(aes(y = Value, col = Title, group = Title), linetype = "dashed")+
  geom_point(aes(y = Value, col = Title, group = Title, shape = Title))+
  scale_color_manual(values = c("#f03b20", "#feb24c"))+ # this is where I manually define the colors. The groups go in alphabetical order by default, so I put the color for "Current" before the color for "Previous".
# Note: you could add a scale_shape_manual() function here if you wanted to set the shapes by hand, but it looks like the shapes you want are already the defaults.
  theme_bw()+
  geom_col(aes(y = Dynamic/2.5), col = "#bdbdbd", size = 0.65, fill = NA)+ # I didn't make any changes here.
  scale_y_continuous(sec.axis = sec_axis(~.*2.5))+
# By default, ggplot will create a legend that has the title "Type", or the name of whichever column you've mapped to your colors, shapes, etc. If you mapped colors and shapes to different columns, it will create separate legends for each; if you mapped them to the same variable (such as we did here), it will put them together on the same legend, which I think is what you want.
# I use the labs() function here to change the title of the legend. I think there are other ways to do this too, this is just the first one that comes to mind.
  labs(color = guide_legend(title = "Your title here"), 
       shape = guide_legend(title = "Your title here"))

The part of your question that I'm not sure how to address is the part where you ask to put boxes in the legend as well. Maybe someone who knows ggplot2 better than I do can address that. But I hope this helps at least somewhat!

To read more about the philosophy behind ggplot2 and what data structures are best used with it, take a look at the visualization chapter of the R For Data Science book.

I hope that helps! Let me know if you have other questions, and good luck :slight_smile:

1 Like

Thank you very much, the pleasure is mine :slight_smile:

It's hard to say, I'm semi-new to R and when I was being taught it was said ggplot is handy library for plotting and I can't really say the difference comparing to base r plots and which functions belong to which library. I've heard that plot build by adding next layers one on another, that's where idea for solution comes from.

Thank you very much for your solution and for the extensive answer! I have one question to it. When you transform data to long format you double values in dynamic column, what results in doubling the boxes on plot. Do you know the elegant way, to come over this? Ofcource I can go with the loop and set zero value to every 2 rows, but it not seems to be a optimal solution.

I will for sure!

It definitly does help. Thank you very much again and also good luck :slight_smile:

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.