Visualizzazione dati con R

Nella sessione di oggi giocheremo un po’ con la visualizzazione dati (una delle attività più divertenti dell’analisi dati). Negli ultimi anni la capacità di visualizzare i pattern presenti nei dati in modo efficace è diventata una cosa molto richiesta, sia in ambito di ricerca accademica o giornalistica che in ambito aziendale. Ci sono almeno due ambiti in cui la visualizzazione dati vi può aiutare:

  1. In fase di esplorazione dati: è molto più facile vedere un pattern in un grafico piuttosto che in una sequela di numeri
  2. In fase di report: un grafico bello da vedere cattura l’attenzione e trasmette il vostro messaggio molto più efficacemente di una sequela di numeri

R è un ottimo programma per questo. Ha un buon motore grafico che permette di fare grafici tra i più esteticamente appaganti che possiate trovare (confrontateli con quelli di Excel e capirete cosa intendo), a meno di non usare applicazioni specifiche (e abbastanza costose) come Tableau. Inoltre, il pacchetto ggplot2, sviluppato nel 2005 e da allora diventato uno degli strumenti più utilizzati per visualizzare dati in R, rende molto facile produrre grafici dall’aspetto piacevole che trasmettono informazioni complesse in modo relativamente semplice.

Oggi faremo due cose. Per prima cosa giocheremo con le funzioni per fare grafici che sono presenti in R base. Dopodiché inizieremo a usare ggplot2. In entrambi i casi, come al solito, vedremo alcuni esempi. Tenete comunque a mente che le possibilità di visualizzazione dati vanno ben oltre quello che vedremo qui.

Per prima cosa, carichiamo i dati. Oggi useremo 2 diversi dataset:

library(rio)
setwd("/folder/where/you/keep/the/data")
# Importiamo i dati CSES
cses <- import("cses2018small.xlsx")
# Importiamo i dati V-Dem
vdem <- import("vdem_small.dta")
head(vdem)
##   country year liberal free_exp gdp_pc_log postcom
## 1 Austria 1990   0.916    0.976   10.09307       0
## 2 Austria 1991   0.916    0.976   10.14471       0
## 3 Austria 1992   0.916    0.976   10.17072       0
## 4 Austria 1993   0.916    0.976   10.18203       0
## 5 Austria 1994   0.916    0.976   10.23265       0
## 6 Austria 1995   0.912    0.976   10.27291       0

Il dataset V-Dem è utile perché introduce una dimensione temporale che incontrerete talvolta nei dati che andrete ad analizzare. Gli stessi 28 paesi sono osservati in 29 punti nel tempo (dal 1990 al 2018). Quindi abbiamo due dimensioni di variazione: (1) la variazione tra paesi, e (2) la variazione nel tempo all’interno del paese. Il dataset contiene le seguenti variabili:

Come promemoria, il dataset CSES contiene le seguenti variabili:

Visualizzazione dati con R base

Anche usando R base ci sono molte possibilità per fare buoni grafici. Tuttavia molti di questi grafici vengono meglio con ggplot2. Questo per non parlare dei grafici più complessi, che con R base richiedono molta più sintassi. Quindi in questa sessione vedremo solo alcune funzioni base che potete usare per un’ispezione veloce dei dati.

  • Istogrammi sono un modo molto utile per vedere la distribuzione di una singola variabile. Gli istogrammi mostrano l’intervallo di valori di una variabile sull’asse delle x e la frequenza di tali valori sull’asse delle y. La frequenza può essere assoluta (il semplice conteggio delle osservazioni nell’intervallo tra due valori di \(X\)) o relativa (come la densità di probabilità o la percentuale di osservazioni nell’intervallo tra due valori di \(X\)). Potete fare un istogramma in R base con la funzione hist().
hist(vdem$gdp_pc_log)

Notare che il ogni grafico può essere personalizzato. Per esempio, possiamo colorare le barre, aggiungere un’etichetta all’asse delle x (è importante che un grafico contenga informazioni su cosa mostrano i valori sui due assi) ed eliminare il nome del grafico:

