ggplot2 in pratica

Attività in aula - mercoledì 28 ottobre 2026

Come funziona

Oggi impariamo ggplot2 per piccoli passi. Per ogni attività:

  1. Osserva: il docente presenta un’idea nuova con un esempio sui dati gapminder
  2. Anticipa: prima di eseguire il codice, scrivi su un foglio (o nello script, come commento) che cosa ti aspetti di vedere
  3. Esegui: esegui il codice e verifica se avevi ragione
  4. Modifica: adatta il codice ai dati delle biblioteche ed eseguilo
  5. Confronta: discutiamo insieme le soluzioni, gli errori e le sorprese

Non serve finire tutto: i punti Bonus sono per chi termina prima. Quello che non riesci a completare in aula ti sarà utile per il prossimo compito.

Preparazione

  • Crea un progetto RStudio di nome lab11 (in Positron: crea una cartella lab11 e aprila con File → Open Folder).
  • Crea una sottocartella dati e salva al suo interno i file dell’esercitazione 1 (utenti.csv, prestiti.xlsx e catalogo.txt).
  • Crea uno script lab11_cognome_nome.R e copia al suo inizio il codice che segue. Eseguilo e verifica di avere nell’ambiente di lavoro le tabelle utenti (150 righe), prestiti (396 righe) e prestiti_completo (389 righe).
library(tidyverse)   # contiene anche ggplot2
library(readxl)
library(janitor)

utenti <- read_delim("hw05-dati/utenti.csv", delim = ";") |>
  clean_names() |>
  mutate(categoria = replace_values(categoria, "stu" ~ "STU"),
         categoria = recode_values(categoria,
                                   "STU" ~ "Studente", "LAV" ~ "Lavoratore",
                                   "PEN" ~ "Pensionato", "DOC" ~ "Docente",
                                   "ALT" ~ "Altro"),
         genere = replace_values(genere, "f" ~ "F"),
         genere = factor(genere, levels = c("F", "M"),
                         labels = c("Femmina", "Maschio")),
         eta = 2025 - anno_di_nascita)
prestiti <- read_excel("hw05-dati/prestiti.xlsx", sheet = "Prestiti 2025", skip = 3) |>
  clean_names()
catalogo <- read_tsv("hw05-dati/catalogo.txt") |>
  clean_names() |>
  rename(genere_letterario = genere)
prestiti_completo <- prestiti |>
  inner_join(utenti, by = join_by(cod_utente == id_utente)) |>
  left_join(catalogo, by = "inventario")
TipLo schema di ogni grafico ggplot2
ggplot(data = <TABELLA>, mapping = aes(<ESTETICA> = <VARIABILE>, ...)) +
  <GEOM_FUNZIONE>() +
  ...

I layer si aggiungono con +, non si concatenano con la pipe |>. La pipe si può usare solo prima di ggplot(), per passarle la tabella: utenti |> ggplot(aes(...)) + geom_...().

Parte 1 - Le basi

Attività 1 - Dati, estetiche, geometrie

Costruisci il grafico a barre del numero di utenti per categoria con ggplot(), aes() e geom_bar().

  • Anticipa: che cosa succede se scrivi utenti |> ggplot(aes(x = categoria)) |> geom_bar()? Prova e leggi con attenzione il messaggio di errore.
  • Bonus: ottieni le barre orizzontali. Suggerimento: su quale asse va la variabile?

Attività 2 - geom_bar() o geom_col()?

Costruisci la tabella di frequenza delle categorie con tab_categoria <- utenti |> tabyl(categoria) e rappresentala con geom_col(), indicando in aes() sia la x sia la y.

  • Anticipa: che cosa succede se usi geom_bar() al posto di geom_col() con la stessa aes(x = categoria, y = n)?
  • Bonus: ordina le barre dalla più alta alla più bassa. Con geom_bar() puoi usare x = fct_infreq(categoria); con geom_col() puoi usare x = reorder(categoria, -n).
TipSuggerimento

geom_bar() conta le righe della tabella per ciascuna modalità (dati grezzi); geom_col() usa valori già calcolati (ad esempio una tabella di frequenza) che vanno indicati come y.

Attività 3 - Associare o fissare?

Rappresenta con geom_point() la relazione tra eta (asse x) e anno_iscrizione (asse y), in tre versioni:

  1. con geom_point(aes(color = "blue"))
  2. con geom_point(color = "blue")
  3. con color = categoria all’interno di aes()
  • Anticipa: di che colore saranno i punti nella versione (a)? Ci sarà una legenda?
  • Che cosa ti dice il messaggio di avvertimento (warning) che compare in tutte e tre le versioni?
  • Bonus: nella versione (c) fissa la dimensione dei punti a 3 e la trasparenza (alpha) a 0.6.
TipSuggerimento

Dentro aes() si associa (mapping) un’estetica a una variabile della tabella: il colore cambia con i valori della variabile e compare una legenda. Fuori da aes(), come argomento della funzione geom_, si fissa (setting) lo stesso valore per tutti gli elementi.

