Итеративно стройте столбцы и динамически сбрасывайте ylab с помощью ggplot2

#r #for-loop #ggplot2

Вопрос:

Заданные фреймы данных df1 и df2 следующим образом:

df1:

 df1 lt;- 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 lt;- 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))  

С помощью приведенного ниже кода я могу зациклить все столбцы на основе df2 , что означает , что для каждого столбца, если их типы идентичны, затем построить их на одном графике и, наконец, сохранить их с именем типа.

 library(ggplot2) library(data.table) df1$date lt;- as.Date(df1$date) df1.m lt;- 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 lt;- 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")) }  

Теперь я надеюсь сбросить ylab() значение для каждого участка, что означает, что если его тип идентичен, то установите его ylab() с помощью unit df2 .

Я пробую код ниже, но он не работает:

 for(my_type in unique(df1.m2$type))   for (my_unit in unique(df1.m2$unit)){  g lt;- 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")) }  

Как я мог бы достичь этого на основе приведенного выше кода? Искренняя благодарность заранее.

Ответ №1:

Не уверен, что вы пробовали с вложенными for . Насколько я понимаю, вы могли бы достичь желаемого результата, используя unique(unit) отфильтрованный набор данных в качестве метки для y масштаба:

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

Комментарии:

1. Смогли ли вы устранить эту проблему? В общем случае это означает, что вы пытаетесь использовать функцию в качестве фрейма данных. Если бы я догадался, я бы сказал, что вы переименовали фрейм данных, который я вызвал d , df но пропустили, чтобы заменить его во всех строках кода.

2. Да, я совершил ошибку.

Ответ №2:

Вот альтернативный подход, который позволяет полностью избежать зацикливания на фрейме данных.

  1. Преобразовать df1 в длинный формат и переименовать name в columns
  2. Присоединяйтесь к df2 on columns
  3. Измените столбец type , чтобы включить единицы измерения
  4. Значение графика в зависимости от даты, цвета columns и фасета по type
  5. Внесите некоторые изменения в тему для отображения типа и единиц измерения на каждой оси фасета
     library(ggplot2) library(dplyr) library(tidyr)  df1 %gt;%   pivot_longer(2:6,   names_to = "columns") %gt;%   left_join(df2) %gt;%   mutate(type = paste(type, unit)) %gt;%   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))  

Результат:

введите описание изображения здесь

Комментарии:

1. Это довольно классный альтернативный подход, я его протестирую.

2. Если у меня будет много столбцов, он сгенерирует все подзаголовки в одном графике, верно?

3. Да, будет столько аспектов, для которых есть значения type , поэтому это может не подойти, если их слишком много. В этом случае я бы все равно развернулся, присоединился и мутировал, но затем filter по типу для создания отдельных участков.

Ответ №3:

 for(my_type in unique(df1.m2$type)) {    g lt;- 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")) }  

Или используйте вместо if else переключатель

 scale_y_continuous(labels = function(x) {  switch(my_type, "price" = paste("$", x), "pct_change" = paste(x, "%"), x)  })  

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь