Storytelling con i dati — Deliverable 3.3

BRISWA 2.0 • Work Package 3

Negativo Neutro Positivo

Storytelling con i dati: un Policy Brief e una Guida didattica — Questo documento ha una duplice finalità. È scritto come un policy brief, utilizzando dati reali su razzismo e inclusione per mettere in luce il divario tra ottimismo, fiducia e vissuto quotidiano. Allo stesso tempo, funziona come guida didattica, mostrando passo passo come creare grafici e infografiche in Python e trasformarli in strumenti di narrazione. In questo modo i lettori non solo comprendono i risultati, ma imparano anche i metodi che li generano — così da poter applicare gli stessi strumenti in altri contesti di decisione sociale.

L’indagine BRISWA 2.0 restituisce un quadro in generale ottimista: la maggior parte dei (giovani) rispondenti si fida delle proprie università, considera lo sport un veicolo di integrazione e dà per scontata la norma dell’inclusione. Allo stesso tempo, circa uno su cinque riferisce esperienze dirette di discriminazione razziale e quasi nessuno di loro ha ricevuto assistenza. Le visualizzazioni che seguono servono quindi sia come esempi tecnici, sia come dispositivi narrativi per raccontare questa storia più complessa, in cui fiducia istituzionale e ottimismo convivono con episodi persistenti di razzismo nella vita quotidiana — nei luoghi dell’educazione, negli spazi pubblici, nei social media e nello sport.

GraficoPythonDati

Percezioni delle istituzioni (con riquadro sull’età)

Barre sovrapposte divergenti (negativo / neutro / positivo) per tre domande: Sostegno all’integrazione, I programmi affrontano il razzismo e Efficacia sull’inclusione. A destra, un riquadro più piccolo mostra la distribuzione per età dei rispondenti, concentrata nella prima età adulta.

Le risposte sono raggruppate in tre blocchi: negativo (valutazioni 1–2 o “No”), neutro (valutazione 3 o “Non so / risposta mista”) e positivo (valutazioni 4–5 o “Sì”). Su tutte e tre le domande emerge un pattern chiaro: circa tre quarti degli studenti esprimono valutazioni positive, una quota molto ridotta è apertamente negativa e circa un quinto rimane nella fascia neutra. Quest’ultimo gruppo è particolarmente rilevante, perché segnala esperienze miste o incertezza su quanto le istituzioni siano davvero efficaci nel rispondere al razzismo e nel promuovere l’inclusione.

Letto insieme al riquadro sull’età, il grafico suggerisce uno sguardo “ottimista ma ancora in formazione”: un campione prevalentemente giovane (per lo più tra i 18 e i 24 anni) esprime fiducia negli sforzi istituzionali, ma una quota non trascurabile esita a sostenerli pienamente. Queste risposte ambigue offrono un contesto importante per le esperienze di discriminazione mostrate nei grafici successivi.

Grafico sulle percezioni istituzionali con riquadro sull’età
Clicca sull’immagine per ingrandire Scarica PDF
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
import numpy as np

# --------------------------
# 1) Institutional trust data
# --------------------------
support_counts   = {1: 2, 2: 4, 3: 29, 4: 33, 5: 69}
prog_counts_raw  = {'No': 17, 'No, Not sure': 1, 'Not sure': 32, 'Yes': 86, 'Yes, No': 1}
effective_counts = {1: 1, 2: 4, 3: 26, 4: 51, 5: 55}

def likert_to_buckets(counts):
    total = sum(counts.values())
    neg = counts.get(1, 0) + counts.get(2, 0)
    neu = counts.get(3, 0)
    pos = counts.get(4, 0) + counts.get(5, 0)
    return neg, neu, pos, total

def yns_to_buckets(counts):
    neg = counts.get('No', 0)
    pos = counts.get('Yes', 0)
    neu = counts.get('Not sure', 0) + counts.get('Yes, No', 0) + counts.get('No, Not sure', 0)
    total = neg + neu + pos
    return neg, neu, pos, total

