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")ggplot2 in pratica
Attività in aula - mercoledì 28 ottobre 2026
Come funziona
Oggi impariamo ggplot2 per piccoli passi. Per ogni attività:
- Osserva: il docente presenta un’idea nuova con un esempio sui dati
gapminder - Anticipa: prima di eseguire il codice, scrivi su un foglio (o nello script, come commento) che cosa ti aspetti di vedere
- Esegui: esegui il codice e verifica se avevi ragione
- Modifica: adatta il codice ai dati delle biblioteche ed eseguilo
- 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 cartellalab11e aprila con File → Open Folder). - Crea una sottocartella
datie salva al suo interno i file dell’esercitazione 1 (utenti.csv,prestiti.xlsxecatalogo.txt). - Crea uno script
lab11_cognome_nome.Re copia al suo inizio il codice che segue. Eseguilo e verifica di avere nell’ambiente di lavoro le tabelleutenti(150 righe),prestiti(396 righe) eprestiti_completo(389 righe).
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 digeom_col()con la stessaaes(x = categoria, y = n)? - Bonus: ordina le barre dalla più alta alla più bassa. Con
geom_bar()puoi usarex = fct_infreq(categoria); congeom_col()puoi usarex = reorder(categoria, -n).
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:
- con
geom_point(aes(color = "blue")) - con
geom_point(color = "blue") - con
color = categoriaall’interno diaes()
- 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.
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 poigeom_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 funzioniadorn_*()corrisponde il grafico conposition = "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"afacet_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 xscale_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.abball’interno discale_x_continuous(). Che cos’èmonth.abb?
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()(argomentititle,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 ditheme_minimal()?
Sfida finale - Ricrea questo grafico
Ricrea il grafico seguente, costruito sui dati della tabella utenti.

- 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