hist(vdem$gdp_pc_log, col = "blue", 
     xlab = "Logged GDP per capita", main = "")

  • I Boxplot (o “diagramma a scatola”ì) sono un metodo diverso per mostrare la stessa cosa. Mostrano la distribuzione di una variabile in base ai suoi quartili. Consistono in un riquadro, che copre l’intervallo tra il primo e il terzo quartile dei valori di una variabile, e mostra la mediana (cioè il secondo quartile) nel mezzo. Inoltre, i “baffi” (whiskers, le due linee fuori dal riquadro) coprono l’intervallo tra il valore minimo e massimo della variabile escludendo gli outlier. In R base si fanno con la funzione boxplot().
boxplot(vdem$gdp_pc_log)

I boxplot possono anche mostrare una relazione bivariata tra due variabili. Per esempio, guardiamo la distribuzione della variabile gdp_pc_log per ogni anno di osservazione. In questo caso i nomi delle variabili vanno messi in una una formula, scritta come y ~ x, dove y è la variabile di cui vogliamo vedere la distribuzione (nel nostro caso gdp_pc_log) e x è la variabile di raggruppamento (nel nostro caso year).

boxplot(gdp_pc_log ~ year, data = vdem, 
        horizontal = T,                 # Mettiamo le scatole in orizzontale
        las = 2)                        # Cambiamo l'orientamento dei numeri sugli assi

Oppure possiamo utilizzare country come fattore di raggruppamento:

boxplot(gdp_pc_log ~ country, data = vdem, 
        horizontal = T,
        las = 2)

Tuttavia, questo ci pone di fronte a 2 problemi:

  1. I nomi dei paesi escono dai margini della figura. Questo non va bene per ovvi motivi.
  2. È difficile trovare un pattern in questi dati, poiché i paesi sono visualizzati in ordine alfabetico, un fattore arbitrario per organizzare i dati che non contiene informazione rilevante.

Cominciamo con il primo punto. In R, potete cambiare i margini di una figura modificando i parametri grafici di default che sono usati per produrre ogni grafico nella sessione corrente. Potete vederli (e cambiarli) usando la funzione par(). Il parametro che ci interessa sono i margini della figura, che si chiama mar. È possibile vedere i valori predefiniti digitando:

par()$mar
## [1] 5.1 4.1 4.1 2.1

Ora, i valori si riferiscono alla distanza tra i margini della figura e i margini dell’area del grafico. L’ordine in cui vengono mostrati è sotto, sinistra, sopra, destra. Come potete vedere, c’è un po’ più spazio in basso (per l’etichetta dell’asse x e le etichette dei valori), a sinistra (per l’etichetta dell’asse y e le etichette dei valori), e in alto (per il titolo principale).

Nel nostro caso abbiamo bisogno di più spazio a sinistra, e quindi possiamo cambiare i valori di quel margine. Tuttavia, una volta che i valori di par() vengono modificati rimangono così per l’intera sessione (ovvero, ogni grafico fatto da qui in poi avrà quei margini), quindi è meglio salvare i valori default originali e ripristinarli dopo aver fatto il grafico.

# Salvare i parametri grafici di default
pdefault <- par()
# Cambiare i margini per fare più spazio a sinistra
par(mar = c(5, 8, 4, 2))
# Fare il grafico
boxplot(gdp_pc_log ~ country, data = vdem, 
        horizontal = T,
        las = 2,
        ylab = "")

# Risettare i parametri di default
par(pdefault)

Il secondo problema è meno tecnico e più sostanziale. L’idea di fare un boxplot per paese in questo caso è che in questo modo possiamo confrontare i paesi rispetto al loro PIL pro capite. Tuttavia, se i paesi sono ordinati in ordine alfabetico, il confronto non è così facile. Le informazioni ci sono tutte, ma non sono organizzate in modo da far emergere il messaggio rilevante - il messaggio rilevante è quali paesi hanno un PIL pro capite sistematicamente più alto, e quali hanno un PIL pro capite sistematicamente più basso nel periodo osservato. Un modo per far emergere questa informazione è quello di ordinare i paesi in base al loro PIL pro capite mediano. In questo modo possiamo vedere il pattern di variazione tra paesi molto più chiaramente.

Excursus: variabili factor, ordine e grafici

Per farle questo, abbiamo bisogno di creare una nuova variabile factor per il paese, con i livelli ordinati in base alla mediana di gdp_pc_log all’interno di ogni paese. Per capire come funziona, dobbiamo scavare un po’ nella proprietà delle variabili factor in R.

Facciamo un esempio creando un falso data frame con una variabile nominale var.

fda <- data.frame(var = c("a", "b", "c"))

Come potete vedere, R memorizza le variabili nominali come factor di default. Potete saperlo chiedendolo esplicitamente con la funzione is.factor():

is.factor(fda$var)
## [1] FALSE

Le variabili factor hanno una proprietà: sono variabili numeriche etichettate, cioè il loro vero valore è numerico (intero) ma il valore numerico è un segnaposto che ha senso solo se associato a un’etichetta (che, nel nostro caso, sono le lettere “a”, “b” e “c”). Le etichette associate ai valori unici della variabile fattore sono chiamate “livelli”. Potete vedere quali sono i livelli di var digitando il nome della variabile stessa:

fda$var
## [1] "a" "b" "c"

Quando R utilizza la variabile factor come fattore di raggruppamento, userà per default l’ordine alfabetico dei livelli. Questo può essere visto facendo una tabella di var:

table(fda$var)
## 
## a b c 
## 1 1 1

Tuttavia, possiamo cambiare l’ordine con cui i livelli del fattore appaiono nell’output (in questo caso la tabella) cambiando l’attributo della variabile stessa. Per esempio, se vogliamo cambiare l’ordine da c("a", "b", "c") a c("b", "c", "a"), possiamo fare in questo modo:

fda$var <- factor(fda$var, levels = c("b", "c", "a"))

Ora se chiediamo una tabella di var, i valori saranno visualizzati nell’ordine che abbiamo impostato noi:

table(fda$var)
## 
## b c a 
## 1 1 1

Possiamo sfruttare questa proprietà quando vogliamo ordinare le categorie nominali in un grafico. Nel nostro caso, abbiamo bisogno di ordinare i livelli della variabile country in base alla mediana di gdp_pc_log. Possiamo farlo automaticamente usando la funzione reorder().

Lo facciamo creando una nuova variabile chiamata country_sort:

vdem$country_sort <- with(vdem, reorder(country, gdp_pc_log, function(x) median(x, na.rm = T)))
# Facciamo una tabella delle prime 100 osservazioni dei dati per vedere se ha funzionato
with(vdem[1:100, ], table(country_sort, country))
##                 country
## country_sort     Austria Belgium Bulgaria Cyprus
##   Romania              0       0        0      0
##   Bulgaria             0       0       29      0
##   Latvia               0       0        0      0
##   Lithuania            0       0        0      0
##   Poland               0       0        0      0
##   Estonia              0       0        0      0
##   Croatia              0       0        0      0
##   Slovakia             0       0        0      0
##   Hungary              0       0        0      0
##   Czech Republic       0       0        0      0
##   Portugal             0       0        0      0
##   Malta                0       0        0      0
##   Slovenia             0       0        0      0
##   Greece               0       0        0      0
##   Cyprus               0       0        0     13
##   Spain                0       0        0      0
##   France               0       0        0      0
##   Italy                0       0        0      0
##   Finland              0       0        0      0
##   Belgium              0      29        0      0
##   Germany              0       0        0      0
##   United Kingdom       0       0        0      0
##   Austria             29       0        0      0
##   Denmark              0       0        0      0
##   Sweden               0       0        0      0
##   Netherlands          0       0        0      0
##   Ireland              0       0        0      0
##   Luxembourg           0       0        0      0

Ora possiamo fare il nostro boxplot usando la variabile (ordinata) country_sort invece che la variabile (non ordinata) country.

par(mar = c(5, 8, 4, 2))
boxplot(gdp_pc_log ~ country_sort, data = vdem, 
        horizontal = T,
        las = 2,
        ylab = "")

par(pdefault)

In questo modo, il grafico contiene e comunica più informazione di prima.

  • I grafici a barre sono simili agli istogrammi, ma vanno meglio con le variabili categoriche perchè mostrano la percentuale di osservazioni all’interno di ogni categoria. R ha la funzione barplot(), che però vuole come oggetto input una tabella di frequenza (se la applicate direttamente sulla variabile conterà la frequenza di ogni singola osservazione).
barplot(table(cses$eco_eval))

Come abbiamo visto in passato, possiamo usare la funzione prop.table() per ottenere frequenze relative invece che frequenze assolute. Inoltre, è possibile personalizzare il grafico in molti modi.

barplot(prop.table(table(cses$eco_eval)),
        names.arg = c("Got worse", "Remained the same", "Got better"),
        ylab = "Proportion",
        main = "Perceived change of state of the economy\nover the last year")

  • Gli scatter plot (grafici di dispersione) sono il modo per mostrare le relazioni tra due variabili. In R base si producono con la funzione plot(). Inoltre, dato che dovremmo scrivere il nome del dataset due volte, una volta prima di ogni variabile per identificare la variabile con il segno del dollaro $, possiamo usare la funzione with() (che abbiamo già visto) per dare il nome del dataset da cui vengono le variabili una sola volta:
with(vdem, plot(x = liberal, y = gdp_pc_log))

I nomi delle variabili possono anche essere messi in una formula (con gdp_pc_log come y e liberal come x):

plot(gdp_pc_log ~ liberal, data = vdem)

Anche in questo caso, possiamo aggiungere parametri grafici per migliorare l’estetica e leggibilità del grafico:

plot(gdp_pc_log ~ liberal, data = vdem, 
     pch = 20, cex = 0.5,                # Dimensione e forma dei punti
     xlab = "Liberal democracy index",
     ylab = "Logged GDP per capita")

Visualizzazione con ggplot2

Se con i grafici di R base possiamo fare tanto (effettivamente tutto), ci sono librerie che ci permettono di visualizzare informazioni molto complesse in modo relativamente semplice. La più usata è sicuramente ggplot2. Come molte altre librerie che abbiamo visto in questi giorni, ggplot2 fa parte del tidyverse. Questo significa che la avete già installata sul vostro computer, ma soprattutto che è molto ben integrata con altre funzioni del tidyverse, in particolare quelle da con dplyr. Per trarre il massimo vantaggio da questa integrazione, invece che caricare solo ggplot2, caricheremo l’intera collezione tidyverse.

library(tidyverse)

La sintassi di ggplot2 funziona in modo un pó diverso da quella di R base. In un certo senso, è più vicina alla logica delle espressioni di dplyr che usano il pipe operator (anche se non è la stessa cosa). La funzione principale per produrre un grafico si chiama (senza sorpresa) ggplot(). Il tipo di informazioni richieste dalla funzione è più o meno lo stesso che mettereste in una funzione R di base: dovete specificare l’oggetto dati dal quale provengono le variabili, e dovete specificare i nomi delle variabili. Queste informazioni però vanno in una sottofunzione specifica che si chiama aes().

Notate che in ggplot2 la funzione ggplot() viene usata per produrre qualsiasi grafico che volete fare. Questo implica chiaramente che occorre dire da qualche parte che tipo di grafico vogliamo fare (ad esempio uno scatter plot, un box plot, ecc.). Questo viene fatto in ggplot2 aggiungendo layers al grafico. I layer (o strati) sono altre informazioni che si integrano nel grafico esistente. Possono contenere altri dati, oppure solo il tipo di geometria che si vuole visualizzare nel grafico (che determina il tipo di grafico). Senza i layer non c’è alcun grafico in ggplot2. Se provate a fare un grafico senza layer non verrà fuori niente.

ggplot(data = vdem, aes(x = liberal, y = gdp_pc_log))

I layer in ggplot2 sono aggiunti utilizzando le funzioni geom_*. Per esempio, se vogliamo aggiungere punti al grafico (quindi fare uno scatter plot) possiamo aggiungere il livello geom_point(). Tuttavia, nella sintassi di ggplot2, questo non viene fatto all’interno della funzione ggplot(), ma viene concatenato dopo la chiamata iniziale (come in dplyr con il pipe) usando il segno più +:

ggplot(vdem, aes(x = liberal, y = gdp_pc_log)) +
  geom_point()

