Почему gganimate неправильно упорядочивает строки по дате с transition_reveal?

Я хочу воспроизвести анимированный рисунок Эда Хокинса об изменении климата в R с gganimate. Фигура называется климатическая спираль. В то время как статическая ggplot фигура показывает правильный порядок строк по годам (самые последние данные вверху), анимированный график с transition_reveal() приводит к неправильному порядку строк.

Вот воспроизводимый пример кода с синтетическими данными:

library(tidyverse)
library(lubridate)
library(gganimate)
library(RColorBrewer) 

# Create monthly data from 1950 to 2020 (and a component for rising values with time)
df <- tibble(year = rep(1950:2020, each = 12), 
             month = rep(month.abb, 2020-1950+1)) %>%
  mutate(date = dmy(paste("01",month,year)),
         value = rnorm(n(), 0, 2) + row_number()*0.005) %>%
  with_groups(year, mutate, value_yr = mean(value))


temp <- df %>%
  ggplot(aes(x = month(date, label=T), y = value, color = value_yr)) +
  geom_line(size = 0.6, aes(group = year)) +
  geom_hline(yintercept = 0, color = "white") +
  geom_hline(yintercept = c(-4,4), color = c("skyblue3","red1"), size = 0.2) +
  geom_vline(xintercept = 1:12, color = "white", size = 0.2) +
  annotate("label", x = 12.5, y = c(-4,0,4), label = c("-4°C","0°C","+4°C"), 
           color = c("skyblue3","white","red1"), size = 2.5, fill = "#464950", 
           label.size = NA, label.padding = unit(0.1, "lines"),) +
  geom_point(x = 1, y = -11, size = 15, color = "#464950") + 
  geom_label(aes(x = 1, y = -11, label = year), 
             color = "white", size = 4, 
             fill = "#464950", label.size = NA) +
  coord_polar(start = 0) +
  scale_color_gradientn(colors = rev(brewer.pal(n=11, name = "RdBu")),
                        limits = range(df$value_yr)) +
  labs(x = "", y = "") + 
  theme_bw() +
  theme(panel.background = element_blank(),
        panel.border = element_blank(),
        panel.grid.major = element_blank(),
        plot.background=element_rect(fill = "#464950", color = "#464950"),
        axis.text.x = element_text(margin = margin(t = -20, unit = "pt"), 
                                   color = "white"),
        axis.text.y = element_blank(), 
        axis.ticks = element_blank(),
        legend.position = "none") 

Теперь мы можем либо сохранить график в формате PNG, либо анимировать и сохранить в формате GIF:

ggsave(temp, filename = "test.png", width = 5, height = 5, dpi = 320)

# Animate by date:
anim <- temp +
  transition_reveal(date) +
  ease_aes('linear')
  
output <- animate(anim, nframes = 100, end_pause = 30,
                  height = 5, width = 5, units = "in", res = 300)

anim_save("test.gif", output)

Посмотрим на результаты!

Статический PNG: Почему gganimate неправильно упорядочивает строки по дате с transition_reveal?

Анимированный гифка: Почему gganimate неправильно упорядочивает строки по дате с transition_reveal?

На первый взгляд результаты кажутся одинаковыми, однако на деталях видны различия (например, выделенная синяя линия).

Почему gganimate неправильно упорядочивает строки по дате с transition_reveal?

В этом примере кода с синтетическими данными различия незначительны. Но с реальными данными цифры выглядят совсем иначе, так как многие красные линии (недавние точки данных с высокими температурами) исчезают на заднем плане. Итак, как сохранить заказ в transition_reveal() по дате? Любая помощь приветствуется, большое спасибо!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это не ответ как таковой. Вот почему. Вам придется сказать мне, что вы предпочитаете, учитывая эту информацию, чтобы я дал вам решение.

Я попробовал несколько вещей, каждая из которых, как я была уверена, сработает, но не сработала. Итак, я хотел посмотреть, что происходит в ggplot. Моя догадка оказалась верной. Ваши данные в порядке value_yr в png, а не year.

Я повторяю этот вопрос в конце:

Either you can put the animation in order of value_yr or you can put the color in ggplot in order by year. Which would you prefer?

Откуда я знаю? Я извлек назначенные цвета в объекте.

tellMe <- ggplot_build(temp)$data[[1]]
head(tellMe)
#    colour x           y group PANEL flipped_aes size linetype alpha
# 1 #1E60A4 1 -1.75990067     1     1       FALSE  0.6        1    NA
# 2 #1E60A4 2 -0.08968196     1     1       FALSE  0.6        1    NA
# 3 #1E60A4 3 -0.69657130     1     1       FALSE  0.6        1    NA
# 4 #1E60A4 4 -0.10777727     1     1       FALSE  0.6        1    NA
# 5 #1E60A4 5  1.57710505     1     1       FALSE  0.6        1    NA
# 6 #1E60A4 6  1.63277369     1     1       FALSE  0.6        1    NA 

gimme <- tellMe %>% group_by(group) %>% 
  summarise(color = unique(colour)) %>% 
  print(n = 100) # there are less than 100, I just want them all