def to_pct(neg, neu, pos, total):
    f = 100.0 / total if total else 0
    return neg*f, neu*f, pos*f

sN, sU, sP = to_pct(*likert_to_buckets(support_counts))
pN, pU, pP = to_pct(*yns_to_buckets(prog_counts_raw))
eN, eU, eP = to_pct(*likert_to_buckets(effective_counts))

labels = [
    "Support for integration",
    "Programmes address racism",
    "Effectiveness on inclusion"
]
rows = [(sN, sU, sP), (pN, pU, pP), (eN, eU, eP)]

# Consistent colors
NEG_COLOR = "#d73027"  # negative (red)
NEU_COLOR = "#f7f7f7"  # neutral (light gray)
POS_COLOR = "#2b8cbe"  # positive (blue)

# --------------------------
# 2) Age distribution data
# --------------------------
ages = [
    24,20,22,22,18,21,19,25,20,20,21,19,20,18,24,22,19,23,22,21,
    21,21,20,20,19,18,19,21,20,22,21,20,20,20,20,20,20,19,20,20,
    20,20,20,23,26,25,20,21,22,20,23,19,20,22,20,19,20,20,19,20,
    19,20,21,20,20,21,20,18,21,19,20,19,20,20,23,22,21,22,20,20,
    20,19,20,20,20,19,20,22,20,20,20,20,19,20,20,21,20,22,20,20,
    19,20,22,21,21,23,21,20,20,20,20,22,19,19,21,22,24,19,19,22,
    28,20,20,21,20,19,20,22,18,20,22,19,20
]

ages_arr = np.array(ages, dtype=int)
bins = np.arange(ages_arr.min()-0.5, ages_arr.max()+1.5, 1)  # 1-year bins
counts, bin_edges = np.histogram(ages_arr, bins=bins)
centers = (bin_edges[:-1] + bin_edges[1:]) / 2.0

# Smooth histogram with a simple moving average
kernel = np.array([1, 2, 1], dtype=float)
kernel = kernel / kernel.sum()
smooth = np.convolve(counts, kernel, mode='same').astype(float)
if smooth.max() > 0:
    smooth = smooth / smooth.max()  # normalize 0–1

# Mode age (dominant)
unique, cts = np.unique(ages_arr, return_counts=True)
mode_age = int(unique[np.argmax(cts)])  # likely 20 or 21

# --------------------------
# Plot: main chart + inset
# --------------------------
fig, ax = plt.subplots(figsize=(12, 6))

# Diverging stacked bars
ypos = list(range(len(rows)))[::-1]
for y, (neg, neu, pos) in zip(ypos, rows):
    ax.barh(y, -neg, left=0, align='center', color=NEG_COLOR, edgecolor='none')
    ax.barh(y, neu, left=0, align='center', color=NEU_COLOR, edgecolor='none')
    ax.barh(y, pos, left=neu, align='center', color=POS_COLOR, edgecolor='none')

ax.set_yticks(ypos)
ax.set_yticklabels(labels)
ax.set_xlim(-100, 100)
ax.set_xlabel("Share of respondents (%)")
ax.axvline(0, linewidth=1, color="#999999")
ax.set_title("Institutional perceptions")

# Segment annotations
def annotate(x_left, width, y, text):
    if abs(width) < 4: return
    ax.text(x_left + width/2, y, text, va='center', ha='center', fontsize=9)

for y, (neg, neu, pos) in zip(ypos, rows):
    annotate(-neg, neg, y, f"{neg:.0f}%")
    annotate(0, neu, y, f"{neu:.0f}%")
    annotate(neu, pos, y, f"{pos:.0f}%")

# Legend
handles = [
    Patch(facecolor=NEG_COLOR, edgecolor='none', label="Negative (1–2 or No)"),
    Patch(facecolor=NEU_COLOR, edgecolor='none', label="Neutral (3 or Not sure / mixed)"),
    Patch(facecolor=POS_COLOR, edgecolor='none', label="Positive (4–5 or Yes)")
]
ax.legend(handles=handles, loc="upper center", ncol=3, bbox_to_anchor=(0.5, 1.12), frameon=False)