I layer sono usati per ogni tipo di personalizzazione del grafico, dalle etichette agli assi all’aggiungere più dati. All’interno di ogni layer si possono cambiare le opzioni per quello specifico parametro grafico, ma si possono anche specificare i dati sorgente e le variabili da mostrare in quel layer. Per esempio, lo stesso grafico qui sopra potrebbe anche essere prodotto mettendo la funzione aes() con i nomi delle variabili all’interno della funzione geom_point():

ggplot() +
  geom_point(data = vdem, aes(x = liberal, y = gdp_pc_log))

Alcuni esempi:

  • Istogramma (semplice)
ggplot(vdem, aes(x = gdp_pc_log)) +
  geom_histogram()

  • Istogramma (migliorato)
ggplot(vdem, aes(x = gdp_pc_log)) +
  geom_histogram(alpha = 0.2, col = "black") +
  xlab("Log GDP per capita") +
  ylab("Count") +
  theme_bw()

  • Grafico a violino: come i box plot ma più belli da vedere
ggplot(vdem, aes(x = reorder(country, gdp_pc_log, function(x) mean(x, na.rm = T)), y = gdp_pc_log)) +
  geom_violin(fill = "gray50", trim = F, scale = "width") +
  coord_flip() +
  ylab("Log GDP per capita") +
  xlab("Country") +
  theme_bw()

Grafici multivariati

I dati vdem ci permettono di visualizzare l’andamento temporale delle variabili che abbiamo. Per esempio, possiamo vedere come l’indice di “democrazia liberale” è cambiato in Italia nel corso tempo. Questo è un grafico di tipo bivariato, perchè mostra la relazione tra un fenomeno (il tempo) e un altro (la democrazia liberale in Italia).

ggplot(filter(vdem, country == "Italy"), aes(y = liberal, x = year)) +
  geom_line() +
  geom_point() +
  ylab("Liberal democracy index") +
  xlab("Year") +
  scale_x_continuous(breaks = seq(1990, 2018, by = 2)) +
  theme_bw()

Possiamo aggiungere una terza variabile (mostrando quindi una relazione multivariata) scomponendo la relazione tra le due variabili per paese. Possiamo farlo aggiungendo un fattore di raggruppamento e usando i colori per identificare i diversi paesi:

ggplot(vdem, aes(y = gdp_pc_log, x = year, group = country)) +
  geom_line(aes(col = country)) +
  ylab("Log GDP per capita") +
  xlab("Year") +
  scale_x_continuous(breaks = seq(1990, 2016, by = 2)) +
  theme_bw()

Tuttavia, con 28 paesi è molto difficile capirci qualcosa.

In alternativa possiamo mostrare il trend paese per paese dividendo il grafico in pannelli (“facets”) con il layer facet_wrap():

ggplot(vdem, aes(x = year, y = gdp_pc_log)) +
  geom_line() +
  facet_wrap(~country, ncol = 5) +
  ylab("Log GDP per capita") +
  xlab("Year") +
  scale_x_continuous(breaks = seq(1990, 2020, by = 5)) +
  theme_bw()

Un altro modo ancora per mostrare la stessa relazione è fare una heatmap (mappa di calore) usando la funzione geom_tile():

ggplot(filter(vdem, !is.na(gdp_pc_log)), 
       aes(x = year, y = reorder(country, gdp_pc_log, function(x) mean(x, na.rm = T)))) +
  geom_tile(aes(fill = gdp_pc_log)) +
  scale_fill_gradient(low = "white", high = "black", 
                      "Log GDP\nper capita") +
  scale_x_continuous(breaks = seq(1990, 2016, by = 5)) +
  ylab("") +
  xlab("Year") +
  theme_bw()

Linee di regressione e curve di relazione

Tornando al trend della variabile liberal nel corso del tempo in Italia, oltre a tracciare i singoli punti con una linea, possiamo aggiungere una linea di smoothing per far emergere il pattern generale in modo più chiaro. Questo è un passo nella direzione di un modello di regressione. In ggplot2 questo viene fatto con la funzione geom_smooth(), che se lasciata senza opzioni aggiuntive, applica una funzione non parametrica per interpolare i punti, generalmente una lowess (quando i punti sono pochi, come nel nostro caso) o una GAM (quando ci sono più osservazioni).

