rggplot2ggh4x

secondary axis is not working properly with geom_col


I am trying to use help_secondary of ggh4x with geom_col like

library(tidyverse)
library(ggh4x)
library(scales) 

# Run the secondary axis helper
sec <- help_secondary(df, primary = c(Tmax, Tmin, RH), 
                      secondary = Rainfall)

ggplot(df, aes(x = Date)) +
  geom_col(aes(y = sec$proj(Rainfall)), colour = "blue") +
  geom_line(aes(y = Tmax), colour = "red") +
  geom_line(aes(y = Tmin), colour = "green") +
  geom_line(aes(y = RH), colour = "black") +
  scale_y_continuous(sec.axis = sec) +
  ylab("Max and Min temperature, RH")

enter image description here

As you can see from the plot, the secondary y-axis starts at -500. The 0 rainfall value is shown as -500 which ideally should be left out in the barplot.

Another thing, how can I have the legend?

Data

df = structure(list(Date = structure(c(18628, 18659, 18687, 18718, 
18748, 18779, 18809, 18840, 18871, 18901, 18932, 18962, 18993, 
19024, 19052, 19083, 19113, 19144, 19174, 19205, 19236, 19266, 
19297, 19327, 19358, 19389, 19417, 19448, 19478, 19509, 19539
), class = "Date"), Tmax = c(34.3774193548387, 34.8428571428571, 
35.7387096774194, 35.44, 34.1161290322581, 30.9333333333333, 
29.2193548387097, 29.9225806451613, 29.78, 32.4096774193548, 
32.97, 32.4129032258065, 32.2225806451613, 33.9428571428571, 
35.6, 35.2133333333333, 33.658064516129, 31.0566666666667, 29.4516129032258, 
29.6548387096774, 30.2066666666667, 32.4870967741935, 34.2566666666667, 
34.558064516129, 33.8161290322581, 36.3821428571429, 35.9483870967742, 
35.2266666666667, 35.9709677419355, 33.04, 28.6322580645161), 
    Tmin = c(21.5483870967742, 20.4714285714286, 24.1483870967742, 
    24.41, 25.2354838709677, 23.3966666666667, 23.2129032258064, 
    23.7935483870968, 24.6633333333333, 24.0225806451613, 23.3466666666667, 
    20.8516129032258, 19.3806451612903, 19.5, 23.558064516129, 
    24.9533333333333, 25.8741935483871, 23.92, 23.3709677419355, 
    22.8677419354839, 22.5433333333333, 21.7161290322581, 21.2133333333333, 
    21.0258064516129, 19.3612903225807, 20.6142857142857, 21.641935483871, 
    24.5343333333333, 26.0903225806452, 25.4443333333333, 23.7645161290323
    ), RH = c(62.1129032258064, 57.5892857142858, 70.4193548387097, 
    68.25, 74.8387096774194, 85.3333333333333, 88.5161290322581, 
    85.8870967741936, 86.4333333333334, 79.1129032258064, 74.6, 
    69.1935483870968, 62.6290322580645, 65.5892857142858, 66.3548387096774, 
    70.7166666666667, 75.7741935483871, 85.6833333333334, 88.3387096774194, 
    86.8064516129033, 84.1166666666667, 74.3870967741936, 64.4, 
    63.7903225806452, 60.1290322580645, 58.7321428571429, 58.4677419354839, 
    69.3, 65.9193548387097, 79.45, 91.6451612903226), Rainfall = c(9.1, 
    2, 0, 27, 422.6, 903.9, 1345.9, 343.9, 481, 239.9, 166.4, 
    105.9, 0, 0, 0.3, 51.2, 99.6, 700.6, 1098.3, 347.6, 276.8, 
    71.3, 0, 2.2, 0, 0, 0, 0, 0, 597, 1763.4)), row.names = c(NA, 
31L), class = "data.frame")

Solution

  • The issue is that by default help_secondary will rescale the based on the range of the variables mapped on the primary and the secondary axis, i.e. the primary minimum is mapped on the secondary minimum.

    However, as you are using a geom_col the range or the limits of the y scale are extended to include 0. This is not and can't be accounted for by help_secondary.

    For your case, where the minimum of the secondary variable is zero, you could fix that by switching to method="max" in help_secondary.

    To get a legend, you have to map on aesthetics, i.e. move color= inside aes() and set your colors via scale_color_manual.

    library(ggplot2)
    library(ggh4x)
    library(scales)
    
    sec <- help_secondary(df,
      primary = c(Tmax, Tmin, RH),
      secondary = Rainfall,
      method = "max"
    )
    
    ggplot(df, aes(x = Date)) +
      geom_col(aes(y = sec$proj(Rainfall), color = "rain")) +
      geom_line(aes(y = Tmax, color = "tmax")) +
      geom_line(aes(y = Tmin, color = "tmin")) +
      geom_line(aes(y = RH, color = "rh")) +
      scale_color_manual(
        values = c(
          tmin = "green", tmax = "red",
          rh = "black", rain = "blue"
        )
      ) +
      scale_y_continuous(sec.axis = sec) +
      ylab("Max and Min temperature, RH")
    

    EDIT To fix the legend, map on the fill aes to get filled bars, apply the color scale both on the color and fill aes by adding aesthetics = c("fill", "color"), set the same name for both scales (so that both legends get merged) and tweak the legend via the override.aes argument of guide_legend, i.e. remove the legend fill for the lines:

    ggplot(df, aes(x = Date)) +
      geom_col(aes(y = sec$proj(Rainfall), fill = "rain")) +
      geom_line(aes(y = Tmax, color = "tmax")) +
      geom_line(aes(y = Tmin, color = "tmin")) +
      geom_line(aes(y = RH, color = "rh")) +
      scale_color_manual(
        values = c(
          tmin = "green", tmax = "red",
          rh = "black", rain = "blue"
        ),
        aesthetics = c("fill", "color")
      ) +
      scale_y_continuous(sec.axis = sec) +
      labs(y = "Max and Min temperature, RH", color = NULL, fill = NULL) +
      guides(color = guide_legend(
        override.aes = list(fill = c("blue", rep("transparent", 3)))
      ))
    

    enter image description here