## @knitr package_usati
# carico le librerie di lavoro --------------------------------------------
library(tidyverse)          # per ggplot2 e per le funzioni di dplyr
library(janitor)            # per la funzione clean_names
library(gapminder)          # per la tabella dati utilizzata
library(gganimate)          # per animare i grafici di ggplot2
# NOTA: per creare le animazioni gganimate ha bisogno di un "renderer":
#       - il package gifski (consigliato) per salvare in formato gif
#       - il package av per salvare in formato video (mp4)
#       se non sono installati:
#       install.packages(c("gganimate", "gifski", "av"))

## @knitr preparo_tabelle
gap_data <- gapminder |>
  clean_names() |>
  rename(gdp_per_cap = gdp_percap)
gap_2007 <- gap_data |>
  filter(year == 2007)
# medie per continente e anno, utili per alcuni esempi
gap_continenti <- gap_data |>
  group_by(continent, year) |>
  summarise(life_exp = mean(life_exp),
            gdp_per_cap = mean(gdp_per_cap),
            .groups = "drop")
gap_continenti


## @knitr sezione_1
# 1. L'IDEA DI FONDO =======================================================

## @knitr idea_statico
# gganimate estende la grammatica di ggplot2: si parte da un grafico
# statico e si AGGIUNGONO (con il +) nuovi "strati" che descrivono come
# il grafico cambia nel tempo. Le famiglie di funzioni sono:
#   transition_*()  quale variabile guida l'animazione (obbligatoria)
#   enter_*()/exit_*()  come compaiono e scompaiono gli elementi
#   ease_aes()      con quale "andatura" ci si muove da un fotogramma all'altro
#   view_*()        come cambiano gli assi durante l'animazione
#   shadow_*()      quale traccia lasciano i fotogrammi passati
# partiamo da un grafico statico: tutti gli anni insieme (troppi punti!)
ggplot(gap_data, aes(x = gdp_per_cap, y = life_exp)) +
  geom_point(alpha = 0.3) +
  scale_x_log10()

## @knitr idea_animato
# aggiungendo transition_time(year) otteniamo un fotogramma per ogni anno
# (e i fotogrammi intermedi, interpolati)
p_idea <- ggplot(gap_data, aes(x = gdp_per_cap, y = life_exp)) +
  geom_point(alpha = 0.5) +
  scale_x_log10() +
  transition_time(year)
class(p_idea)               # un oggetto "gganim": un ggplot che sa muoversi
p_idea                      # stampandolo, R calcola e mostra l'animazione
# NOTA: il calcolo richiede qualche secondo (per default 100 fotogrammi);
#       in RStudio/Positron l'animazione compare nel pannello Viewer


## @knitr sezione_2
# 2. TRANSITION_STATES: UNA VARIABILE QUALITATIVA ==========================

## @knitr states_base
# transition_states() passa da uno "stato" all'altro: gli stati sono le
# modalità di una variabile qualitativa (o di un numero intero con pochi
# valori). Qui: l'aspettativa di vita del 2007, un continente alla volta
p_states <- ggplot(gap_2007, aes(x = gdp_per_cap, y = life_exp)) +
  geom_point(aes(color = continent), size = 3) +
  scale_x_log10() +
  transition_states(continent)
p_states
# NOTA: guardate bene il passaggio da un continente all'altro: i punti
#       "viaggiano" e cambiano colore. gganimate abbina le righe di uno
#       stato a quelle dello stato successivo e le sposta: qui l'effetto
#       non ha senso (un paese africano non "diventa" americano).
#       Lo sistemiamo nella sezione 3

## @knitr states_opzioni
# gli argomenti principali di transition_states():
#   transition_length  durata (relativa) del passaggio tra due stati
#   state_length       durata (relativa) della pausa su ciascuno stato
#   wrap               TRUE (default): dall'ultimo stato torna al primo
# nel titolo, {closest_state} viene sostituito dallo stato corrente
p_states <- ggplot(gap_2007, aes(x = gdp_per_cap, y = life_exp)) +
  geom_point(aes(color = continent), size = 3, show.legend = FALSE) +
  scale_x_log10() +
  labs(title = "Continente: {closest_state}") +
  transition_states(continent, transition_length = 1, state_length = 3)
p_states

