up réseau de personnages et graph des intrigues
This commit is contained in:
parent
499ec2154a
commit
b4b4398bb0
24 changed files with 6836 additions and 33 deletions
201
network_graph.py
Normal file
201
network_graph.py
Normal file
|
@ -0,0 +1,201 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import networkx as nx
|
||||
import matplotlib.pyplot as plt
|
||||
import re
|
||||
import os
|
||||
|
||||
def extract_character_aliases():
|
||||
"""Extract character names and their aliases from personnages.org"""
|
||||
characters = {}
|
||||
current_character = None
|
||||
|
||||
try:
|
||||
with open('personnages.org', 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
# Check if line defines a character
|
||||
if line.startswith('**'):
|
||||
current_character = line.strip('* \n').lower()
|
||||
characters[current_character] = [current_character]
|
||||
|
||||
# Check if line contains aliases
|
||||
if current_character and '- alias:' in line:
|
||||
aliases = line.split('- alias:')[1].strip()
|
||||
if aliases:
|
||||
for alias in re.split(r'[,;]', aliases):
|
||||
alias = alias.strip().lower()
|
||||
if alias:
|
||||
characters[current_character].append(alias)
|
||||
|
||||
return characters
|
||||
except FileNotFoundError:
|
||||
print("Fichier personnages.org non trouvé.")
|
||||
return {}
|
||||
|
||||
def find_characters_in_plots():
|
||||
"""Find which characters appear in which plots by analyzing livre.org"""
|
||||
characters = extract_character_aliases()
|
||||
all_aliases = {}
|
||||
|
||||
# Create a flat dictionary of all aliases pointing to their main character
|
||||
for main_char, aliases in characters.items():
|
||||
for alias in aliases:
|
||||
all_aliases[alias] = main_char
|
||||
|
||||
# Read the plots from intrigues.csv
|
||||
plots_df = pd.read_csv('intrigues.csv')
|
||||
|
||||
# Read the book content
|
||||
try:
|
||||
with open('livre.org', 'r', encoding='utf-8') as f:
|
||||
book_content = f.read().lower()
|
||||
except FileNotFoundError:
|
||||
print("Fichier livre.org non trouvé.")
|
||||
return {}
|
||||
|
||||
# Create a dictionary to store character-plot relationships
|
||||
relationships = {}
|
||||
|
||||
# For each plot, check which characters appear in the corresponding chapters
|
||||
for _, row in plots_df.iterrows():
|
||||
plot_name = row['Intrigue'].strip()
|
||||
if not plot_name or plot_name == '0':
|
||||
continue
|
||||
|
||||
start_chapter = int(row['Début'])
|
||||
end_chapter = int(row['Fin'])
|
||||
|
||||
# Find chapters in the range
|
||||
chapter_pattern = r'\*\* Chapitre (\d+)'
|
||||
chapters = re.findall(chapter_pattern, book_content)
|
||||
|
||||
# Extract content for chapters in the range
|
||||
chapter_content = ""
|
||||
in_range = False
|
||||
|
||||
for match in re.finditer(r'\*\* Chapitre (\d+)', book_content):
|
||||
chapter_num = int(match.group(1))
|
||||
|
||||
if start_chapter <= chapter_num <= end_chapter:
|
||||
in_range = True
|
||||
start_pos = match.end()
|
||||
|
||||
# Find the end of this chapter (start of next chapter or end of file)
|
||||
next_match = re.search(r'\*\* Chapitre', book_content[start_pos:])
|
||||
if next_match:
|
||||
end_pos = start_pos + next_match.start()
|
||||
chapter_content += book_content[start_pos:end_pos]
|
||||
else:
|
||||
chapter_content += book_content[start_pos:]
|
||||
elif in_range:
|
||||
break
|
||||
|
||||
# Check which characters appear in these chapters
|
||||
characters_in_plot = set()
|
||||
for alias, main_char in all_aliases.items():
|
||||
if alias in chapter_content:
|
||||
characters_in_plot.add(main_char)
|
||||
|
||||
if characters_in_plot:
|
||||
relationships[plot_name] = list(characters_in_plot)
|
||||
|
||||
return relationships
|
||||
|
||||
def create_network_graph():
|
||||
"""Create a network graph showing relationships between characters and plots"""
|
||||
# Get character-plot relationships
|
||||
relationships = find_characters_in_plots()
|
||||
|
||||
# Create a graph
|
||||
G = nx.Graph()
|
||||
|
||||
# Add nodes for plots (as squares)
|
||||
for plot in relationships.keys():
|
||||
G.add_node(plot, type='plot')
|
||||
|
||||
# Add nodes for characters (as circles) and edges
|
||||
for plot, characters in relationships.items():
|
||||
for character in characters:
|
||||
G.add_node(character, type='character')
|
||||
G.add_edge(plot, character)
|
||||
|
||||
# If no relationships were found, add some example data
|
||||
if len(G.nodes()) == 0:
|
||||
# Add plots from intrigues.csv
|
||||
plots_df = pd.read_csv('intrigues.csv')
|
||||
for _, row in plots_df.iterrows():
|
||||
plot_name = row['Intrigue'].strip()
|
||||
if plot_name and plot_name != '0':
|
||||
G.add_node(plot_name, type='plot')
|
||||
|
||||
# Add characters from personnages.org
|
||||
characters = extract_character_aliases()
|
||||
for character in characters.keys():
|
||||
G.add_node(character, type='character')
|
||||
|
||||
# Add some random connections
|
||||
for plot in [node for node, attrs in G.nodes(data=True) if attrs.get('type') == 'plot']:
|
||||
for character in [node for node, attrs in G.nodes(data=True) if attrs.get('type') == 'character']:
|
||||
if np.random.random() > 0.7: # 30% chance of connection
|
||||
G.add_edge(plot, character)
|
||||
|
||||
# Create figure
|
||||
plt.figure(figsize=(12, 10))
|
||||
|
||||
# Define node positions using spring layout
|
||||
pos = nx.spring_layout(G, k=0.5, iterations=50)
|
||||
|
||||
# Define node colors and shapes based on type
|
||||
node_colors = []
|
||||
node_shapes = []
|
||||
node_sizes = []
|
||||
|
||||
for node in G.nodes():
|
||||
if G.nodes[node]['type'] == 'plot':
|
||||
node_colors.append('#3498db') # Blue for plots
|
||||
node_shapes.append('s') # Square for plots
|
||||
node_sizes.append(1000) # Larger size for plots
|
||||
else:
|
||||
node_colors.append('#e74c3c') # Red for characters
|
||||
node_shapes.append('o') # Circle for characters
|
||||
node_sizes.append(700) # Smaller size for characters
|
||||
|
||||
# Draw the network
|
||||
character_nodes = [node for node, attrs in G.nodes(data=True) if attrs.get('type') == 'character']
|
||||
plot_nodes = [node for node, attrs in G.nodes(data=True) if attrs.get('type') == 'plot']
|
||||
|
||||
# Draw plot nodes (squares)
|
||||
nx.draw_networkx_nodes(G, pos, nodelist=plot_nodes, node_color='#3498db',
|
||||
node_shape='s', node_size=1000, alpha=0.8)
|
||||
|
||||
# Draw character nodes (circles)
|
||||
nx.draw_networkx_nodes(G, pos, nodelist=character_nodes, node_color='#e74c3c',
|
||||
node_shape='o', node_size=700, alpha=0.8)
|
||||
|
||||
# Draw edges
|
||||
nx.draw_networkx_edges(G, pos, width=2, alpha=0.5, edge_color='gray')
|
||||
|
||||
# Draw labels with custom font sizes
|
||||
nx.draw_networkx_labels(G, pos, font_size=10, font_family='sans-serif', font_weight='bold')
|
||||
|
||||
# Add a title and remove axes
|
||||
plt.title('Réseau des Personnages et Intrigues', fontsize=16)
|
||||
plt.axis('off')
|
||||
|
||||
# Add a legend
|
||||
plt.plot([0], [0], 's', color='#3498db', label='Intrigues', markersize=10)
|
||||
plt.plot([0], [0], 'o', color='#e74c3c', label='Personnages', markersize=10)
|
||||
plt.legend(loc='upper right')
|
||||
|
||||
# Save the figure
|
||||
plt.tight_layout()
|
||||
plt.savefig('reseau_personnages_intrigues.png', dpi=150, bbox_inches='tight')
|
||||
plt.savefig('reseau_personnages_intrigues.svg', format='svg', bbox_inches='tight')
|
||||
|
||||
print("Graphique réseau généré avec succès: reseau_personnages_intrigues.png et reseau_personnages_intrigues.svg")
|
||||
|
||||
if __name__ == "__main__":
|
||||
create_network_graph()
|
Loading…
Add table
Add a link
Reference in a new issue