Search code examples
rggplot2plottransformationyaxis

How can I adjust the second Y-axis scale with ggplot2?


I'm trying to compare two temperature variables in a single plot. Initially, I generated this plot:

Plot 01

enter image description here

However, the second variable, represented in green, doesn't completely fit within the plot.

To accommodate the green line, I manipulated the axis transformation in my code, resulting in this new plot:

Plot 02

enter image description here

Unfortunately, the values on the second Y-axis (highlighted in yellow) are not accurate. Ideally, I would like the axis limits to be around c(0, 60). I'm not sure how to set the second Y-axis to start from zero.

I'd be very grateful for your help.

Here's the code I've been working on:

rm(list = ls())   # Resetear o limpiar todos los objetos del area de trabajo
graphics.off()    # Resetear o limpiar area de graficos

# Load necessary libraries
library(ggplot2)
library(tidyr)


# Data
tem.perception <- c(55, 58, 57, 11,  0,  0,  0,  4, 15, 18, 22, 35)

tem.inahmi <- read.table(header = TRUE, sep = ",",
text = "year,ENE,FEB,MAR,ABR,MAY,JUN,JUL,AGO,SEP,OCT,NOV,DIC
1980,25.1,25.1,25.8,24.1,26.3,25.1,26.0,25.1,25.1,23.3,25.1,25.1
1981,27.3,28.3,27.5,27.3,25.3,23.7,22.5,22.7,25.5,25.5,25.5,25.2
1982,25.6,26.9,27.8,28.1,27.6,25.5,25.2,24.5,26.5,26.5,26.5,26.9
1983,26.3,27.3,27.2,26.7,27.0,26.3,25.5,26.3,24.9,25.4,26.3,26.8
1984,27.3,26.8,27.0,26.7,26.0,25.0,24.6,24.8,25.2,25.4,25.9,26.5
1985,27.3,27.1,27.0,26.7,26.0,25.0,24.6,24.8,25.2,25.4,25.9,26.5
1986,27.3,27.1,27.0,26.7,26.0,23.6,24.6,24.8,24.2,25.4,25.9,26.3
1987,27.3,27.1,27.0,26.7,26.0,25.0,24.6,24.8,25.2,25.4,25.9,26.5
1988,27.3,27.1,27.0,26.7,26.0,25.0,24.6,24.8,25.2,25.4,25.9,26.5
1989,27.3,27.1,27.0,26.7,26.0,25.0,24.6,24.8,25.2,25.4,25.9,26.5
1990,27.3,27.1,27.0,26.7,26.0,25.0,24.6,24.8,25.2,25.4,25.9,26.5
1991,26.3,27.8,27.6,27.8,27.7,25.6,26.3,23.6,24.8,25.4,25.8,27.3
1992,28.5,27.7,26.0,26.5,25.9,26.0,24.4,24.4,24.4,25.7,25.8,26.7
1993,27.6,27.0,26.8,26.3,24.3,24.2,26.0,26.0,26.0,26.0,26.0,26.0
1994,27.3,27.1,27.0,26.7,26.0,25.0,24.6,24.8,25.2,25.4,25.9,26.5
1995,28.3,26.2,28.1,27.7,27.0,26.2,24.1,24.5,25.1,25.6,26.1,25.9
1996,27.4,28.5,27.5,27.6,26.5,24.2,23.1,23.7,24.8,24.8,25.4,26.7
1997,27.4,28.2,28.0,27.3,26.9,26.1,27.0,27.2,28.0,27.1,27.4,27.6
1998,27.8,28.0,27.5,26.7,25.5,24.7,25.2,24.3,26.2,25.3,26.2,26.6
1999,27.5,26.5,26.6,26.2,25.8,25.8,23.6,25.8,24.5,25.8,26.0,25.8
2000,27.6,25.9,26.4,25.9,25.9,25.9,24.1,25.9,25.2,25.9,26.0,25.9
2001,27.1,27.1,27.0,26.7,26.0,25.0,24.6,24.6,25.0,25.4,25.9,27.2
2002,27.3,28.3,27.0,26.7,26.0,25.0,24.6,25.1,25.8,25.4,25.9,26.5
2003,27.7,27.1,28.2,26.7,26.0,25.0,24.6,24.8,25.2,25.4,25.9,26.5
2004,28.6,27.1,27.0,26.7,26.0,25.0,24.6,24.8,25.2,25.5,25.8,27.0
2005,28.3,27.3,26.8,27.4,27.0,26.1,24.7,24.6,24.4,24.7,25.7,26.5
2006,27.6,26.9,26.2,26.3,25.4,24.3,24.2,25.1,25.9,26.1,27.0,27.6
2007,28.1,28.8,28.3,27.0,26.7,24.9,25.0,24.3,25.0,24.7,26.1,26.4
2008,26.2,26.0,25.9,26.0,24.1,22.2,23.3,24.2,25.5,25.3,25.7,26.8
2009,26.7,26.0,26.1,25.9,25.3,24.3,24.7,24.9,25.4,25.9,25.8,26.6
2010,26.8,26.6,26.4,26.0,25.1,24.7,23.6,24.3,24.3,24.8,25.2,26.0
2011,27.6,27.1,27.8,27.2,25.8,25.2,24.1,24.5,25.2,24.7,26.1,26.2
2012,27.3,27.1,27.0,26.7,26.0,25.0,24.6,24.8,25.2,25.4,25.9,26.5
2013,25.2,25.2,25.2,26.4,25.3,24.5,24.3,24.6,24.7,25.2,25.1,26.7
" )

tem.inahmi$year <- as.factor(tem.inahmi$year)  # Convert the 'year' column to a factor

# see max and min
max(tem.perception); min(tem.perception)
max(tem.inahmi[,2:13]); min(tem.inahmi[,2:13])

# Melt the data into long format to have month, year, and value columns
tem.inahmi_melted <- tem.inahmi %>% 
  gather(key = "month", value = "value", -year)

# Creating a month factor variable with custom levels for correct ordering
tem.inahmi_melted$month <- factor(tem.inahmi_melted$month, levels = c("ENE", "FEB", "MAR", "ABR", "MAY", "JUN", "JUL", "AGO", "SEP", "OCT", "NOV", "DIC"))

# Create a dataframe for the geom_line data
tem.geom_line <- data.frame(
  month = factor(c("ENE", "FEB", "MAR", "ABR", "MAY", "JUN", "JUL", "AGO", "SEP", "OCT", "NOV", "DIC"), 
                 levels = c("ENE", "FEB", "MAR", "ABR", "MAY", "JUN", "JUL", "AGO", "SEP", "OCT", "NOV", "DIC")),
  #value = (tem.perception*0.15)+20.5  #for the fitted plot
  value = tem.perception
)

# Construct the basic ggplot2
tem.plot <- ggplot(tem.inahmi_melted, aes(x = month, y = value)) +
  geom_boxplot(aes(colour = "INAMHI"), fill = "NA") +  # Boxplot with blue border
  geom_line(data = tem.geom_line, aes(y = value, colour = "Percepción"), group = 1, size = 0.8) +  # Geom line in red
  scale_color_manual(name = "", values = c("INAMHI" = "#F8766D", "Percepción" = "#00BA38")) +  # Assign colors
  #scale_y_continuous( sec.axis = sec_axis(~.*2-21, name = "Percepción [Nro. respuestas]")) +  #for the fitted plot
  scale_y_continuous( sec.axis = sec_axis(~., name = "Percepción [Nro. respuestas]")) +  # Second Y axis 
  
  theme_minimal() +
  xlab("Mes") +
  ylab("Temperatura [°C]")+
  labs(title = "TEMPERATURE (Inahmi vs Perception)")  +
  theme(legend.position="bottom",
        axis.title.y = element_text(color = "#F8766D"),  # Y axis label color in blue
        axis.title.y.right = element_text(color = "#00BA38"),  # Second Y axis label color in red
        axis.text.y = element_text(color = "#F8766D"),  # Y axis text color in blue
        axis.text.y.right = element_text(color = "#00BA38")) +
  coord_cartesian(ylim = c(21, 31))

print(tem.plot)

To achieve the second plot, I only changed these two lines in my script:

#value = (tem.perception*0.15)+20.5  #for the fitted plot
#scale_y_continuous( sec.axis = sec_axis(~.*2-21, name = "Percepción [Nro. respuestas]")) +  #for the fitted plot

Solution

  • The transform on tem.geom_line$value and the reverse-transform given within sec_axis should be perfect complements of each other.

    Sticking with your first transform,

    tem.geom_line <- data.frame(
      month = factor(c("ENE", "FEB", "MAR", "ABR", "MAY", "JUN", "JUL", "AGO", "SEP", "OCT", "NOV", "DIC"), 
                     levels = c("ENE", "FEB", "MAR", "ABR", "MAY", "JUN", "JUL", "AGO", "SEP", "OCT", "NOV", "DIC")),
      value = (tem.perception*0.15)+20.5  #for the fitted plot
      # value = tem.perception
    )
    

    I'll change your second transform to sec_axis(~ (. - 20.5) / 0.15, ...).

    ggplot(tem.inahmi_melted, aes(x = month, y = value)) +
      geom_boxplot(aes(colour = "INAMHI"), fill = "NA") +  # Boxplot with blue border
      geom_line(data = tem.geom_line, aes(y = value, colour = "Percepción"), group = 1, size = 0.8) +  # Geom line in red
      scale_color_manual(name = "", values = c("INAMHI" = "#F8766D", "Percepción" = "#00BA38")) +  # Assign colors
      #scale_y_continuous( sec.axis = sec_axis(~.*2-21, name = "Percepción [Nro. respuestas]")) +  #for the fitted plot
      scale_y_continuous( sec.axis = sec_axis(~ (. - 20.5) / 0.15, name = "Percepción [Nro. respuestas]")) +  # Second Y axis 
      
      theme_minimal() +
      xlab("Mes") +
      ylab("Temperatura [°C]")+
      labs(title = "TEMPERATURE (Inahmi vs Perception)")  +
      theme(legend.position="bottom",
            axis.title.y = element_text(color = "#F8766D"),  # Y axis label color in blue
            axis.title.y.right = element_text(color = "#00BA38"),  # Second Y axis label color in red
            axis.text.y = element_text(color = "#F8766D"),  # Y axis text color in blue
            axis.text.y.right = element_text(color = "#00BA38")) +
      coord_cartesian(ylim = c(21, 31))
    

    enter image description here