Home > Software engineering >  ggplot2 plot two columns with same x axis
ggplot2 plot two columns with same x axis

Time:05-24

I have a data frame with 3 columns:

  1. A date time column
  2. water level of a pond over 2 years (hourly)
  3. daily precipitation over 2 years (daily)

I want to plot the date time on the x axis and the other two as two separate y axis.

I've tried with ggplot2, but this seems like quite a tricky thing to do. Does anyone know of any solutions or of any other methods.

Thankyou.

This is my current code. I don't know how to add in the data for a second axis however. (It is in a for loop as I have multiple locations within the pond. They all have the same data layout.)

scaleFUN <- function(x) sprintf("%.2f", x)
plotlist_mAODdate <- list()

j = 1   # counter for plot title and index
for (datTime in mAODdata){
  plotName <- names(mAODdata)[j]
  j = j 1
  plot <- 
    datTime %>%
    ggplot()  
    geom_point(aes_string(x='DateTime', y='Rel_mAOD'), col='grey')  
    geom_smooth(aes_string(x='DateTime', y='Rel_mAOD'))  
    theme_classic()  
    labs(y='Water Depth (mAOD)', x=NULL)  
    ggtitle(plotTitles[[plotName]][1])   
    scale_x_datetime(
      breaks=seq(min(datTime$DateTime), max(datTime$DateTime), 
                 by= "6 months"), date_labels="%b-%y")  
    scale_y_continuous(labels=scaleFUN)  
    geom_vline(xintercept=as.POSIXct('2020-11-03 01:00:00'), col='red')  
    geom_vline(xintercept=as.POSIXct('2021-11-01 01:00:00'), col='red', linetype='dashed')  
    theme(text=element_text(size=20, family='Calibri Light'))  
    theme(plot.margin = unit(c(1, 1, 1, 1), 'cm'))  
    theme(axis.title.y=element_text(margin=margin(t=0, r=20, b=0, l=0)))  
    theme(axis.title.x=element_text(margin=margin(t=20, r=0, b=0, l=0)))
  
  plotlist_mAODdate[[plotName]] <- plot
}

CodePudding user response:

Since you mentioned other methods, you can do this in base R by:

Data

df <- data.frame(date = seq(as.Date('2021-01-01'),as.Date('2022-12-31'), by = 1),
                 water = 250   1:730*2,
                 precipitation = 0   (1:730)^2)

Code

par(mar = c(5.1, 4.1, 4.1, 4.1))
plot(x = df$date, y = df$water, type = "l", col = "red", bty = "n", ylab = "", xlab = "")
  par(new = TRUE)
  plot(x = df$date, y = df$precipitation, type = "l", col = "blue", axes = FALSE, xlab = "", ylab = "")
  axis(side = 4)
  mtext("Year", side = 1, padj = 4)
  mtext("Water", side = 2, padj = -4)
  mtext("Precipitation", side = 4,, padj = 4, srt = -90)
  legend("topleft", c("Water","Precipitation"), lty = 1, col = c("red","blue"), bty = "n")

Output enter image description here

Multiple locations

If you have multiple locations, you can do:

Data

set.seed(123)
df2 <- data.frame(date = seq(as.Date('2021-01-01'),as.Date('2022-12-31'), by = 1),
                   water = 250   1:730*2,
                   precipitation = 0   (1:730)^2,
                   location = sample(LETTERS[1:4], 730, replace = TRUE))

Code

par(mfrow = c(floor(length(unique(df2$location))/2), 2), mar = c(5.1, 4.1, 4.1, 4.1))
for(i in sort(unique(df2$location))){
  plot(x = df2[df2$location == i, "date"], y = df2[df2$location == i, "water"], type = "l", col = "red", bty = "n", ylab = "", xlab = "")
  par(new = TRUE)
  plot(x = df2[df2$location == i, "date"], y = df2[df2$location == i, "precipitation"], type = "l", col = "blue", axes = FALSE, xlab = "", ylab = "")
  axis(side = 4)
  mtext(paste0("Location: ", i), side = 3, adj = 0)
  mtext("Year", side = 1, padj = 4)
  mtext("Water", side = 2, padj = -4)
  mtext("Precipitation", side = 4,, padj = 4, srt = -90)
  legend("topleft", c("Water","Precipitation"), lty = 1, col = c("red","blue"), bty = "n")
}

Output enter image description here

CodePudding user response:

I used the sec.axis method with

geom_point(aes(y=(prcp_amt/150) 72), col='blue') 

and

scale_y_continuous(sec.axis = sec_axis(~(.-72)*150, name='Precipitation (mm)') 

and rescaling the data, so they both fit on the same scale. I know this isn't the best method, but I needed the rest of the ggplot2 to make the appearance of the graphs. This is how it's incorporated into the full code.

scaleFUN <- function(x) sprintf("%.2f", x)
plotlist_mAODdate <- list()

j = 1   # counter for plot title and index
for (datTime in mAODdata){
  plotName <- names(mAODdata)[j]
  j = j 1
  plot <- 
    datTime %>%
    ggplot(aes(x=DateTime))  
    geom_point(aes(y=Rel_mAOD), col='grey')  
    geom_smooth(aes(y=Rel_mAOD), col='black')  
    geom_point(aes(y=(prcp_amt/150) 72), col='blue')  
    theme_classic()  
    labs(y='Water Depth (mAOD)', x=NULL)  
    ggtitle(plotTitles[[plotName]][1])   
    scale_x_datetime(
      breaks=seq(min(datTime$DateTime), max(datTime$DateTime), 
                 by= "6 months"), date_labels="%b-%y")  
    scale_y_continuous(labels=scaleFUN, sec.axis = sec_axis(~(.-72)*150, name='Precipitation (mm)'))  
    geom_vline(xintercept=as.POSIXct('2020-11-03 01:00:00'), col='red')  
    geom_vline(xintercept=as.POSIXct('2021-11-01 01:00:00'), col='red', linetype='dashed')  
    theme(text=element_text(size=20, family='Calibri Light'))  
    theme(plot.margin = unit(c(1, 1, 1, 1), 'cm'))  
    theme(axis.title.y=element_text(margin=margin(t=0, r=20, b=0, l=0)))  
    theme(axis.title.x=element_text(margin=margin(t=20, r=0, b=0, l=0)))
  
  plotlist_mAODdate[[plotName]] <- plot
}
  • Related