# --------------------------
# Inset: small age distribution on the right
# --------------------------
mini = ax.inset_axes([0.15, 0.15, 0.22, 0.55])  # x0, y0, width, height
mini.set_facecolor("white")

mini.plot(centers, smooth, color=POS_COLOR, lw=2)

# Only one x tick at dominant age
mini.set_xticks([mode_age])
mini.set_xticklabels([str(mode_age)])

# No y ticks; vertical label
mini.set_yticks([])
mini.set_ylabel("age distribution", rotation=90)

# Clean look
for spine in ["top", "right"]:
    mini.spines[spine].set_visible(False)
mini.spines["bottom"].set_alpha(0.4)
mini.spines["left"].set_alpha(0.4)

mini.set_title("Age distribution", pad=6, fontsize=10)

plt.tight_layout()
plt.show()
GraficoPython

Hai subito discriminazioni razziali?

Grafico a ciambella che riassume se i rispondenti hanno subito discriminazioni razziali dopo l’arrivo nel paese ospitante. Il segmento “Sì” combina le risposte chiaramente positive e le voci miste “Sì, No”; al centro, un’etichetta indica la quota complessiva di studenti che ha sperimentato discriminazioni, insieme alla piccolissima percentuale che ha ricevuto assistenza.

Su 137 rispondenti, 109 hanno risposto “No”, 26 “Sì” e 2 hanno selezionato sia “Sì” sia “No”. Nel complesso, ciò significa che 28 studenti — circa uno su cinque — hanno riferito esperienze personali di discriminazione razziale. Tra questi, solo una persona (il 3,6% del gruppo “Sì”) ha dichiarato di aver ricevuto assistenza. Per quasi tutti gli altri, il supporto non è stato offerto, non era accessibile o non è stato richiesto.

Il riquadro di testo a destra della ciambella mostra i contesti in cui questi 28 studenti hanno subito discriminazioni. Oltre la metà cita spazi pubblici, quasi la metà contesti educativi e più di un terzo i social media. Solo una quota ridotta menziona esplicitamente il calcio. Questi pattern suggeriscono che gli episodi si concentrano nella vita pubblica e istituzionale di tutti i giorni, proprio negli stessi spazi in cui, come mostrano i grafici precedenti, fiducia e ottimismo verso le istituzioni sono relativamente alti.

Grafico a ciambella: esperienze di discriminazione razziale
Clicca sull’immagine per ingrandire Scarica PDF
import matplotlib.pyplot as plt

# --- Inline survey data (exact tallies) ---
discr_experience = {"No": 109, "Yes": 26, "Yes, No": 2}
n_total = sum(discr_experience.values())
n_yes = 26 + 2   # count "Yes" + mixed

# Context percentages among the 28 "Yes"
context_info = [
    "Of those who responded Yes:",
    "57.1% experienced discrimination in a public space",
    "46.5% experienced discrimination in an educational setting",
    "39.3% experienced discrimination in Social media",
    "7.1% experienced discrimination in a football setting"
]

# --- Donut chart ---
fig, ax = plt.subplots(figsize=(8, 6))
sizes = list(discr_experience.values())
labels = list(discr_experience.keys())

# Consistent color scheme: blue = No, red = Yes, gray = Yes/No
colors = ["#1f77b4", "#d62728", "#bdbdbd"]  

wedges, _ = ax.pie(sizes, startangle=90, colors=colors)

# Donut hole
centre_circle = plt.Circle((0, 0), 0.60, fc="white")
ax.add_artist(centre_circle)

# Title
ax.set_title("Experienced racial discrimination?")

# Central text
pct_yes = round(100.0 * n_yes / n_total, 1)
ax.text(0, 0.07, f"{pct_yes}%", ha="center", va="center", fontsize=12, weight="bold")
ax.text(0, -0.06, "reported ‘Yes’", ha="center", va="center", fontsize=11)
ax.text(0, -0.20, "3.6% of ‘Yes’ received assistance",
        ha="center", va="center", fontsize=9, color="darkred")

