Visualizzatore dello Spazio Narrativo Proppiano
Description
Questo software, denominato "Visualizzatore dello Spazio Narrativo Proppiano (VSNP)", rappresenta un'implementazione computazionale (Versione 1.0.0) per l'analisi e la visualizzazione di narrazioni, specificamente fiabe, codificate secondo le 31 funzioni morfologiche di Vladimir Propp. Sviluppato nell'ambito della più ampia ricerca del Dr. Luigi Usai sulla Teoria del Tensore Narrativo, lo script utilizza Python e librerie scientifiche standard (NumPy, Matplotlib, Scikit-learn) per:
- Rappresentare le fiabe come vettori in uno spazio funzionale proppiano.
- Applicare tecniche di riduzione dimensionale (PCA e t-SNE) per proiettare questo spazio multidimensionale in rappresentazioni 2D, facilitando l'identificazione visiva di cluster e relazioni strutturali tra le narrazioni.
- Calcolare metriche di similarità (es. similarità del coseno) per quantificare la vicinanza strutturale tra le fiabe basata sulla loro composizione funzionale. Il VSNP è concepito come uno strumento esplorativo e analitico per ricercatori in narratologia computazionale, studi folklorici, e discipline umanistiche digitali, offrendo un passo concreto verso l'operazionalizzazione del concetto di Tensore Narrativo per l'analisi comparativa delle strutture narrative. Il codice include un dataset esemplificativo basato su fiabe europee note, ma è strutturato per essere estensibile a corpora più ampi e all'intero set di funzioni proppiane.
- Introdotta anche una visualizzazione 3D dello Spazio Narrativo di Propp.
# Visualizzatore dello Spazio Narrativo Proppiano (2D e 3D)
# Autore: Dr. Luigi Usai (concettualizzazione) e Gemini (implementazione)
# Data: 25 Maggio 2025
# Versione: 1.1.0 (con aggiunta visualizzazione 3D)
# Descrizione: Questo script analizza un insieme di narrazioni (fiabe) codificate
# secondo le funzioni morfologiche di Vladimir Propp.
# Utilizza tecniche di riduzione dimensionale (PCA, t-SNE) per visualizzare
# le fiabe in uno spazio 2D e PCA per una visualizzazione 3D.
# Calcola inoltre la similarità del coseno tra le fiabe.
# Questo strumento è un passo verso l'operazionalizzazione del
# concetto di Tensore Narrativo.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # Necessario per i plot 3D
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.metrics.pairwise import cosine_similarity
# Definiamo le 31 funzioni di Propp (dal Suo generatore propp_varianti_generator_py_v1)
FUNZIONI_PROPP_CODICI = [f"F{i+1}" for i in range(31)]
FUNZIONI_PROPP_DESCRIZIONI = {
"F1": "Allontanamento", "F2": "Divieto", "F3": "Infrazione",
"F4": "Investigazione", "F5": "Delazione", "F6": "Tranello",
"F7": "Connivenza", "F8": "Danneggiamento/Mancanza", "F9": "Mediazione",
"F10": "Consenso dell'Eroe", "F11": "Partenza dell'Eroe", "F12": "Messa alla Prova",
"F13": "Reazione dell'Eroe", "F14": "Conseguimento Mezzo Magico", "F15": "Trasferimento",
"F16": "Lotta", "F17": "Marchiatura", "F18": "Vittoria",
"F19": "Rimozione Danno/Mancanza", "F20": "Ritorno dell'Eroe", "F21": "Persecuzione",
"F22": "Salvataggio", "F23": "Arrivo in Incognito", "F24": "Pretese Falso Eroe",
"F25": "Compito Difficile", "F26": "Adempimento Compito", "F27": "Riconoscimento",
"F28": "Smascheramento", "F29": "Trasfigurazione", "F30": "Punizione",
"F31": "Nozze/Ricompensa"
}
# Utilizziamo le funzioni selezionate nel Suo esempio tabellare per la dimostrazione.
FUNZIONI_SUBSET_CODICI = ["F1", "F2", "F3", "F8", "F11", "F14", "F16", "F18", "F31"]
FUNZIONI_SUBSET_NOMI_SINTETICI = [
FUNZIONI_PROPP_DESCRIZIONI[codice] for codice in FUNZIONI_SUBSET_CODICI
]
NOMI_FIABE = [
"Cappuccetto Rosso", "Biancaneve", "Cenerentola",
"Aladino", "Il Gatto con gli Stivali",
"Hansel e Gretel (sempl.)",
"La Bella Addormentata (sempl.)"
]
MATRICE_FIABE_FUNZIONI = np.array([
[1, 1, 1, 1, 1, 0, 1, 0, 0], # Cappuccetto Rosso
[1, 0, 0, 1, 1, 1, 1, 1, 1], # Biancaneve
[1, 0, 0, 1, 1, 1, 0, 1, 1], # Cenerentola
[0, 1, 1, 1, 1, 1, 1, 1, 1], # Aladino
[1, 0, 0, 1, 1, 1, 1, 1, 1], # Il Gatto con gli Stivali
[1, 0, 0, 1, 0, 1, 0, 1, 0], # Hansel e Gretel
[0, 1, 1, 1, 0, 0, 0, 1, 1] # La Bella Addormentata
])
assert MATRICE_FIABE_FUNZIONI.shape[1] == len(FUNZIONI_SUBSET_CODICI), \
"Numero di colonne non corrisponde al numero di funzioni nel subset"
assert MATRICE_FIABE_FUNZIONI.shape[0] == len(NOMI_FIABE), \
"Numero di righe non corrisponde al numero di fiabe"
def visualizza_spazio_narrativo_2d_pca(matrice_dati, etichette_punti, etichette_funzioni):
if matrice_dati.shape[0] < 2 or matrice_dati.shape[1] < 2:
print("Dati insufficienti per PCA 2D.")
return
pca = PCA(n_components=2, random_state=42)
dati_ridotti_pca = pca.fit_transform(matrice_dati)
plt.figure(figsize=(12, 8))
plt.scatter(dati_ridotti_pca[:, 0], dati_ridotti_pca[:, 1], s=100, alpha=0.7, c=np.arange(len(etichette_punti)), cmap='viridis')
for i, etichetta in enumerate(etichette_punti):
plt.annotate(etichetta, (dati_ridotti_pca[i, 0], dati_ridotti_pca[i, 1]), textcoords="offset points", xytext=(0,10), ha='center', fontsize=9)
plt.title("Spazio Narrativo Proppiano 2D (PCA)", fontsize=16)
plt.xlabel(f"Componente Principale 1 (Varianza: {pca.explained_variance_ratio_[0]:.2f})", fontsize=12)
plt.ylabel(f"Componente Principale 2 (Varianza: {pca.explained_variance_ratio_[1]:.2f})", fontsize=12)
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()
print("\n--- Interpretazione Componenti Principali 2D (Loadings PCA) ---")
for i in range(pca.components_.shape[0]):
print(f"\nComponente Principale {i+1}:")
loadings_componente = pca.components_[i]
funzioni_e_loadings = sorted(zip(etichette_funzioni, loadings_componente), key=lambda x: abs(x[1]), reverse=True)
for funzione, loading in funzioni_e_loadings:
print(f" - {funzione}: {loading:.3f}")
print(f"Varianza spiegata: {pca.explained_variance_ratio_[i]:.3f}")
def visualizza_spazio_narrativo_2d_tsne(matrice_dati, etichette_punti):
if matrice_dati.shape[0] < 3: # t-SNE più stabile con più campioni
print("Skipping t-SNE 2D visualization due to insufficient samples.")
return
tsne = TSNE(n_components=2, random_state=42, perplexity=min(30, matrice_dati.shape[0]-1), n_iter=1000, learning_rate='auto', init='pca')
dati_ridotti_tsne = tsne.fit_transform(matrice_dati)
plt.figure(figsize=(12, 8))
plt.scatter(dati_ridotti_tsne[:, 0], dati_ridotti_tsne[:, 1], s=100, alpha=0.7, c=np.arange(len(etichette_punti)), cmap='viridis')
for i, etichetta in enumerate(etichette_punti):
plt.annotate(etichetta, (dati_ridotti_tsne[i, 0], dati_ridotti_tsne[i, 1]), textcoords="offset points", xytext=(0,10), ha='center', fontsize=9)
plt.title("Spazio Narrativo Proppiano 2D (t-SNE)", fontsize=16)
plt.xlabel("Dimensione t-SNE 1", fontsize=12)
plt.ylabel("Dimensione t-SNE 2", fontsize=12)
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()
def visualizza_spazio_narrativo_3d_pca(matrice_dati, etichette_punti, etichette_funzioni):
"""
Applica PCA per ridurre la dimensionalità a 3 componenti e visualizza i punti in 3D.
"""
if matrice_dati.shape[0] < 3 or matrice_dati.shape[1] < 3:
print("Dati insufficienti per PCA 3D (richiede almeno 3 campioni e 3 features).")
return
pca_3d = PCA(n_components=3, random_state=42)
dati_ridotti_pca_3d = pca_3d.fit_transform(matrice_dati)
fig = plt.figure(figsize=(14, 10))
ax = fig.add_subplot(111, projection='3d')
# Scatter plot 3D
# Usiamo un colore diverso per ogni fiaba per distinguerle meglio
colors = plt.cm.viridis(np.linspace(0, 1, len(etichette_punti)))
for i in range(dati_ridotti_pca_3d.shape[0]):
ax.scatter(dati_ridotti_pca_3d[i, 0], dati_ridotti_pca_3d[i, 1], dati_ridotti_pca_3d[i, 2],
s=100, alpha=0.8, color=colors[i], label=etichette_punti[i] if i < 10 else None) # Etichetta solo le prime per non affollare
# Aggiunta etichette testo vicino ai punti
ax.text(dati_ridotti_pca_3d[i, 0], dati_ridotti_pca_3d[i, 1], dati_ridotti_pca_3d[i, 2],
f' {etichette_punti[i]}', size=8, zorder=1, color='k')
ax.set_title("Spazio Narrativo Proppiano 3D (PCA)", fontsize=16)
ax.set_xlabel(f"Comp. Principale 1 (Var: {pca_3d.explained_variance_ratio_[0]:.2f})", fontsize=10)
ax.set_ylabel(f"Comp. Principale 2 (Var: {pca_3d.explained_variance_ratio_[1]:.2f})", fontsize=10)
ax.set_zlabel(f"Comp. Principale 3 (Var: {pca_3d.explained_variance_ratio_[2]:.2f})", fontsize=10)
ax.grid(True)
if len(etichette_punti) <= 10: # Mostra legenda solo se non troppe etichette
ax.legend(fontsize=9, loc='center left', bbox_to_anchor=(1.05, 0.5))
plt.tight_layout(rect=[0, 0, 0.85, 1]) # Aggiusta layout per far spazio alla legenda
plt.show()
print("\n--- Interpretazione Componenti Principali 3D (Loadings PCA) ---")
total_variance_explained_3d = np.sum(pca_3d.explained_variance_ratio_)
print(f"Varianza Totale Spiegata dai primi 3 Componenti: {total_variance_explained_3d:.3f}")
for i in range(pca_3d.components_.shape[0]):
print(f"\nComponente Principale {i+1} (3D):")
loadings_componente = pca_3d.components_[i]
funzioni_e_loadings = sorted(zip(etichette_funzioni, loadings_componente), key=lambda x: abs(x[1]), reverse=True)
for funzione, loading in funzioni_e_loadings:
print(f" - {funzione}: {loading:.3f}")
print(f"Varianza spiegata da questo componente: {pca_3d.explained_variance_ratio_[i]:.3f}")
def calcola_similarita_coseno(matrice_dati, etichette_punti):
if matrice_dati.shape[0] < 2:
print("Similarità del coseno richiede almeno due punti dati.")
return None
mat_similarita = cosine_similarity(matrice_dati)
print("\n--- Matrice di Similarità del Coseno tra le Fiabe ---")
riga_intestazione = "{:<28}".format("")
for etichetta in etichette_punti:
riga_intestazione += "{:<15}".format(etichetta[:13]) # Tronca etichette lunghe
print(riga_intestazione)
print("-" * len(riga_intestazione))
for i, etichetta_riga in enumerate(etichette_punti):
riga_dati = "{:<28}".format(etichetta_riga)
for j in range(mat_similarita.shape[1]):
riga_dati += "{:<15.3f}".format(mat_similarita[i, j])
print(riga_dati)
return mat_similarita
# --- Esecuzione Principale ---
if __name__ == "__main__":
print("--- Visualizzatore dello Spazio Narrativo Proppiano (2D e 3D) ---")
print(f"Numero di fiabe analizzate: {MATRICE_FIABE_FUNZIONI.shape[0]}")
print(f"Numero di funzioni di Propp considerate (subset): {MATRICE_FIABE_FUNZIONI.shape[1]}")
# 1. Visualizza lo spazio narrativo in 2D (PCA)
visualizza_spazio_narrativo_2d_pca(MATRICE_FIABE_FUNZIONI, NOMI_FIABE, FUNZIONI_SUBSET_NOMI_SINTETICI)
# 2. Visualizza lo spazio narrativo in 2D (t-SNE)
visualizza_spazio_narrativo_2d_tsne(MATRICE_FIABE_FUNZIONI, NOMI_FIABE)
# 3. Visualizza lo spazio narrativo in 3D (PCA)
visualizza_spazio_narrativo_3d_pca(MATRICE_FIABE_FUNZIONI, NOMI_FIABE, FUNZIONI_SUBSET_NOMI_SINTETICI)
# 4. Calcola e stampa la similarità del coseno
mat_similarita = calcola_similarita_coseno(MATRICE_FIABE_FUNZIONI, NOMI_FIABE)
if mat_similarita is not None and mat_similarita.shape == (len(NOMI_FIABE), len(NOMI_FIABE)):
print("\n--- Esempio di Interpretazione Similarità ---")
idx_biancaneve = NOMI_FIABE.index("Biancaneve")
idx_cenerentola = NOMI_FIABE.index("Cenerentola")
similarita_bc = mat_similarita[idx_biancaneve, idx_cenerentola]
print(f"Similarità tra 'Biancaneve' e 'Cenerentola': {similarita_bc:.3f}")
idx_cappuccetto = NOMI_FIABE.index("Cappuccetto Rosso")
similarita_cb = mat_similarita[idx_cappuccetto, idx_biancaneve]
print(f"Similarità tra 'Cappuccetto Rosso' e 'Biancaneve': {similarita_cb:.3f}")
print("\n--- Fine Analisi ---")
Files
Files
(21.6 kB)
| Name | Size | Download all |
|---|---|---|
|
md5:e966322475c71fcedc4c034e67a4346a
|
10.6 kB | Download |
|
md5:3e8c093093ade4e81137a3d918ffc21b
|
11.0 kB | Download |