Hands-on Workshop
Cosa impareremo oggi:
theme() e i suoi parametrielement_*() per personalizzare ogni dettagliolabs()ggsave() in alta qualitàApproccio:
Struttura degli Esercizi:
📁 File: 09_themes_personalizzazione_exercises.R
30 esercizi organizzati in 6 parti:
💡 Suggerimento: Inizia con temi predefiniti, poi personalizza gradualmente!
Definizione:
Un tema controlla tutti gli elementi non relativi ai dati in un grafico:
Separazione Fondamentale:
Perché è Importante:
Best Practice
Separa sempre la creazione del grafico dalla sua personalizzazione estetica. Prima focus sui dati, poi sull’aspetto!
Caratteristiche:
library(ggplot2)
# Tema default (non serve specificare)
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class))
# Oppure esplicitamente
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
theme_gray()Quando usarlo:
Filosofia del Gray Background
Lo sfondo grigio non è casuale! Aiuta a:
Parametri base_size:
# Aumenta dimensioni testo
ggplot(mpg, aes(x = class)) +
geom_bar() +
theme_gray(base_size = 18)
# Diminuisce tutto
ggplot(mpg, aes(x = class)) +
geom_bar() +
theme_gray(base_size = 8)Tutti i temi accettano base_size, base_family, base_line_size, base_rect_size
theme_minimal():
ggplot(economics, aes(x = date, y = unemploy)) +
geom_line(color = "steelblue", size = 1) +
theme_minimal()
# Con base_size
ggplot(economics, aes(x = date, y = unemploy)) +
geom_line(color = "steelblue", size = 1) +
theme_minimal(base_size = 14)Quando usarlo:
theme_classic():
ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point(aes(color = Species), size = 3) +
theme_classic()Quando usarlo:
Differenza Chiave
theme_minimal() = griglia + no bordi
theme_classic() = no griglia + assi tradizionali
theme_bw() - Bianco e Nero
theme_void() - Nessun Elemento
theme_dark() - Sfondo Scuro
ggplot(diamonds, aes(x = carat, y = price)) +
geom_point(alpha = 0.1, color = "cyan") +
theme_dark()theme_light() - Leggero
Adesso tocca a te!
Struttura Gerarchica:
theme() controlla ~100 parametri organizzati gerarchicamente:
Ereditarietà: Gli elementi figli ereditano proprietà dai genitori
Background Elements:
ggplot(economics, aes(x = date, y = unemploy)) +
geom_line() +
theme_minimal() +
theme(
# Sfondo intero plot
plot.background = element_rect(
fill = "lightblue",
color = "navy",
size = 2
),
# Sfondo area dati
panel.background = element_rect(
fill = "white",
color = "black",
size = 1
),
# Bordo panel
panel.border = element_rect(
color = "darkgreen",
fill = NA,
size = 1.5
)
)Differenza plot vs panel:
# Esempio chiaro della differenza
ggplot(mpg, aes(x = class)) +
geom_bar() +
labs(title = "Distribuzione Classi") +
theme(
plot.background = element_rect(fill = "yellow"),
panel.background = element_rect(fill = "lightgreen"),
panel.border = element_rect(
color = "red",
fill = NA,
size = 2
)
)Attenzione
fill = NA significa trasparente, non “nessun fill”!
Controllo Completo delle Gridlines:
# Rimuovere tutte le griglie
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
theme_minimal() +
theme(
panel.grid = element_blank()
)
# Solo griglia maggiore
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
theme_minimal() +
theme(
panel.grid.minor = element_blank()
)
# Solo griglia orizzontale
ggplot(mpg, aes(x = class)) +
geom_bar() +
theme_minimal() +
theme(
panel.grid.major.x = element_blank(),
panel.grid.minor = element_blank()
)# Personalizza colore e stile
ggplot(economics, aes(x = date, y = unemploy)) +
geom_line() +
theme_minimal() +
theme(
panel.grid.major = element_line(
color = "gray70",
size = 0.5,
linetype = "dashed"
),
panel.grid.minor = element_line(
color = "gray90",
size = 0.25,
linetype = "dotted"
)
)Best Practice per Griglie
Adesso tocca a te!
Parametri Principali:
element_text(
family = "sans", # Font family
face = "plain", # plain, bold, italic
colour = "black", # Colore testo
size = 11, # Dimensione (pt)
hjust = 0.5, # Align orizzontale (0-1)
vjust = 0.5, # Align verticale (0-1)
angle = 0, # Rotazione (gradi)
lineheight = 1.2, # Interlinea
margin = margin(0,0,0,0) # Margini
)Esempio Completo:
Elementi di Testo Comuni:
plot.title - Titolo principaleplot.subtitle - Sottotitoloplot.caption - Didascaliaaxis.title.x/y - Titoli assiaxis.text.x/y - Labels assilegend.title - Titolo legendalegend.text - Testo legendastrip.text - Testo facetEsempio Ereditarietà:
Parametri:
element_line(
colour = "black",
size = 0.5,
linetype = 1, # 1=solid, 2=dashed, etc
lineend = "butt", # butt, round, square
arrow = NULL
)Tipi di Linea:
# linetype può essere:
# 0 = blank, 1 = solid, 2 = dashed
# 3 = dotted, 4 = dotdash, 5 = longdash
# 6 = twodash
ggplot(economics, aes(x = date, y = unemploy)) +
geom_line() +
theme_minimal() +
theme(
axis.line = element_line(
color = "black",
size = 1
),
panel.grid.major = element_line(
linetype = "dashed",
color = "gray70"
)
)Elementi di Linea Comuni:
axis.line.x/y - Linee assiaxis.ticks - Tick markspanel.grid.major/minor - Griglielegend.key - Bordo chiave legendaEsempio con Frecce:
Parametri:
element_rect(
fill = NA, # Colore riempimento
colour = NA, # Colore bordo
size = 0.5, # Spessore bordo
linetype = 1 # Tipo linea bordo
)Elementi Rettangolari:
plot.background - Sfondo interopanel.background - Sfondo panelpanel.border - Bordo panellegend.background - Sfondo legendalegend.key - Background chiavi legendastrip.background - Sfondo facet labelsfill vs colour:
ggplot(mpg, aes(x = class)) +
geom_bar() +
theme_classic() +
theme(
# fill = riempimento interno
plot.background = element_rect(
fill = "lightyellow"
),
# colour = bordo
panel.border = element_rect(
colour = "navy",
fill = NA, # Trasparente!
size = 2
)
)NA vs element_blank()
Due modi diversi di “rimuovere”:
fill = NA o colour = NA
→ Trasparente ma elemento esiste ancora
→ Occupa spazio nel layout
element_blank()
→ Elemento rimosso completamente
→ Non occupa spazio
Quando usare cosa:
NA: Vuoi l’elemento ma trasparenteelement_blank(): Non vuoi l’elemento affattoEsempio pratico:
Adesso tocca a te!
Annotazioni Complete:
labs(
title = "Titolo Principale",
subtitle = "Sottotitolo descrittivo",
caption = "Fonte dati",
x = "Asse X",
y = "Asse Y",
color = "Nome Legenda",
fill = "Nome Legenda",
size = "Nome Legenda",
# ... qualsiasi aesthetica
)Esempio Completo:
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
geom_point(size = 3, alpha = 0.7) +
labs(
title = "Consumo Carburante vs Cilindrata",
subtitle = "Dati EPA per veicoli 1999-2008",
caption = "Fonte: EPA fuel economy data",
x = "Cilindrata motore (litri)",
y = "Consumo autostrada (mpg)",
color = "Classe\nVeicolo"
) +
theme_minimal()Formattazione Titoli:
ggplot(economics, aes(x = date, y = unemploy/1000)) +
geom_line(color = "steelblue", size = 1) +
labs(
title = "Disoccupazione USA",
subtitle = "1967-2015",
y = "Disoccupati (migliaia)",
x = NULL, # Rimuove label
caption = "Dati: Federal Reserve Economic Data"
) +
theme_minimal() +
theme(
plot.title = element_text(
size = 20,
face = "bold",
hjust = 0 # Allinea a sinistra
),
plot.subtitle = element_text(
size = 14,
color = "gray40"
),
plot.caption = element_text(
size = 9,
hjust = 1, # Allinea a destra
face = "italic"
)
)Sostituire Tutti i Labels:
# ggtitle(), xlab(), ylab() - shortcut
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
ggtitle("Titolo") +
xlab("Asse X") +
ylab("Asse Y")
# Equivalente a:
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
labs(
title = "Titolo",
x = "Asse X",
y = "Asse Y"
)Multi-line Titles con expression():
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
labs(
title = expression(
paste("Consumo vs Cilindrata (", R^2, ")")
)
)Best Practice
Usa sempre labs() invece di modificare direttamente i nomi delle variabili nei dati!
Adesso tocca a te!
legend.position:
# Posizioni predefinite
theme(legend.position = "right") # Default
theme(legend.position = "left")
theme(legend.position = "top")
theme(legend.position = "bottom")
theme(legend.position = "none") # Nasconde
# Coordinate precise (0-1, 0-1)
ggplot(mpg, aes(x = displ, y = hwy,
color = class)) +
geom_point(size = 3) +
theme_minimal() +
theme(
legend.position = c(0.85, 0.75),
legend.background = element_rect(
fill = "white",
color = "black"
)
)legend.justification:
legend.direction:
# Layout orizzontale
ggplot(mpg, aes(x = displ, y = hwy,
color = class)) +
geom_point() +
theme_minimal() +
theme(
legend.position = "bottom",
legend.direction = "horizontal"
)
# Layout verticale (default)
theme(legend.direction = "vertical")legend.box:
# Quando hai più legende
ggplot(mpg, aes(x = displ, y = hwy,
color = class, size = cyl)) +
geom_point(alpha = 0.6) +
theme_minimal() +
theme(
legend.box = "horizontal", # Side-by-side
# oppure "vertical"
legend.box.just = "top"
)Multiple Legende
Usa legend.box per controllare il layout quando hai più di una estetica mappata.
Elementi Testo:
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
geom_point(size = 3) +
labs(color = "Classe Veicolo") +
theme_minimal() +
theme(
# Titolo legenda
legend.title = element_text(
size = 14,
face = "bold",
color = "navy"
),
# Labels legenda
legend.text = element_text(
size = 11,
face = "italic"
),
# Allineamento titolo
legend.title.align = 0.5 # 0=left, 0.5=center, 1=right
)Elementi Background:
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
geom_point(size = 3) +
theme_minimal() +
theme(
# Sfondo legenda
legend.background = element_rect(
fill = "gray95",
color = "black",
size = 0.5
),
# Sfondo chiavi
legend.key = element_rect(
fill = "white",
color = NA
),
# Dimensione chiavi
legend.key.size = unit(1.5, "cm"),
legend.key.height = unit(1, "cm"),
legend.key.width = unit(1, "cm")
)guides() - Controllo Fine:
# Personalizza guide per estetica
ggplot(mpg, aes(x = displ, y = hwy,
color = class, size = cyl)) +
geom_point(alpha = 0.6) +
guides(
color = guide_legend(
title = "Tipo",
nrow = 2,
override.aes = list(size = 4)
),
size = guide_legend(
title = "Cilindri",
reverse = TRUE
)
)guide_legend() Opzioni:
nrow/ncol - Righe/colonnebyrow - Riempimento per rigareverse - Inverti ordineoverride.aes - Modifica aesthetics nella legendatitle.position - “top”, “bottom”, “left”, “right”label.position - Come titleguide_colorbar() per Scale Continue:
ggplot(faithfuld, aes(waiting, eruptions)) +
geom_raster(aes(fill = density)) +
scale_fill_viridis_c() +
guides(
fill = guide_colorbar(
title = "Densità",
barwidth = 1,
barheight = 10,
title.position = "top",
title.hjust = 0.5
)
) +
theme_minimal()Rimuovere Guide Specifiche:
# Rimuove solo color legend
guides(color = "none")
# Equivalente a:
scale_color_discrete(guide = "none")Override Aesthetics
override.aes è perfetto per rendere le chiavi della legenda più visibili quando i punti nel plot sono piccoli o trasparenti.
Adesso tocca a te!
Definire un Tema Custom:
# Crea funzione tema
theme_mio <- function(base_size = 12) {
theme_minimal(base_size = base_size) +
theme(
# Griglia
panel.grid.minor = element_blank(),
panel.grid.major = element_line(
color = "gray90",
size = 0.5
),
# Testo
plot.title = element_text(
size = base_size * 1.5,
face = "bold",
hjust = 0,
margin = margin(b = 10)
),
plot.subtitle = element_text(
size = base_size * 1.1,
color = "gray40",
margin = margin(b = 15)
),
# Assi
axis.title = element_text(
size = base_size * 1.1,
face = "bold"
),
# Legenda
legend.position = "top",
legend.title = element_blank()
)
}Usare il Tema:
# Applica a singolo plot
ggplot(mpg, aes(x = displ, y = hwy,
color = class)) +
geom_point(size = 3) +
labs(
title = "Consumo vs Cilindrata",
subtitle = "Dati EPA"
) +
theme_mio()
# Con base_size diverso
ggplot(mpg, aes(x = class)) +
geom_bar() +
theme_mio(base_size = 16)Impostare come Default:
# Per tutta la sessione
theme_set(theme_mio())
# Ora tutti i plot usano theme_mio
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point()
# Reset a default
theme_set(theme_gray())Organizzazione
Salva i tuoi temi in un file R separato e caricalo con source("my_themes.R")
Sintassi Base:
p <- ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
theme_minimal()
# Salva ultimo plot
ggsave("mio_plot.png")
# Salva plot specifico
ggsave("mio_plot.png", plot = p)
# Specifica dimensioni
ggsave(
"mio_plot.png",
plot = p,
width = 8,
height = 6,
units = "in" # "in", "cm", "mm"
)Formati Supportati:
Risoluzione e DPI:
# Alta risoluzione per pubblicazioni
ggsave(
"plot_highres.png",
plot = p,
width = 8,
height = 6,
dpi = 300 # Standard pubblicazioni
)
# Bassa risoluzione per web
ggsave(
"plot_web.png",
plot = p,
width = 800,
height = 600,
units = "px",
dpi = 72
)Controllo Background:
# Sfondo trasparente
ggsave(
"plot_transparent.png",
plot = p,
bg = "transparent"
)
# Sfondo bianco
ggsave(
"plot_white.png",
plot = p,
bg = "white"
)DPI per Pubblicazioni
ggthemes - Temi Classici:
library(ggthemes)
# Economist style
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
geom_point(size = 3) +
theme_economist() +
scale_color_economist()
# Wall Street Journal
ggplot(mpg, aes(x = class)) +
geom_bar() +
theme_wsj()
# FiveThirtyEight
ggplot(economics, aes(x = date, y = unemploy)) +
geom_line() +
theme_fivethirtyeight()
# Altri: theme_tufte(), theme_excel(),
# theme_stata(), theme_solarized()hrbrthemes - Temi Moderni:
library(hrbrthemes)
# Modern minimal
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
theme_ipsum()
# Con font Roboto Condensed
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
theme_ipsum_rc()
# Dark theme
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(color = "white") +
theme_ft_rc()cowplot - Scientific:
1. Workflow Consigliato:
theme()labs()guides()ggsave()2. Separazione Responsabilità:
# ✅ GIUSTO: Separa dati e aspetto
p_base <- ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class))
p_styled <- p_base +
theme_minimal() +
labs(title = "Mio Plot")
# ❌ SBAGLIATO: Tutto insieme
ggplot(mpg, aes(...)) + geom_point(...) +
theme(...) + scale_x_continuous(...) +
guides(...) + labs(...)3. Riusabilità:
# Crea tema aziendale
theme_company <- function() {
theme_minimal() +
theme(
plot.title = element_text(
color = "#003366",
face = "bold"
),
# ... altri parametri
)
}Organizzazione Codice
source("my_themes.R")4. Pubblicazioni Scientifiche:
theme_classic() o theme_bw()5. Presentazioni:
theme_minimal() o theme_void()6. Web/Digital:
7. Accessibilità:
# Usa scale adatte a daltonici
scale_color_viridis_d()
scale_fill_brewer(palette = "Set2")
# Font leggibili
theme(text = element_text(size = 12))
# Contrasto sufficiente
# Evita rosso/verde come unica distinzioneGolden Rules
Documentazione:
Cheat Sheets:
Pacchetti Utili:
ggthemes - Temi classici (Economist, WSJ, Tufte)hrbrthemes - Temi moderni typography-focusedcowplot - Temi scientificithematic - Temi automatici da RStudio themeProssima Sessione:
Pratica Consigliata:
Continua a Imparare
Prova a combinare tutto ciò che hai imparato creando un grafico completo con dati personalizzati, tema custom, e esportalo in alta qualità!

REVELO Training - Data Viz 2025