## @knitr states_barre
# un esempio classico: barre che crescono anno dopo anno.
# Qui year ha 12 valori: lo trattiamo come stato
p_barre <- ggplot(gap_continenti, aes(x = continent, y = life_exp,
                                      fill = continent)) +
  geom_col(show.legend = FALSE) +
  labs(title = "Aspettativa di vita media nel {closest_state}",
       x = NULL, y = "Anni") +
  transition_states(year, transition_length = 2, state_length = 1)
p_barre


## @knitr sezione_3
# 3. ENTER, EXIT ED EASE: COME SI MUOVONO GLI ELEMENTI =====================

## @knitr enter_exit
# per evitare che i punti "viaggino" da un continente all'altro bisogna
# dire a gganimate quali righe sono lo stesso oggetto: l'estetica group.
# Con group = country ogni paese è un oggetto a sé, presente in un solo
# stato: entra quando arriva il suo continente ed esce quando se ne va.
# enter_*() ed exit_*() definiscono COME entra ed esce:
#   enter_fade() / exit_fade()        dissolvenza
#   enter_grow() / exit_shrink()      crescita / riduzione della dimensione
#   enter_fly(x_loc, y_loc) / exit_fly()  arrivo / uscita da un punto
#   enter_drift() / exit_drift()      scivolamento laterale
p_states_paesi <- ggplot(gap_2007, aes(x = gdp_per_cap, y = life_exp,
                                       group = country)) +
  geom_point(aes(color = continent), size = 3, show.legend = FALSE) +
  scale_x_log10() +
  labs(title = "Continente: {closest_state}") +
  transition_states(continent, transition_length = 1, state_length = 3)
p_states_paesi                # senza enter/exit: compaiono e spariscono
p_states_paesi +
  enter_fade() +
  exit_shrink()

## @knitr ease
# ease_aes() stabilisce l'andatura del movimento tra due fotogrammi:
#   "linear"        velocità costante (default)
#   "cubic-in-out"  parte piano, accelera, rallenta all'arrivo
#   "elastic-out"   arriva "rimbalzando"
#   "bounce-out"    arriva "saltellando"
# provate a cambiare il valore e a osservare le barre
p_barre +
  ease_aes("cubic-in-out")
p_barre +
  ease_aes("elastic-out")


## @knitr sezione_4
# 4. TRANSITION_TIME: UNA VARIABILE TEMPORALE ==============================

## @knitr time_base
# transition_time() usa una variabile numerica che rappresenta il tempo:
# a differenza di transition_states() non ci sono pause, e la durata dei
# passaggi è proporzionale alla distanza nel tempo
# nel titolo si usa {frame_time}: il tempo del fotogramma corrente
p_time <- ggplot(gap_continenti, aes(x = gdp_per_cap, y = life_exp,
                                     color = continent)) +
  geom_point(size = 4) +
  scale_x_log10() +
  labs(title = "Anno: {frame_time}") +
  transition_time(year)
p_time
# il titolo mostra anni con i decimali (es. 1953.27): sono i fotogrammi
# intermedi. Si arrotonda con una funzione R dentro le graffe:
p_time +
  labs(title = "Anno: {round(frame_time)}")


## @knitr sezione_5
# 5. SHADOW: LA MEMORIA DEI FOTOGRAMMI PASSATI =============================

## @knitr shadow
# le funzioni shadow_*() lasciano una traccia dei fotogrammi precedenti
#   shadow_wake()   una scia che si dissolve (wake_length = lunghezza)
#   shadow_trail()  una serie di "impronte" a intervalli regolari
#   shadow_mark()   lascia sul grafico tutti i fotogrammi già mostrati
p_time_tit <- p_time +
  labs(title = "Anno: {round(frame_time)}")
p_time_tit +
  shadow_wake(wake_length = 0.2)
p_time_tit +
  shadow_trail(distance = 0.1, alpha = 0.3)
p_time_tit +
  shadow_mark(alpha = 0.3, size = 1.5)


## @knitr sezione_6
# 6. TRANSITION_REVEAL: LE SERIE STORICHE ==================================

## @knitr reveal
# transition_reveal() "scopre" i dati progressivamente lungo una variabile
# (tipicamente il tempo), lasciando visibile il tratto già percorso:
# è l'animazione naturale per un grafico a linee.
# nel titolo si usa {frame_along}
paesi <- c("Italy", "China", "India", "Brazil", "Nigeria")
p_reveal <- gap_data |>
  filter(country %in% paesi) |>
  ggplot(aes(x = year, y = life_exp, color = country)) +
  geom_line(linewidth = 1) +
  geom_point(size = 3) +
  labs(title = "Aspettativa di vita fino al {frame_along}",
       x = NULL, y = "Anni", color = NULL) +
  transition_reveal(year)