# Legend box positioned near the "Yes" slice (red, right side)
legend_text = "\n".join(context_info)
ax.text(1.2, 0, legend_text,
        ha="left", va="center",
        fontsize=10,
        bbox=dict(boxstyle="round,pad=0.5", fc="white", ec="0.5"))

ax.set_aspect('equal')
plt.tight_layout()
plt.show()
GraficoPython

Sport: strumento di integrazione e luogo di discriminazione

Infografica combinata che mette in relazione tre prospettive sullo sport: le principali tipologie di programmi antirazzisti individuate nelle analisi di progetto (con “Lo sport come strumento di integrazione” in evidenza); le risposte all’indagine sulla domanda se lo sport sia un efficace strumento contro il razzismo; e i contesti in cui gli studenti che hanno sperimentato discriminazione dicono che gli episodi si sono verificati, compresa una piccola fetta relativa al calcio.

Nel questionario, il 92% dei rispondenti ha risposto “Sì” alla domanda se lo sport possa essere uno strumento di integrazione tra culture, mentre solo una minoranza è in disaccordo. Questo dato risuona con quanto emerge dall’analisi dei programmi: molte iniziative usano lo sport e il calcio come veicolo principale per promuovere l’inclusione, accanto a forum comunitari, supporto a gruppi vulnerabili, attività di sensibilizzazione e azioni educative e formative.

Allo stesso tempo, il calcio non è solo parte della soluzione ma anche parte del problema. Nella scomposizione dei contesti di discriminazione, una fetta del 7,1% corrisponde a episodi esplicitamente collegati ad ambienti calcistici. Mettere questa fetta accanto alla convinzione fortemente positiva sul ruolo integrativo dello sport e alla centralità dei programmi basati sullo sport crea una tensione deliberata: lo sport è celebrato come potente strumento antirazzista, ma rimane anche un’arena in cui razzismo e molestie possono ancora emergere e vanno affrontati in modo attivo.

Infografica sullo sport come strumento di integrazione e contesto di discriminazione
Clicca sull’immagine per ingrandire Scarica PDF
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
import math

# -----------------------
# Inline data (as given)
# -----------------------
program_groups = {
    "Sport as tool for integration": 1,  # highlighted
    "Community forums & dialogue": 1,
    "Support for vulnerable groups": 1,
    "Awareness-raising": 1,
    "Education & training": 1
}

sport_counts = {"Yes": 126, "No": 11}  # survey belief in sport as integration

# Contexts among those who experienced discrimination (share within 'Yes' group)
contexts_pct = {
    "Public space": 57.1,
    "Educational setting": 46.5,
    "Social media": 39.3,
    "Football setting": 7.1  # highlight this
}

# -----------------------
# Look & feel
# -----------------------
HIGHLIGHT = "#2b8cbe"   # vivid blue
PALE      = "#cdd9e5"   # pale blue/gray for toned-down bars
NO_TONE   = "#c7c7c7"   # toned-down gray for "No"
PIE_PALE  = "#e6e6e6"   # pale for non-highlighted pie slices
PIE_HI    = "#d73027"   # highlight color for football slice (stands out)

# -----------------------
# Layout: 2x2 grid (bottom spans both columns)
# -----------------------
fig = plt.figure(figsize=(12.5, 8), constrained_layout=True)
gs  = fig.add_gridspec(2, 2, height_ratios=[1, 1.1])

# --- Top-left: Program groups (highlight 'Sport') ---
ax0 = fig.add_subplot(gs[0, 0])
labels_pg = list(program_groups.keys())
values_pg = list(program_groups.values())
colors_pg = [HIGHLIGHT if "Sport" in lab else PALE for lab in labels_pg]
ax0.barh(labels_pg, values_pg, color=colors_pg)
ax0.set_xlim(0, 1.2)
ax0.set_xticks([])
ax0.set_title("Anti-racism program types", pad=6)
for i, lab in enumerate(labels_pg):
    ax0.text(0.05, i, lab, va="center", ha="left", fontsize=10, color="black")

