Search code examples
rggplot2transformationlinegraph

How can I insert a line graph (ylim = 27. 30) into another diagram with 2 line graphs (ylim=0,120) without distortion?


I need to visualize data of different character (temperature, light intensity, rel. humidity) for a kind of climate diagram. My problem, I believe, lies within the different ylims, which prevent an easy transformation to combine the graphs into one diagram. If I put in the temperature graph as in the code below, the fluctuation of the temperature becomes invisible due to the different scales of the diagram from plot_humidity.

Temperature graph inserted without transformation does not sufficiently show variation over time:

plot_humidity <- ggplot(df, aes(x = datetime, y = mean_humidity)) +
  geom_line(aes(y = mean_humidity, color = "Rel. humidity", group = 1), linewidth = 1) +
  geom_line(aes(y = mean_Light/100, color = "Light intensity", group = 2), linewidth = 1) +
  geom_line(aes(y = mean_Temperature, color = "Temperature", group = 3), linewidth = 1) +
  geom_ribbon(aes(ymin= mean_humidity - sd_humidity,
                  ymax= mean_humidity + sd_humidity,
                  fill = "Rel. humidity",  color = "Rel. humidity"),
              alpha=0.2, group = 1) +
  geom_ribbon(aes(ymin= (mean_Light/100) - (sd_Light/100),
                  ymax= (mean_Light/100) + (sd_Light/100),
                  fill = "Light intensity", color = "Light intensity"),
              alpha=0.2, group = 2) +
  geom_ribbon(aes(ymin= mean_Temperature - sd_Temperature,
                  ymax= mean_Temperature + sd_Temperature,
                  fill = "Temperature", color = "Temperature"),
              alpha=0.2, group = 3) +
  labs( x = "time", y = "relative humidity (in %)", color = "Variable") +
  scale_color_manual(values = c("Light intensity" = "green", "Temperature" = "red", "Rel. humidity" = "blue")) +
  scale_fill_manual(values = c("Light intensity" = "green", "Temperature" = "red", "Rel. humidity" = "blue")) +
  scale_x_datetime(breaks = "1 hour", date_labels = "%H",
                   limits = as.POSIXct(strptime(c("2022-12-23 01:00:00", "2022-12-24 01:00:00"),
                                                format = "%Y-%m-%d %H:%M:%S")),
                   expand = c(0, 0)) +
  theme(axis.line.y.left =  element_line( color = "blue"),
        axis.text.y.left = element_text(color = "blue"),
        plot.margin = margin(10, 10, 10, 30)) +
  guides(fill = "none") +
  scale_y_continuous(limits = c(), sec.axis = sec_axis(~ . * 100, name = "light intensity (in lux)")) +
  theme(axis.text.y.right = element_text(color = "green"),
        axis.line.y.right = element_line(color = "green"))



  plot <- wrap_elements(get_plot_component(plot_temperature, "ylab-l")) +
  wrap_elements(get_y_axis(plot_temperature)) +
  plot_humidity +
  plot_layout(widths = c( 3, 1, 40))

Instead of the red graph in the diagram above, I want to have it look like below and overlap with the other graphs.

single temperature graph

plot_temperature <- ggplot(df, aes(x = datetime, y = mean_Temperature)) +
  geom_line(aes(y= mean_Temperature, color = "Temperature"), linewidth = 1) +
  geom_ribbon(aes(ymin= mean_Temperature - sd_Temperature,
                  ymax= mean_Temperature + sd_Temperature,
                  fill = "Temperature", color = "Temperature"), alpha = 0.2) +
  labs(y = "mean temperature (in °C) +/- standard deviation") +
  scale_color_manual(values = "red") +
  theme(axis.line.y.left =  element_line( color = "red"),
        axis.text.y.left = element_text(color = "red"),) +
  scale_x_datetime(breaks = "1 hour", date_labels = "%H",
                   limits = as.POSIXct(strptime(c("2022-12-23 01:00:00", "2022-12-24 01:00:00"),
                                                format = "%Y-%m-%d %H:%M:%S")),
                   expand = c(0, 0))