ggplot(filter(vdem, country == "Italy"), aes(y = liberal, x = year)) +
  geom_point() +
  geom_smooth() +
  ylab("Liberal democracy index") +
  xlab("Year") +
  scale_x_continuous(breaks = seq(1990, 2018, by = 2)) +
  theme_bw()

Naturalmente questo può essere fatto anche per gruppi:

ggplot(vdem, aes(y = gdp_pc_log, x = year, group = country)) +
  geom_smooth(aes(col = country), se = F) +
  ylab("Log GDP per capita") +
  xlab("Year") +
  scale_x_continuous(breaks = seq(1990, 2016, by = 2)) +
  theme_bw()

geom_smooth() può anche essere usato per aggiungere una retta di regressione al grafico, specificando l’opzione method = "lm". Per esempio, possiamo guardare la relazione lineare tra l’indice di libertà di espressione (la variabile free_exp) e l’indice di democrazia liberale.

ggplot(vdem, aes(x = free_exp, y = liberal)) +
  geom_point() +
  geom_smooth(method = "lm", col = "red") +
  ylab("Liberal democracy index") +
  xlab("Freedom of expression index") +
  theme_bw()

Usare ggplot2 con dplyr

Essendo parte del tidyverse, ggplot2 è molto ben integrato con le altre librerie dell’ecosistema. Questo ci permette per esempio di concatenare molto facilmente le funzioni di dplyr (per modificare o aggregare i dati) e quelle di ggplot2 (per visualizzarli).

Per esempio, vediamo se dal 1990 c’è stata una convergenza in termini di democrazia liberale tra i paesi dell’Europa occidentale e i paesi post-comunisti del blocco dell’Europa centro-orientale. Per farlo abbiamo bisogno prima di aggregare la variabile liberale per gruppo (usando come fattore di raggruppamento la variabile dummy postcom) e mostrare il trend dei due gruppi di paesi. Usando l’operatore pipe %>% possiamo concatenare tutte le operazioni di manipolazione dei dati alla sintassi di ggplot2 per produrre il grafico. Dobbiamo solo ricordarci di passare dal pipe (per la parte dplyr) al segno più + (per la parte ggplot2).

vdem %>%                                                                  # Manipolazione dati
  group_by(year, postcom) %>%
  summarize(libm = mean(liberal, na.rm = T)) %>%
  mutate(
    gr = ifelse(postcom == 0, "West\nEurope", "Central-Eastern\nEurope")
  ) %>%
  ggplot(., aes(x = year, y = libm, group = gr)) +                        # Grafico
  geom_smooth(aes(col = gr)) +
  scale_color_manual(values = c("red", "blue"), "Geo-political area") +
  scale_x_continuous(breaks = seq(1990, 2018, by = 2)) +
  xlab("") +
  ylab("Liberal democracy index") +
  theme_bw() +
  theme(legend.position = "bottom")

Possiamo farlo in diversi modi. Per esempio, possiamo fare una heathmap usando la funzione geom_tile().

cses %>%
  filter(!is.na(eco_eval)) %>%
  group_by(area, eco_eval) %>%
  summarize(nobs = n()) %>%
  group_by(area) %>%
  mutate(
    share = nobs / sum(nobs),
    gr = ifelse(eco_eval == -1, "Got worse",
                ifelse(eco_eval == 0, "Remained\nthe same",
                       "Got better"))
    ) %>%
  ungroup() %>%
  mutate(
    area = factor(area, levels = rev(c("Nord-Ovest", "Nord-Est", "Centro", "Sud"))),
    gr = factor(gr, levels = c("Got worse", "Remained\nthe same", "Got better"))
  ) %>%
  ggplot(., aes(x = gr, y = area, fill = share)) +
  geom_tile() +
  scale_fill_gradient(low = "white", high = "black", 
                      labels = scales::percent, 
                      "Share of\nrespondents") +
  ylab("Geographical area") +
  xlab("Evaluation of the economy over the last year") +
  theme_bw()

Un altro esempio: usando i dati cses, vediamo quanti intervistati in ogni area geografica hanno valutato l’andamento dell’economia durante l’anno prima delle elezioni in modo positivo, negativo o neutro. Possiamo fare un diagramma a barre, mostrando le barre in due modi: “impilate” una sopra l’altra (stacked) o “affiancate” (dodged). Proviamo entrambi i modi e decidiamo quale ci convince di più:

ecodat <- cses %>%
  filter(!is.na(eco_eval)) %>%
  group_by(area, eco_eval) %>%
  summarize(nobs = n()) %>%
  group_by(area) %>%
  mutate(
    share = nobs / sum(nobs),
    gr = ifelse(eco_eval == -1, "Got worse",
                ifelse(eco_eval == 0, "Remained\nthe same",
                       "Got better"))
    ) %>%
  ungroup() %>%
  mutate(
    area = factor(area, levels = rev(c("Nord-Ovest", "Nord-Est", "Centro", "Sud"))),
    gr = factor(gr, levels = c("Got worse", "Remained\nthe same", "Got better"))
  )

# "Stacked"
ggplot(ecodat, aes(x = area, y = share, fill = gr)) +
  geom_bar(stat = "identity", position = "stack") +
  scale_fill_manual(values = c("gray20", "gray50", "gray80"), 
                    "Evaluation of the economy\nover the last year") +
  scale_y_continuous(breaks = seq(0, 1, by = 0.2),
                     labels = scales::percent) +
  ylab("Share of respondents") +
  xlab("Geographical area") +
  theme_bw()

# "Dodged"
ggplot(ecodat, aes(x = area, y = share, fill = gr)) +
  geom_bar(stat = "identity", position = "dodge", col = "black") +
  scale_fill_manual(values = c("gray20", "gray50", "gray80"), 
                    "Evaluation of the economy\nover the last year") +
  scale_y_continuous(breaks = seq(0, 1, by = 0.2),
                     labels = scales::percent) +
  ylab("Share of respondents") +
  xlab("Geographical area") +
  theme_bw() +
  theme(legend.position = "bottom")

Salvare i grafici come immagine

Una volta che abbiamo un grafico, è utile esportare l’immagine in modo da poterla inserire nel nostro paper o report o sito web o qualsiasi altra cosa per cui lo abbiamo fatto. In RStudio possiamo semplicemente usare il pulsante “Export” sul pannello in basso a destra, ma in alternativa possiamo salvare il grafico come immagine direttamente con la sintassi in modo da poter automatizzare il processo (per esempio in caso dobbiamo fare molti grafici) e avere più controllo su alcuni parametri come la dimensione della figura.

Con ggplot2 possiamo farlo usando la funzione ggsave(). Anche in questo caso, può essere fatto in diversi modi:

  1. Mettere il grafico in un oggetto e applicare la funzione ggsave() a quell’oggetto:
# Salvare il grafico in un oggetto
plot1 <- ggplot(ecodat, aes(x = area, y = share, fill = gr)) +
  geom_bar(stat = "identity", position = "dodge", col = "black") +
  scale_fill_manual(values = c("gray20", "gray50", "gray80"), 
                    "Evaluation of the economy\nover the last year") +
  scale_y_continuous(breaks = seq(0, 1, by = 0.2),
                     labels = scales::percent) +
  ylab("Share of respondents") +
  xlab("Geographical area") +
  theme_bw() +
  theme(legend.position = "bottom")

# Salvare l'oggetto come immagine
ggsave(plot1, filename = "eco_barplot.pdf",
         device = cairo_pdf, width = 6, height = 5)

Nota: se mettere il grafico in un oggetto, R non lo visualizzerà nel pannello dei grafici. Se volete farlo dovete chiedere a R di mostrare esplicitamente l’oggetto.

plot1

  1. Un altro metodo è di concatenare la funzione ggsave() direttamente dopo la sintassi per fare il grafico usando l’operatore pipe %>%. In questo caso dobbiamo “racchiudere” tutte le funzioni che producono il grafico all’interno di parentesi. Anche in questo caso R non visualizzerà il grafico.
(ggplot(ecodat, aes(x = area, y = share, fill = gr)) +
  geom_bar(stat = "identity", position = "dodge", col = "black") +
  scale_fill_manual(values = c("gray20", "gray50", "gray80"), 
                    "Evaluation of the economy\nover the last year") +
  scale_y_continuous(breaks = seq(0, 1, by = 0.2),
                     labels = scales::percent) +
  ylab("Share of respondents") +
  xlab("Geographical area") +
  theme_bw() +
  theme(legend.position = "bottom")) %>%
  ggsave(., filename = "eco_barplot.pdf",
         device = cairo_pdf, width = 6, height = 5)