p_reveal
# NOTA: geom_point mostra solo il punto corrente, geom_line l'intero
#       percorso fino a quel momento


## @knitr sezione_7
# 7. VIEW: ASSI CHE SI ADATTANO ============================================

## @knitr view
# view_follow() adatta gli assi ai dati del fotogramma corrente: gli
# assi "inseguono" i punti, come una telecamera.
# fixed_x = TRUE (o fixed_y = TRUE) lascia fisso uno dei due assi
p_time_tit +
  view_follow()
p_time_tit +
  view_follow(fixed_y = TRUE)


## @knitr sezione_8
# 8. TRANSITION_LAYERS: LA GRAMMATICA "IN DIRETTA" =========================

## @knitr layers
# transition_layers() mostra i layer uno dopo l'altro, nell'ordine in cui
# sono stati aggiunti: un modo per vedere la costruzione del grafico
ggplot(gap_2007, aes(x = gdp_per_cap, y = life_exp)) +
  geom_point(aes(color = continent)) +
  geom_smooth(color = "black", se = FALSE) +
  geom_text(data = filter(gap_2007, country %in% paesi),
            aes(label = country), vjust = -1) +
  scale_x_log10() +
  transition_layers(layer_length = 1, transition_length = 1) +
  enter_grow()
# NOTA: con geom_smooth() la combinazione con enter_fade() restituisce un
#       errore (Can't combine `..1$fill`...): usiamo enter_grow()


## @knitr sezione_9
# 9. ANIMATE E ANIM_SAVE: CONTROLLARE E SALVARE L'ANIMAZIONE ===============

## @knitr animate
# stampare un oggetto gganim equivale a chiamare animate() con i valori
# di default. animate() permette di controllare:
#   nframes    numero di fotogrammi (default 100)
#   fps        fotogrammi al secondo (default 10): durata = nframes / fps
#   duration   in alternativa: durata in secondi
#   width, height, res   dimensioni (in pixel) e risoluzione
#   start_pause, end_pause   fotogrammi di pausa all'inizio e alla fine
#   rewind     TRUE: alla fine l'animazione torna indietro
#   renderer   il formato di uscita: gifski_renderer() (gif),
#              av_renderer() (video mp4)
animate(p_time_tit, nframes = 120, fps = 20,
        width = 700, height = 450, end_pause = 20)

## @knitr anim_save
# anim_save() salva l'ultima animazione mostrata (o quella indicata
# con l'argomento animation) nella cartella del progetto
anim_save("continenti.gif")
# per un video: si sceglie il renderer av_renderer() in animate()
video <- animate(p_time_tit, nframes = 120, fps = 20,
                 renderer = av_renderer())
anim_save("continenti.mp4", animation = video)


## @knitr sezione_10
# 10. IL GRAFICO DI GAPMINDER, PASSO PASSO =================================
# Ricostruiamo il diagramma a bolle animato reso celebre da Hans Rosling
# (TED Talk "The best stats you've ever seen", 2006): ricchezza e salute
# di tutti i paesi del mondo dal 1952 al 2007

## @knitr bolle_passo_1
# PASSO 1: il grafico di dispersione di un solo anno
ggplot(gap_2007, aes(x = gdp_per_cap, y = life_exp)) +
  geom_point()

## @knitr bolle_passo_2
# PASSO 2: la scala logaritmica sull'asse x
# il reddito pro capite è molto asimmetrico: in scala logaritmica la
# nuvola di punti si "apre" e la relazione diventa quasi lineare
ggplot(gap_2007, aes(x = gdp_per_cap, y = life_exp)) +
  geom_point() +
  scale_x_log10()

## @knitr bolle_passo_3
# PASSO 3: dai punti alle bolle
# la dimensione rappresenta la popolazione, il colore il continente;
# scale_size() regola la dimensione minima e massima delle bolle,
# alpha rende visibili le bolle sovrapposte
ggplot(gap_2007, aes(x = gdp_per_cap, y = life_exp,
                     size = pop, color = continent)) +
  geom_point(alpha = 0.7) +
  scale_x_log10() +
  scale_size(range = c(2, 15))