# --- Top-right: Yes/No belief (Yes highlighted, No toned down) ---
ax1 = fig.add_subplot(gs[0, 1])
yn_labels = list(sport_counts.keys())
yn_vals   = list(sport_counts.values())
yn_colors = [HIGHLIGHT if lab == "Yes" else NO_TONE for lab in yn_labels]
bars = ax1.bar(yn_labels, yn_vals, color=yn_colors)
ax1.set_title("Do students see sport as an effective anti-racism tool?", pad=6)
ax1.set_ylabel("Number of respondents")
for b in bars:
    ax1.text(b.get_x() + b.get_width()/2, b.get_height() + 0.8, f"{int(b.get_height())}", ha="center", va="bottom", fontsize=10)

# --- Bottom: Pie (contexts) — only 'Football' highlighted ---
ax2 = fig.add_subplot(gs[1, :])
labels_ctx = list(contexts_pct.keys())
values_ctx = list(contexts_pct.values())
colors_ctx = [PIE_HI if "Football" in lab else PIE_PALE for lab in labels_ctx]
wedges, texts = ax2.pie(values_ctx, colors=colors_ctx, startangle=90)
ax2.set_title("Where discrimination occurs (among those who reported it)", pad=8)
legend_handles = [
    Patch(facecolor=PIE_HI,  label="Football setting"),
    Patch(facecolor=PIE_PALE, label="Other contexts")
]
ax2.legend(handles=legend_handles, loc="center left", bbox_to_anchor=(0.02, 0.5), frameon=False)

fb_idx = labels_ctx.index("Football setting")
fb_wedge = wedges[fb_idx]
angle = (fb_wedge.theta2 + fb_wedge.theta1) / 2
r = 1.1
x = r * math.cos(math.radians(angle))
y = r * math.sin(math.radians(angle))
ax2.text(x, y, "7.1%", ha="center", va="center", fontsize=11, weight="bold")

plt.show()
GraficoPython

Indicatori demografici

Infografica a doppia ciambella costruita a partire da indicatori esterni sulla migrazione in Spagna. L’anello interno mostra la quota di donne fra i nuovi cittadini nazionalizzati (57%), mentre l’anello esterno evidenzia la quota di donne migranti che vivono in povertà grave (16,7%). Entrambi gli indicatori provengono dal contesto demografico più ampio utilizzato nel rapporto.

Le due percentuali svolgono ruoli diversi nella narrazione. L’anello interno sottolinea che le donne rappresentano la maggioranza dei nuovi cittadini, in un contesto in cui, in un solo anno, sono state concesse oltre duecentomila nazionalizzazioni. L’anello esterno ricorda che una minoranza significativa di donne migranti vive in condizioni di povertà grave, anche quando il percorso di integrazione formale attraverso nazionalità e permessi sembra avanzare. Nel rapporto completo questi indicatori sono affiancati da confronti per età e stabilità dei permessi; qui l’attenzione è su come la vulnerabilità di genere si intrecci con le forme formali di inclusione.

Affiancando i due anelli, il grafico collega l’indagine BRISWA 2.0 a condizioni strutturali più ampie: le traiettorie demografiche e gli indici di vulnerabilità in Spagna fanno da sfondo alle esperienze individuali di razzismo, fiducia e discriminazione. Le politiche contro il razzismo dovrebbero quindi essere informate fin dall’inizio da questi pattern demografici.

Doppia ciambella: indicatori demografici
Clicca sull’immagine per ingrandire Scarica PDF
import matplotlib.pyplot as plt
from matplotlib.patches import Patch

# Values
women_share = 57.0        # inner ring (blue)
severe_poverty = 16.7     # outer ring (red)

# Style
START = 90
OUTER_R, OUTER_W = 1.3, 0.28   # outer radius, width
INNER_R, INNER_W = 0.85, 0.28  # inner radius, width