Attività 4 - I layer si sovrappongono

Rappresenta la distribuzione dell’eta per categoria con un boxplot (geom_boxplot()) e aggiungi i singoli utenti con geom_jitter(width = 0.2, alpha = 0.5).

  • Anticipa: che cosa cambia se scrivi i due layer in ordine inverso, prima geom_jitter() e poi geom_boxplot()?
  • Bonus: sostituisci il boxplot con un violin plot (geom_violin()), che hai già incontrato nel compito della settimana scorsa.

Debug - Trova l’errore

Ognuno dei tre blocchi seguenti contiene un errore. Prima di eseguirli, prova a individuarlo; poi esegui, leggi il messaggio e correggi.

# D1
ggplot(utenti, aes(x = categoria)) +
  geom_bar

# D2
ggplot(utenti, aes(x = categoria)) +
  geom_bar(fill = genere)

# D3
ggplot(utenti, aes(x = eta))
  + geom_histogram()

Parte 2 - Raffinare il grafico

Per le attività 5 e 6 usa la tabella dei prestiti con il genere letterario noto:

prestiti_validi <- prestiti_completo |>
  filter(!is.na(genere_letterario))

Attività 5 - Barre impilate, affiancate, normalizzate

Salva in un oggetto g la parte comune del grafico

g <- ggplot(prestiti_validi, aes(x = categoria, fill = genere_letterario))

e aggiungi a g, in tre grafici distinti, geom_bar(), geom_bar(position = "dodge") e geom_bar(position = "fill").

  • Anticipa: quale dei tre grafici serve per rispondere alla domanda “la composizione per genere letterario dei prestiti degli studenti è diversa da quella dei pensionati?”. Perché?
  • A quale tabella costruita con tabyl() e le funzioni adorn_*() corrisponde il grafico con position = "fill"? Costruiscila e confronta.

Attività 6 - Un grafico per ogni gruppo

Costruisci l’istogramma dell’eta degli utenti (geom_histogram(binwidth = 5, boundary = 10)) e aggiungi facet_wrap(~ categoria) per ottenere un pannello per ogni categoria.

  • Anticipa: i pannelli avranno tutti lo stesso asse y? È un vantaggio o uno svantaggio?
  • Bonus: aggiungi l’argomento scales = "free_y" a facet_wrap(). Che cosa diventa più facile leggere? E che cosa più difficile?
  • Bonus 2: prova facet_grid(genere ~ categoria).

Attività 7 - Scale e colori

Costruisci la tabella dei prestiti per biblioteca e mese

prestiti_mese <- prestiti |>
  count(biblioteca, mese = month(data_prestito))

e rappresentala con un grafico a linee (geom_line() + geom_point()), con il mese sull’asse x, il numero di prestiti n sull’asse y e una linea di colore diverso per ogni biblioteca. Aggiungi poi:

  • scale_x_continuous(breaks = 1:12) per mostrare tutti i mesi sull’asse x
  • scale_color_brewer(palette = "Dark2") per cambiare la tavolozza dei colori
  • Controlla: guarda bene il mese di agosto. Che cosa mostra il grafico per le biblioteche B01, B02 e B03? Che cosa è successo davvero? Controlla la tabella prestiti_mese.
  • Bonus: usa labels = month.abb all’interno di scale_x_continuous(). Che cos’è month.abb?
TipSuggerimento

Ogni estetica ha la sua famiglia di funzioni scale_<estetica>_<tipo>(): ad esempio scale_x_log10(), scale_x_continuous(), scale_fill_brewer(), scale_color_manual(). Le scale controllano come i valori delle variabili diventano posizioni, colori, dimensioni.

Attività 8 - Rifinire e salvare

Salva il grafico dell’attività 7 in un oggetto p e aggiungi, un pezzo alla volta:

  • titolo, sottotitolo, etichette degli assi, titolo della legenda e fonte, con labs() (argomenti title, subtitle, x, y, color, caption)
  • un tema predefinito, ad esempio theme_minimal()
  • la legenda in basso, con theme(legend.position = "bottom")

Salva infine il grafico in un file png con ggsave("prestiti_mese_biblioteca.png", p, width = 8, height = 4.5) e cerca il file nella cartella del progetto.

  • Anticipa: che cosa succede se aggiungi theme(legend.position = "bottom") prima di theme_minimal()?

Sfida finale - Ricrea questo grafico

Ricrea il grafico seguente, costruito sui dati della tabella utenti.

TipIndizi
  • ci sono 145 utenti, non 150: quali sono stati esclusi?
  • l’età è sull’asse x; le categorie sono ordinate secondo l’età mediana: cerca l’aiuto di fct_reorder()
  • i colori sono "#E6A817" e "#003087", con trasparenza 0.7
  • quando hai una tua versione, prova a chiedere lo stesso grafico a un assistente AI partendo dall’immagine, come visto la settimana scorsa: confronta il suo codice con il tuo