My original plan was to use ggplot and wrap_elements to fuse the different parts of the diagrams (y-axis, ylab, geom_line, geom_ribbon) into one diagram. This is not a problem for the light intensity graph, but the temperature graph is a problem. I can´t just transform the data, or can I? And I haven´t found a way to extract geom_line and geom_ribbon from the single temperature diagram to lay it over plot_humidity, but I would be fine with that as well, if there is no more elegant solution to it.

Is there anything obvious that I am missing? Since I am still learning about R and the work that includes this figure is my first big effort, I appreciate any tips you can give me!

EDIT: Here is my df


Solution

  • If you try transforming your values in plot 1 and back-transforming your scales in plot 2 (with same limits) then this should work:

    library(tidyverse)
    
    file_path <- "datalogger.csv"
    
    df <- read_csv(file_path) |>
      mutate(
        mean_Temperature = Durchschnitt_Temperatur,
        mean_Light = Durchschnitt_Licht,
        mean_humidity = Durchschnitt_Feuchtigkeit,
        sd_Temperature = sd_Temperatur,
        sd_Light = sd_Licht,
        sd_humidity = sd_Feuchtigkeit
      )
    
    g1 <- df |>
      ggplot(aes(time)) +
      geom_line(aes(y = mean_humidity, colour = "Rel. humidity")) +
      geom_line(aes(y = mean_Light / 100, colour = "Light intensity")) +
      geom_line(aes(y = (mean_Temperature - 27) * 40, colour = "Temperature")) +
      geom_ribbon(aes(ymin= mean_humidity - sd_humidity,
                      ymax= mean_humidity + sd_humidity,
                      fill = "Rel. humidity",  color = "Rel. humidity"),
                  alpha=0.2, group = 1) +
      geom_ribbon(aes(ymin= (mean_Light/100) - (sd_Light/100),
                      ymax= (mean_Light/100) + (sd_Light/100),
                      fill = "Light intensity", color = "Light intensity"),
                  alpha=0.2, group = 2) +
      geom_ribbon(aes(ymin= (mean_Temperature - 27 - sd_Temperature) * 40,
                      ymax= (mean_Temperature - 27 + sd_Temperature) * 40,
                      fill = "Temperature", color = "Temperature"),
                  alpha=0.2, group = 3) +
      scale_y_continuous(
        sec.axis = sec_axis(~ . * 100, name = "light intensity (in lux)"),
        limits = c(-10, 120)
      ) +
      scale_color_manual(values = c(
        "Light intensity" = "green",
        "Temperature" = "red",
        "Rel. humidity" = "blue"
      ), 
      aesthetics = c("fill", "colour")) +
      labs( x = "time", y = "relative humidity (in %)", color = "Variable") +
      theme(
        axis.line.y.left =  element_line(color = "blue"),
        axis.text.y.left = element_text(color = "blue"),
        plot.margin = margin(10, 10, 10, 30),
        axis.text.y.right = element_text(color = "green"),
        axis.line.y.right = element_line(color = "green"),
        text = element_text(size = 8)
      ) +
      guides(fill = "none")
    
    
    g2 <- df |>
      ggplot(aes(time, mean_Temperature)) +
      geom_line(aes(colour = "Temperature")) +
      theme(
        axis.line.y.left =  element_line(color = "red"),
        axis.text.y.left = element_text(color = "red"),
        text = element_text(size = 8)
      ) +
      scale_y_continuous(
        sec.axis = sec_axis(~ (. / 40) +27 , name = "Temperature"),
        position = "right",
        limits = c(-10, 120)
      )
    
    library(patchwork)
    library(cowplot)
    
    wrap_elements(get_plot_component(g2, "ylab-l")) +
      wrap_elements(get_y_axis(g2, position = "left")) +
      g1 +
      plot_layout(widths = c(3, 1, 40))