How to add a legend for two geom layers in one ggplot2 plot?

12,166

Solution 1

In ggplot, legends are automatically created for mapped aesthetics. You can add such mappings as follows:

ggplot(data = df, 
       mapping = aes(x = x)) + 

  # specify fill for bar / color for line inside aes(); you can use
  # whatever label you wish to appear in the legend
  geom_col(aes(y = y.bar, fill = "bar.label")) +
  geom_line(aes(y = y.line, color = "line.label")) +

  xlab("Month of year") + 
  scale_y_continuous(name = "Daily classifications per Spotter") + 

  # the labels must match what you specified above
  scale_fill_manual(name = "", values = c("bar.label" = "grey")) +
  scale_color_manual(name = "", values = c("line.label" = "black")) +

  theme_bw()

In the above example, I've also moved the data & common aesthetic mapping (x) to ggplot().

plot

Sample dataset:

set.seed(7)
df <- data.frame(
  x = 1:20,
  y.bar = rpois(20, lambda = 5),
  y.line = rpois(20, lambda = 10)
)

Solution 2

This solution is aimed at plotting 2 curves from 1 data frame. One column data is plotted as line graph against the x-axis (Observation Date) and the other is plotted as Area Graph against the same x-axis(Observation Date). Area Curve will be on secondary y-axis. The Legend plotting and Formatting are also shown in the images attached. Hope you enjoy the solution.

Data Frame structure will look like as follows/ This is a sample of the whole dataset, I will pick 2 columns, obsdate, revenue, and value:

This is a sample of the whole dataset, I will pick 2 columns, obsdate, revenue, and value

I am using Shiny library to host it on a server; if you don't know about shiny you may ignore, this is just the layout~HTML.

library(xlsx) # Library for Excel import 
library (ggplot2) # Library for plot
library(openxlsx) #FOR Running the xlsx file 
library(shiny) #SERVER UI LIBRARY IN R
library(lubridate) # For converting the imported dates to Date Format

file <- "C:/Users/Nikhil Asati/Desktop/Office/Bicurve_data.xlsx"
data1<- read.xlsx( file ,1)
data1$obsdate <- dmy(data1$obsdate)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(),
    mainPanel(
      plotOutput("Plot")
    )
  )
)
server <- function(input, output) {
  output$Plot <- renderPlot({
    #plot value
    p <- ggplot(data1, aes(x=obsdate))
        p <- p + geom_line(aes(y=revenue, colour ="revenue"))
    #plot revenue
        p <- p + geom_ribbon(aes(ymin = 0, ymax=value/16, fill = 'value'),  
                             linetype=1,     
                             #solid, dashed or other line types
                             colour="grey70",
                             #border line color
                             size=1
                             # ,show.legend= TRUE
        )
         p <- p + scale_y_continuous(sec.axis = sec_axis(~.*16, name = "value"))
          
         p<- p + scale_colour_manual("", values=c("revenue" = "Grey" ))
         p<- p +scale_fill_manual(name = "", values = c("value" = "green"))
         p<- p +theme(legend.position = "top") 
         p
  })
  
}


shinyApp(ui = ui, server = server) 

Output will be:

Output Curve

Share:
12,166
hpy
Author by

hpy

Updated on June 07, 2022

Comments

  • hpy
    hpy almost 2 years

    I've got a data frame that looks like this:

    glimpse(spottingIntensityByMonth)
    # Observations: 27
    # Variables: 3
    # $ yearMonth <dttm> 2015-05-01, 2015-06-01, 2015-07-01, 2015-08-01, 2015-09-01, 2015-10-01, 2...
    # $ nClassificationsPerDayPerSpotter <dbl> 3.322581, 13.212500, 13.621701,
        6.194700, 18.127778, 12.539589, 8.659722, ...
    # $ nSpotters <int> 8, 8, 22, 28, 24, 22, 24, 27, 25, 29, 32, 32, 21, 14, 18, 13, 20, 19, 15, ...
    

    I am trying to plot it with ggplot2 like so:

    ggplot() + 
        geom_col(data = spottingIntensityByMonth, 
                 mapping = aes(x = yearMonth, 
                               y = nClassificationsPerDayPerSpotter)
                 ) + 
        xlab("Month of year") + 
        scale_y_continuous(name = "Daily classifications per Spotter") + 
        geom_line(data = spottingIntensityByMonth, 
                  mapping = aes(x = yearMonth,
                                y = nSpotters)
                  ) +
        theme_bw()
    

    This produces a plot like so:

    enter image description here

    Now I want to add a legend that says what the line and columns mean. How do I do this? Thanks!

  • hpy
    hpy over 6 years
    It worked just as you described, THANK YOU very much for your detailed answer! The only thing is that I don't understand the logic behind the scale_*_manual() function calls, how do I understand it? Thanks anyway!! :)
  • Z.Lin
    Z.Lin over 6 years
    @hpy Glad it helped :) The scale_*_manual() functions allow you to specify your own palette in the form of a named vector e.g. c("a" = "red", "b" = "green"), where "a" & "b" are values in the relevant variables. In this case, since I don't want fill / colour to vary by values within y.bar / y.line, I let each take on a single value as far as fill / colour are concerned. This is somewhat unorthodox, but I find it works quite well in practice.
  • hpy
    hpy over 6 years
    Got it, thanks for your explanation! This is super helpful to know.