Search code examples
rggplot2legend-properties

How to add an appropriate legend to a bar+line+ribbon chart?


I made some adaptations to the code of this publication. My goal was obtained a chart with bar, line, and ribbon objects.

However, I faced two problems while plotting it:

  1. The background of all objects (bar, line and ribbon) is filled with steelblue instead of the respective color (see figure) enter image description here;

  2. All objects are represented by line in the legend. However, the bar and ribbon should be represented by squares filled with the colors 'steelblue' and gray; whereas the line should be represented by a line (obviously).

Here is the code that I used:

suppressPackageStartupMessages(library(ggplot2))

zz <- tempfile()
cat("
FECHA H_SOLAR;DIR_M;VEL_M;TEMP_M;HR;PRECIP
01/06/14 00:50:00;314.3;1.9;14.1;68.0;-99.9
01/06/14 01:50:00;322.0;1.6;13.3;68.9;-99.9
01/06/14 02:50:00;303.5;2.1;12.3;70.9;-99.9
01/06/14 03:50:00;302.4;1.6;11.6;73.1;-99.9
01/06/14 04:50:00;306.5;1.2;10.9;76.4;-99.9
01/06/14 05:50:00;317.1;0.8;12.6;71.5;-99.9
01/06/14 06:50:00;341.8;0.0;17.1;58.8;-99.9
01/06/14 07:50:00;264.6;1.2;21.8;44.9;-99.9
01/06/14 08:50:00;253.8;2.9;24.7;32.2;-99.9
01/06/14 09:50:00;254.6;3.7;26.7;27.7;-99.9
01/06/14 10:50:00;250.7;4.3;28.3;24.9;-99.9
01/06/14 11:50:00;248.5;5.3;29.1;22.6;-99.9
01/06/14 12:50:00;242.8;4.7;30.3;20.4;-99.9
01/06/14 13:50:00;260.7;4.9;31.3;17.4;-99.9
01/06/14 14:50:00;251.8;5.1;31.9;17.1;-99.9
01/06/14 15:50:00;258.1;4.6;32.4;15.3;-99.9
01/06/14 16:50:00;254.3;5.7;32.4;14.0;-99.9
01/06/14 17:50:00;252.5;4.6;32.0;14.1;-99.9
01/06/14 18:50:00;257.4;3.8;31.1;14.9;-99.9
01/06/14 19:50:00;135.8;4.2;26.0;41.2;-99.9
01/06/14 20:50:00;126.0;1.7;23.5;48.7;-99.9
01/06/14 21:50:00;302.8;0.7;21.6;53.9;-99.9
01/06/14 22:50:00;294.2;1.1;19.3;67.4;-99.9
01/06/14 23:50:00;308.5;1.0;17.5;72.4;-99.9
", file=zz)

datos=read.csv(zz, sep=";", header=TRUE, na.strings="-99.9")

datos$dia=as.POSIXct(datos[,1], format="%y/%m/%d %H:%M:%S")  

par(mar = c(5, 4, 4, 4) + 0.25)

ggplot(data = datos, aes(x = dia, y = TEMP_M)) +
  geom_bar(stat = "identity", fill = "steelblue", aes(color = "agenda")) +
  geom_ribbon(aes(ymin = TEMP_M*0.5, ymax = TEMP_M*1.5, color = "limite"), data = datos, alpha = 0.25) +
  geom_line(aes(y = TEMP_M, color = "control"), data = datos) +
  labs(x = "Hour", y = "Temperature") +
  scale_colour_manual(" ", values=c(agenda = "steelblue", control = "black", 
                               limite = "gray"),
                      labels = c(agenda = "T1", 
                                 control = "T2", 
                                 limite = "Temperature interval")) + 
  scale_fill_manual(values=c("agenda"="steelblue", "control"="black", "limite"="gray"), 
                    guide="none") + 
  theme(legend.key = element_rect(fill = "white"))

I tried to use the commands "scale_fill_manual()" and "theme()", but it didn't work for my case.

I would be very grateful if someone could help me with this.


Solution

  • This seems a lot more complex than it needs to be. Note that you don't need to write a temporary file to load that data into R - you could use read.csv directly using the text = argument. Also, geom_bar(stat = "identity") is just a long way of writing geom_col. The data argument of each layer is not required because it is inherited from the main ggplot call.

    Probably the neatest way to label your legend would be to use the fill, alpha and color scale for the bars, ribbon and line respectively. For this, you map each to the desired legend label as a string inside aes, then add a manual scale for each:

    ggplot(data = datos, aes(x = dia, y = TEMP_M)) +
      geom_col(aes(fill = "agenda")) +
      geom_ribbon(aes(ymin = TEMP_M*0.5, ymax = TEMP_M*1.5, alpha = 'limite')) +
      geom_line(aes(y = TEMP_M, color = "control")) +
      scale_fill_manual(NULL, values = 'steelblue') +
      scale_color_manual(NULL, values = 'black') +
      scale_alpha_manual(NULL, values = 0.5) +
      labs(x = "Hour", y = "Temperature") +
      theme(legend.key = element_rect(fill = "white"))
    

    enter image description here

    As a side note, there is absolutely no reason to have both a line and bars here. From a data visualization perspective, this is just a waste of ink. The same data can be shown more clearly with just three lines.

    ggplot(data = datos, aes(x = dia, y = TEMP_M)) +
      geom_ribbon(aes(ymin = TEMP_M*0.5, ymax = TEMP_M*1.5, linetype = 'limite'),
                  alpha = 0, color = 'black', show.legend = FALSE) +
      geom_line(aes(y = TEMP_M, linetype = "control")) +
      labs(x = "Hour", y = "Temperature", linetype = NULL) +
      theme_classic(base_size = 16) 
    

    enter image description here