Naturalmente possiamo anche concatenare tutto, dalla preparazione dei dati, alla visualizzazione, all’esportazione in immagine. Ecco alcuni esempi (in cui visualizziamo il grafico ma nella realtà il codice si limita a salvarlo):

(vdem %>%
  mutate(
    decade = ifelse(year < 2000, "1990s",
                    ifelse(year < 2010, "2000s", "2010s")),
    gr = ifelse(postcom == 0, "West\nEurope", "Central-Eastern\nEurope"),
    gr = factor(gr, levels = c("West\nEurope", "Central-Eastern\nEurope"))
  ) %>%
  group_by(country, decade) %>%
  summarize(
    gr = unique(gr),
    liberal = mean(liberal, na.rm = T),
    gdp = mean(gdp_pc_log, na.rm = T)
  ) %>%
  ggplot(., aes(x = gdp, y = liberal)) +
  geom_point() +
  geom_text(aes(label = country), nudge_x = -0.02, nudge_y = -0.01) +
  facet_grid(gr ~ decade) +
  xlab("Freedom of expression index") +
  ylab("Liberal democracy index") +
  theme_bw()) %>%
  ggsave(., filename = "scatter_gdp_liberal.pdf",
         device = cairo_pdf, width = 10, height = 7)

I nomi dei paesi che si sovrappongono sono abbastanza brutti da vedere. Possiamo usare la libreria ggrepel per sistemarle automaticamente in modo che non si sovrappongano. Tuttavia, le etichette sono troppe, e ggrepel ne eliminerà alcune (dandoci un messaggio di warning).

# Ricordatevi di installare "ggrepel"
# install.packages("ggrepel)

library(ggrepel)

vdem %>%
  mutate(
    decade = ifelse(year < 2000, "1990s",
                    ifelse(year < 2010, "2000s", "2010s")),
    gr = ifelse(postcom == 0, "West\nEurope", "Central-Eastern\nEurope"),
    gr = factor(gr, levels = c("West\nEurope", "Central-Eastern\nEurope"))
  ) %>%
  group_by(country, decade) %>%
  summarize(
    gr = unique(gr),
    liberal = mean(liberal, na.rm = T),
    gdp = mean(gdp_pc_log, na.rm = T)
  ) %>%
  ggplot(., aes(x = gdp, y = liberal)) +
  geom_point() +
  geom_text_repel(aes(label = country)) +      # La funzione da "ggrepel"
  facet_grid(gr ~ decade) +
  xlab("Freedom of expression index") +
  ylab("Liberal democracy index") +
  theme_bw()
## Warning: ggrepel: 2 unlabeled data points (too many overlaps). Consider increasing max.overlaps
## Warning: ggrepel: 7 unlabeled data points (too many overlaps). Consider increasing max.overlaps
## Warning: ggrepel: 8 unlabeled data points (too many overlaps). Consider increasing max.overlaps

Un’altra heatmap, con un tipo diverso di divisione in pannelli:

(vdem %>%
  filter(!is.na(gdp_pc_log)) %>%
    mutate(
    decade = ifelse(year < 2000, "1990s",
                    ifelse(year < 2010, "2000s", "2010s")),
    gr = ifelse(postcom == 0, "West\nEurope", "Central-Eastern\nEurope"),
    gr = factor(gr, levels = c("West\nEurope", "Central-Eastern\nEurope"))
  ) %>%
  ggplot(.,aes(x = year, y = reorder(country, gdp_pc_log, function(x) mean(x, na.rm = T)))) +
  geom_tile(aes(fill = gdp_pc_log)) +
  facet_grid(gr ~ decade, scales = "free", space = "free") +
  scale_fill_gradient(low = "white", high = "black", 
                      "Log GDP\nper capita") +
  scale_x_continuous(breaks = seq(1990, 2016, by = 2)) +
  ylab("") +
  xlab("Year") +
  theme_bw()) %>%
  ggsave(., filename = "heathmap_gdp_region.pdf",
         device = cairo_pdf, width = 9, height = 5)