head(gimme)
# # A tibble: 6 × 2
#   group color  
#   <int> <chr>  
# 1     1 #1E60A4
# 2     2 #114781
# 3     3 #175290
# 4     4 #053061
# 5     5 #1C5C9E
# 6     6 #3E8BBF 

Для меня это указывало на то, что цвета не были в групповом порядке, поэтому я хотел увидеть цвета, чтобы визуализировать порядок.

Я использовал эту функцию. Я знаю, что это из демо, но не помню из какого. Я искал, чтобы включить это сюда, но не нашел.

# this is from a demo (not sure which one anymore!
showCols <- function(cl=colors(), bg = "lightgrey",
                     cex = .75, rot = 20) {
  m <- ceiling(sqrt(n <-length(cl)))
  length(cl) <- m*m; cm <- matrix(cl, m)
  require("grid")
  grid.newpage(); vp <- viewport(w = .92, h = .92)
  grid.rect(gp=gpar(fill=bg))
  grid.text(cm, x = col(cm)/m, y = rev(row(cm))/m, rot = rot,
            vp=vp, gp=gpar(cex = cex, col = cm))
}

showCols(gimme$color)

Верхний левый цвет — это самый старый год, значение под ним — следующий год и так далее. Самый последний год — это нижнее значение в крайнем правом столбце.

df %>% group_by(yr) %>% summarise(value_yr = unique(value_yr))
# they are in 'value_yr' order in ggplot, not year
# # A tibble: 71 × 2
#       yr value_yr
#    <int>    <dbl>
#  1  1950  0.0380 
#  2  1951 -0.215  
#  3  1952 -0.101  
#  4  1953 -0.459  
#  5  1954 -0.00130
#  6  1955  0.559  
#  7  1956 -0.457  
#  8  1957 -0.251  
#  9  1958  1.10   
# 10  1959  0.282  
# # … with 61 more rows 

Either you can put the animation in order of value_yr or you can put the color in ggplot in order by year. Which would you prefer?



Обновлять

Вы не будете использовать transition_reveal для группировки и перехода по одному и тому же элементу. К сожалению, я не могу сказать вам, почему, но, похоже, он застрял на 1958 году!

Чтобы этот gif слева соответствовал ggplot png справа:

Во-первых, я изменил вызовы на ggplot и geom_line.

  ggplot(aes(x = month(date, label = T), y = value, 
             group = yr, color = yr)) +
  geom_line(size = .6)

Затем я попытался использовать transition_reveal, но заметил, что последующие годы были наслоены на под других лет. Я не могу объяснить это странное поведение. Когда я бежал showCol после смены temp, цвета были в порядке. Это исключило то, о чем я думал изначально.

Я изменил объект anim, используя transition_manual, чтобы задать порядок слоев графика.

anim <- temp +
  transition_manual(yr, cumulative = T) +
  ease_aes('linear')

Вот и все. Теперь слои совпадают. Что касается того, сработало бы это до того, как вы изменили назначение цвета: исходный сюжет с ручными переходами года слева, ggplot png справа:

Похоже, это тоже сработало бы. Итак, мое первоначальное растянутое объяснение было далеко не таким полезным, как я думал, но, по крайней мере, теперь у вас есть рабочее решение. (Вздох.)

Большое спасибо за то, что нашли время и за очень информативный ответ. Я уже многому научился благодаря вашему подходу! Прежде всего, я не знал, что ggplot упорядочивает элементы по эстетике color. На самом деле я надеялся правильно отсортировать строки с эстетикой group в geom_line() и порядком самого фрейма данных. Что я, наконец, хотел бы видеть, так это сортировку по дате (последний год сверху) как в статическом PNG, так и в анимированном GIF. Я очень ценю вашу помощь.

Sma 22.03.2022 20:33

Просто чтобы убедиться, что я правильно понял: вы хотите, чтобы оба изображения выглядели как GIF-изображение, которое у вас есть в вашем вопросе? Или вы просите, чтобы цвета были в порядке по годам?

Kat 23.03.2022 03:44

Цвет должен быть задан value_yr, который является среднегодовой температурой на конечном графике (синий = низкая годовая температура, красный = высокая годовая температура). Тем не менее, я сначала подумал, что GIF был неправильным, и на самом деле я все еще так думаю (хотя вы показали, что PNG также был испорчен). Давайте проведем простой тест с color = year и всего 10 годами: посмотреть результат здесь. Например, красная линия для 2010 года находится не сверху, а позади других линий для более ранних лет. Вот почему gganimate ведет себя не так, как я ожидал. Спасибо тебе за твое терпение :)

Sma 23.03.2022 22:31

Вау, да. Ты прав. Я обновил свой ответ решением, которое работает (и сохранил там свою застенчивую неправильность). Обновления добавлены внизу.

Kat 24.03.2022 05:27

Ого, наконец решил проблему! Большое спасибо, что поделились своими навыками! Я думаю написать gganimate вопрос на Github, так как другие тоже могут столкнуться с этой проблемой.

Sma 24.03.2022 10:16

Это отличная идея. Я уверен, что другие сталкивались с этой проблемой, многие из которых не знали, что они столкнулись!

Kat 24.03.2022 14:20

Другие вопросы по теме