BLUE_HI,  BLUE_REST  = "#1f77b4", "#dbe9f6"
RED_HI,   RED_REST   = "#d62728", "#f8c9c9"

fig, ax = plt.subplots(figsize=(7.2, 7.2))

# --- OUTER donut: migrant women in severe poverty (16.7% highlighted) ---
outer_vals   = [severe_poverty, 100 - severe_poverty]
outer_colors = [RED_HI, RED_REST]
ax.pie(outer_vals,
       radius=OUTER_R,
       startangle=START,
       colors=outer_colors,
       counterclock=False,
       wedgeprops=dict(width=OUTER_W, edgecolor="white"))

# --- INNER donut: women among new nationals (57% highlighted) ---
inner_vals   = [women_share, 100 - women_share]
inner_colors = [BLUE_HI, BLUE_REST]
ax.pie(inner_vals,
       radius=INNER_R,
       startangle=START,
       colors=inner_colors,
       counterclock=False,
       wedgeprops=dict(width=INNER_W, edgecolor="white"))

# Cosmetics
ax.set(aspect="equal")
ax.axis("off")
ax.set_title("Demographic indicators", pad=10, fontsize=14, weight="bold")

# Legends (right side)
handles = [
    Patch(facecolor=RED_HI,  label=f"Migrant women in severe poverty (Spain): {severe_poverty:.1f}%"),
    Patch(facecolor=BLUE_HI, label=f"Women among new nationals (Spain): {women_share:.0f}%"),
]
ax.legend(handles=handles, loc="center left", bbox_to_anchor=(1.05, 0.0), frameon=False)

plt.tight_layout()
plt.show()

Implicazioni

Considerati insieme, i grafici raccontano qualcosa di più di una serie di statistiche isolate. Mettono in luce un ottimismo di fondo tra i rispondenti: la maggior parte degli studenti si fida delle istituzioni, ritiene che i programmi affrontino il razzismo e vede lo sport come uno strumento di integrazione. Questo ottimismo è strettamente legato al profilo demografico del campione: un gruppo prevalentemente giovane, che dà per scontata la norma dell’inclusione.

Allo stesso tempo, la narrazione visiva sottolinea che la discriminazione persiste nonostante questo ottimismo. Un rispondente su cinque riferisce esperienze personali di discriminazione razziale, concentrate negli spazi pubblici, nell’educazione, nei social media e, in misura minore, nel calcio. Solo il 3,6% di chi ha subito discriminazioni ha ricevuto assistenza. Il divario tra fiducia nelle istituzioni e mancanza di supporto concreto quando gli episodi si verificano è dunque una questione centrale di policy.

Lo sport illustra in modo esemplare questa tensione. È celebrato come strumento efficace contro il razzismo ed è al centro di molte iniziative di integrazione, eppure rimane anche un luogo in cui si manifestano episodi di discriminazione. Questo duplice ruolo suggerisce che gli impegni simbolici verso fair play e rispetto devono essere accompagnati da meccanismi solidi per prevenire, monitorare e contrastare il razzismo nei contesti sportivi.

Infine, gli indicatori demografici ricordano che esperienze e politiche sul razzismo sono inserite in condizioni strutturali più ampie: traiettorie migratorie, distribuzioni per età, squilibri di genere, stabilità dei permessi e vulnerabilità alla povertà. Per istituzioni pubbliche, università e organizzazioni sportive, l’ottimismo non basta. Servono meccanismi e cornici operative in grado di:

  • tradurre la fiducia nelle istituzioni in supporto accessibile ed efficace quando si verificano episodi di discriminazione;
  • fare in modo che i programmi basati sullo sport trasformino il loro forte valore simbolico in azione antirazzista concreta;
  • progettare politiche informate fin dall’inizio dai pattern demografici e dagli indicatori di vulnerabilità.

Senza questo allineamento tra dati, contesto e azione, ogni strategia per contrastare il razzismo rischia di restare soprattutto aspirazionale, più che realmente efficace.

Torna in alto