## @knitr bolle_passo_4
# PASSO 4: tutti gli anni insieme. Il grafico è illeggibile:
# servirebbe un grafico per ogni anno...
ggplot(gap_data, aes(x = gdp_per_cap, y = life_exp,
                     size = pop, color = continent)) +
  geom_point(alpha = 0.7) +
  scale_x_log10() +
  scale_size(range = c(2, 15))

## @knitr bolle_passo_5
# PASSO 5: ... ed è proprio quello che fa transition_time(year)
# basta aggiungere una riga!
p_bolle <- ggplot(gap_data, aes(x = gdp_per_cap, y = life_exp,
                                size = pop, color = continent)) +
  geom_point(alpha = 0.7) +
  scale_x_log10() +
  scale_size(range = c(2, 15)) +
  transition_time(year)
p_bolle

## @knitr bolle_passo_6
# PASSO 6: l'anno nel titolo e un movimento a velocità costante
p_bolle <- p_bolle +
  labs(title = "Anno: {round(frame_time)}") +
  ease_aes("linear")
p_bolle

## @knitr bolle_passo_7
# PASSO 7: l'anno sullo sfondo, come nella presentazione di Rosling.
# Il testo è un nuovo layer, disegnato PRIMA dei punti, quindi sotto le
# bolle; usa una tabella con una riga per anno e non eredita le
# estetiche del grafico (inherit.aes = FALSE)
# il testo deve essere di tipo character: un numero verrebbe interpolato
# tra un anno e l'altro (comparirebbe, ad esempio, 1984.5)
anni <- gap_data |>
  distinct(year) |>
  mutate(etichetta = as.character(year))
p_bolle <- ggplot(gap_data, aes(x = gdp_per_cap, y = life_exp,
                                size = pop, color = continent)) +
  geom_text(data = anni, aes(x = 3000, y = 55, label = etichetta),
            inherit.aes = FALSE, size = 40, color = "grey90") +
  geom_point(alpha = 0.7) +
  scale_x_log10() +
  scale_size(range = c(2, 15)) +
  transition_time(year) +
  ease_aes("linear")
p_bolle

## @knitr bolle_passo_8
# PASSO 8: il nome di alcuni paesi, per seguirli durante l'animazione
# (anche questo è un layer con dati propri: solo i paesi scelti)
paesi <- c("Italy", "China", "India", "Nigeria", "Rwanda")
# osservate il Ruanda: nel 1992 l'aspettativa di vita crolla a 23.6 anni
# (guerra civile e genocidio dei primi anni '90)
p_bolle <- p_bolle +
  geom_text(data = filter(gap_data, country %in% paesi),
            aes(label = country), size = 4, color = "black",
            vjust = -1.5, show.legend = FALSE)
p_bolle

## @knitr bolle_passo_9
# PASSO 9: le rifiniture
#   - etichette leggibili sugli assi (scales::label_dollar)
#   - nessuna legenda per la dimensione (guide = "none")
#   - titoli in italiano e un tema pulito
p_bolle <- p_bolle +
  scale_x_log10(labels = scales::label_dollar()) +
  scale_size(range = c(2, 15), guide = "none") +
  labs(title = "Ricchezza e salute delle nazioni",
       x = "PIL pro capite (dollari, scala logaritmica)",
       y = "Aspettativa di vita (anni)",
       color = "Continente",
       caption = "Fonte: gapminder.org") +
  theme_minimal(base_size = 14)
p_bolle
# NOTA: R avvisa che stiamo sostituendo le scale x e size già presenti
#       ("Scale for x is already present"): è quello che vogliamo

## @knitr bolle_passo_10
# PASSO 10: animazione più fluida e salvataggio
animate(p_bolle, nframes = 240, fps = 20,
        width = 900, height = 600, end_pause = 30)
anim_save("gapminder_bolle.gif")

## @knitr bolle_bonus
# BONUS: un pannello per continente, con i colori "ufficiali" dei paesi
# (il vettore country_colors è contenuto nel package gapminder)
ggplot(gap_data, aes(x = gdp_per_cap, y = life_exp,
                     size = pop, color = country)) +
  geom_point(alpha = 0.7, show.legend = FALSE) +
  scale_color_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  scale_x_log10() +
  facet_wrap(~ continent) +
  labs(title = "Anno: {round(frame_time)}",
       x = "PIL pro capite", y = "Aspettativa di vita") +
  transition_time(year) +
  ease_aes("linear")
