Home > Back-end >  Iteratively plot columns and reset ylab dynamically using ggplot2
Iteratively plot columns and reset ylab dynamically using ggplot2

Time:11-24

Given dataframes df1 and df2 as follows:

df1:

df1 <- structure(list(date = structure(c(1L, 2L, 4L, 5L, 6L, 7L, 8L, 
9L, 10L, 11L, 3L), .Label = c("2021/1/31", "2021/2/1", "2021/2/10", 
"2021/2/2", "2021/2/3", "2021/2/4", "2021/2/5", "2021/2/6", "2021/2/7", 
"2021/2/8", "2021/2/9"), class = "factor"), value1 = c(9.76, 
9.76, 9.88, 9.31, 9.71, 9.56, 9.27, 9.22, 9.21, 9.08, 8.78), 
    value2 = c(6.84, 6.88, 6.95, 6.65, 6.94, 6.85, 6.66, 6.66, 
    6.6, 6.5, 6.25), value3 = c(6.33, 6.21, 6.31, 6.2, 6.56, 
    6.36, 6.36, 6.25, 6.1, 6.02, 5.76), value4 = c(10.68, 10.91, 
    11, 10.49, 10.8, 10.5, 10.2, 9.85, 10.03, 9.8, 9.51), value5 = c(7.77, 
    7.84, 7.83, 7.44, 7.83, 7.77, 7.6, 7.46, 7.46, 7.39, 7.29
    )), class = "data.frame", row.names = c(NA, -11L))

df2:

df2 <- structure(list(type = structure(c(2L, 2L, 3L, 3L, 1L), .Label = c("pct_change", 
"price", "quantity"), class = "factor"), columns = structure(1:5, .Label = c("value1", 
"value2", "value3", "value4", "value5"), class = "factor"), unit = structure(c(3L, 
3L, 1L, 1L, 2L), .Label = c("", "%", "$"), class = "factor")), class = "data.frame", row.names = c(NA, 
-5L))

With code below, I'm able to loop all columns based df2, which means for each columns, if its type are identical, then plot them on same plot and finally save them with name of type.

library(ggplot2)
library(data.table)
df1$date <- as.Date(df1$date)
df1.m <- melt(df1, id = "date")  # convert to long format
# add "type" variable to df1.m
df1.m2 = merge(df1.m, df2, by.x = "variable", by.y = "columns")

# for each "type", filter the data to that type, plot, and save    
for(my_type in unique(df1.m2$type)) {
  g <- ggplot(data = df1.m2[df1.m2$type == my_type,],
       aes(x=date, y = value, colour=variable))  
  geom_line(size = 1, alpha = 1) 
  print(g)
  # ggsave(paste0(my_type,".png"))
}

Now I hope to reset ylab() for each plot, which means if its type is identical, then set its ylab() using unit from df2.

I try code below, but it's not working:

for(my_type in unique(df1.m2$type)) 
  for (my_unit in unique(df1.m2$unit)){
  g <- ggplot(data = df1.m2[df1.m2$type == my_type,],
       aes(x=date, y = value, colour=variable))  
    ylab(my_unit)  
  geom_line(size = 1, alpha = 1) 
  print(g)
  # ggsave(paste0(my_type,".png"))
}

How could I achieve that based on code above? Sincere thanks at advance.

CodePudding user response:

Not sure what you tried with the nested for. As far as I get it you could achieve your desired result by using the unique(unit) of your filtered dataset as the label for y scale:

library(ggplot2)
 
for(my_type in unique(df1.m2$type)) {
  d <- df1.m2[df1.m2$type == my_type,]
  g <- ggplot(data = d,
              aes(x=date, y = value, colour=variable))  
    geom_line(size = 1, alpha = 1)  
    labs(y = unique(d$unit))
  print(g)
}

CodePudding user response:

Here's an alternative approach which avoids looping through the dataframe altogether.

  1. Convert df1 to long format and rename name to columns

  2. Join to df2 on columns

  3. Mutate column type to include the units

  4. Plot value versus date, color by columns and facet by type

  5. Make some theme adjustments to display type and units on each facet axis

    library(ggplot2)
    library(dplyr)
    library(tidyr)
    
    df1 %>% 
      pivot_longer(2:6, 
                   names_to = "columns") %>% 
      left_join(df2) %>% 
      mutate(type = paste(type, unit)) %>% 
      ggplot(aes(date, value))   
      geom_line(aes(color = columns, 
                    group = columns))   
      facet_grid(type ~ ., 
                 switch = 'y', 
                 scales = "free_y")  
      theme(axis.title.y = element_blank(),
      strip.background = element_rect(fill = 'transparent'),
      strip.placement = 'outside',
      strip.text.y = element_text(angle=180))
    

Result:

enter image description here

CodePudding user response:

for(my_type in unique(df1.m2$type)) {
  
  g <- ggplot(
      data = df1.m2[type == my_type],
      aes(x=date, y = value, colour=variable)
    )  
    scale_y_continuous(labels = function(x) {
      if(my_type == "price") { 
        paste("$", x)
      } else if(my_type == "pct_change") {
        paste(x, "%")
      } else {
        x
      }
    })  
    geom_line(size = 1, alpha = 1) 
    print(g)
  # ggsave(paste0(my_type,".png"))
}

enter image description here enter image description here enter image description here

  • Related