import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import random
def generate_character_graph_and_analyze(characters_data, interactions_data, title="Rete di Interazione Personaggi Amleto (Tutti i Criteri)"):
"""
Genera e visualizza un grafo di interazioni tra personaggi e ne analizza le proprietà Small-World.
Args:
characters_data (list): Una lista di tuple (nome_personaggio, peso).
interactions_data (list): Una lista di tuple (personaggio_A, personaggio_B, peso_interazione).
title (str): Il titolo del grafico.
"""
G = nx.Graph()
# Aggiungi nodi (personaggi) con i loro attributi
for char_name, char_weight in characters_data:
G.add_node(char_name, weight=char_weight)
# Aggiungi archi (interazioni) con i loro pesi
for char_a, char_b, interaction_weight in interactions_data:
G.add_edge(char_a, char_b, weight=interaction_weight)
# --- Analisi delle Proprietà della Rete ---
print("\n--- Analisi delle Proprietà della Rete ---")
# 1. Coefficiente di Clustering Medio
avg_clustering_coefficient = nx.average_clustering(G)
print(f"Coefficiente di Clustering Medio (C): {avg_clustering_coefficient:.3f}")
# 2. Lunghezza Media del Cammino più Breve
if nx.is_connected(G):
avg_path_length = nx.average_shortest_path_length(G)
print(f"Lunghezza Media del Cammino più Breve (L): {avg_path_length:.3f}")
else:
print("La rete non è connessa. Impossibile calcolare la Lunghezza Media del Cammino più Breve per l'intera rete.")
avg_path_length = float('inf')
# --- Confronto con una Rete Casuale (Erdos-Renyi G(n, m)) ---
num_nodes = G.number_of_nodes()
num_edges = G.number_of_edges()
random_G = nx.gnm_random_graph(num_nodes, num_edges, seed=random.randint(0, 10000))
random_avg_clustering_coefficient = nx.average_clustering(random_G)
print(f"Coefficiente di Clustering Medio (C_random): {random_avg_clustering_coefficient:.3f} (Rete Casuale)")
random_avg_path_length = float('inf')
if nx.is_connected(random_G):
random_avg_path_length = nx.average_shortest_path_length(random_G)
print(f"Lunghezza Media del Cammino più Breve (L_random): {random_avg_path_length:.3f} (Rete Casuale)")
else:
print("Attenzione: La rete casuale generata non è connessa per il confronto L_random.")
print("\n--- Valutazione 'Small-World' ---")
is_small_world = False
if avg_clustering_coefficient > random_avg_clustering_coefficient * 3: # C è almeno 3 volte C_random
if avg_path_length < float('inf') and random_avg_path_length < float('inf') and avg_path_length <= random_avg_path_length * 1.5: # L è simile a L_random
is_small_world = True
if is_small_world:
print("**La rete sembra mostrare le caratteristiche di una rete 'Small-World'!**")
print(f"- I personaggi tendono a formare 'cricche' o gruppi stretti (C >> C_random).")
print(f"- Nonostante ciò, chiunque è raggiungibile da chiunque altro in pochi 'passaggi' (L ≈ L_random).")
else:
print("La rete potrebbe non essere una 'Small-World' in modo marcato, o necessita di un'analisi più approfondita.")
print("Verifica i valori: C dovrebbe essere molto più alto di C_random, e L comparabile a L_random.")
# --- Codice di Visualizzazione (come prima) ---
plt.figure(figsize=(14, 12))
pos = nx.spring_layout(G, k=0.85, iterations=50)
node_sizes = [G.nodes[node]['weight'] * 2500 for node in G.nodes()]
weights = [G.nodes[node]['weight'] for node in G.nodes()]
norm = mcolors.Normalize(vmin=min(weights), vmax=max(weights))
cmap = plt.cm.viridis
node_colors = [cmap(norm(G.nodes[node]['weight'])) for node in G.nodes()]
nx.draw_networkx_nodes(G, pos, node_size=node_sizes, node_color=node_colors, alpha=0.9)
edge_widths = [G.edges[edge]['weight'] * 6 for edge in G.edges()]
nx.draw_networkx_edges(G, pos, width=edge_widths, alpha=0.6, edge_color='gray')
nx.draw_networkx_labels(G, pos, font_size=11, font_weight='bold')
edge_labels = nx.get_edge_attributes(G, 'weight')
formatted_edge_labels = {edge: f"{weight:.2f}" for edge, weight in edge_labels.items()}
nx.draw_networkx_edge_labels(G, pos, edge_labels=formatted_edge_labels, font_size=9, label_pos=0.3)
plt.title(title, size=18)
plt.axis('off')
plt.show()
# --- Dati per Amleto (con tutti i criteri - i primi valori forniti) ---
characters_data_amleto = [
("Amleto", 1.000), ("Claudio", 0.750), ("Gertrude", 0.600), ("Polonio", 0.450),
("Ofelia", 0.400), ("Orazio", 0.650), ("Laerte", 0.350), ("Rosencrantz", 0.200),
("Guildenstern", 0.200), ("Spettro", 0.300), ("Fortebraccio", 0.150)
]
interactions_data_amleto_full_criteria = [
("Amleto", "Orazio", 0.95),
("Amleto", "Claudio", 0.85),
("Amleto", "Gertrude", 0.70),
("Amleto", "Ofelia", 0.60), # Includeva sentimento e rilevanza narrativa
("Amleto", "Polonio", 0.55),
("Amleto", "Spettro", 0.80), # Elevata per rilevanza narrativa
("Amleto", "Rosencrantz", 0.30),
("Amleto", "Guildenstern", 0.30),
("Claudio", "Gertrude", 0.80),
("Claudio", "Polonio", 0.50),
("Claudio", "Laerte", 0.45),
("Gertrude", "Ofelia", 0.20),
("Polonio", "Ofelia", 0.70),
("Polonio", "Laerte", 0.65),
("Ofelia", "Laerte", 0.55),
("Orazio", "Spettro", 0.25),
("Orazio", "Fortebraccio", 0.10)
]
# Chiamata alla funzione per generare il grafico e analizzare la rete
if __name__ == "__main__":
generate_character_graph_and_analyze(characters_data_amleto, interactions_data_amleto_full_criteria) Click Run or press shift + ENTER to run code