Major update, v1.0 i guess ?
This commit is contained in:
108
tree.py
108
tree.py
@ -1,8 +1,17 @@
|
||||
import pygraphviz as pgv
|
||||
import json
|
||||
import os
|
||||
import hashlib
|
||||
from PIL import Image, ImageDraw, ImageFont, ImageOps
|
||||
|
||||
def get_file_hash(filename: str) -> str:
|
||||
"""Calcule le hash SHA-256 d'un fichier"""
|
||||
hash_sha256 = hashlib.sha256()
|
||||
with open(filename, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
hash_sha256.update(chunk)
|
||||
return hash_sha256.hexdigest()
|
||||
|
||||
def create_avatar_with_name(user_id, name, avatar_path, output_path):
|
||||
"""Crée une image combinant avatar rond et pseudo en dessous"""
|
||||
try:
|
||||
@ -81,48 +90,77 @@ def generate_tree(input_file, output_file, root_id=None):
|
||||
else:
|
||||
G.add_node(user_id, label=info["name"], **{**node_style, "fontcolor": "white"})
|
||||
|
||||
# 2. Identification des niveaux
|
||||
top_level = set()
|
||||
# 2. Calcul des générations avec la nouvelle logique
|
||||
generations = {}
|
||||
|
||||
# Ajout des racines explicites
|
||||
# a. Identifier les racines
|
||||
if root_id:
|
||||
top_level.add(root_id)
|
||||
root_members = [root_id]
|
||||
else:
|
||||
for root in data.get("roots", []):
|
||||
top_level.add(root)
|
||||
root_members = data.get("roots", [k for k,v in data["members"].items() if not v.get("parents")])
|
||||
|
||||
# Ajout des couples sans parents
|
||||
for couple in data.get("couples", []):
|
||||
if all(m in data["members"] and not data["members"][m].get("parents") for m in couple):
|
||||
top_level.update(couple)
|
||||
|
||||
# 3. Création des sous-graphes hiérarchiques
|
||||
if top_level:
|
||||
G.add_subgraph(top_level, name="rank_top", rank="same")
|
||||
|
||||
# Niveau des enfants directs
|
||||
children_level = set()
|
||||
for user_id, info in data["members"].items():
|
||||
parents = info.get("parents", [])
|
||||
if any(p["id"] in top_level for p in parents):
|
||||
children_level.add(user_id)
|
||||
# b. Première passe: membres sans parents = gen 0
|
||||
for user_id in data["members"]:
|
||||
if not data["members"][user_id].get("parents"):
|
||||
generations[user_id] = 0
|
||||
|
||||
if children_level:
|
||||
G.add_subgraph(children_level, name="rank_children", rank="same")
|
||||
|
||||
# 4. Gestion des couples
|
||||
# c. Deuxième passe: aligner les couples
|
||||
for couple in data.get("couples", []):
|
||||
if all(m in data["members"] for m in couple):
|
||||
member1, member2 = couple
|
||||
|
||||
# Lien conjugal
|
||||
G.add_edge(member1, member2, **couple_style)
|
||||
|
||||
# Alignement forcé pour les couples racines
|
||||
if member1 in top_level and member2 in top_level:
|
||||
G.add_subgraph(couple, name=f"couple_{member1}_{member2}", rank="same")
|
||||
m1, m2 = couple
|
||||
if m1 in generations and m2 in generations:
|
||||
gen = min(generations[m1], generations[m2])
|
||||
generations[m1] = gen
|
||||
generations[m2] = gen
|
||||
|
||||
# d. Troisième passe: calcul descendant
|
||||
changed = True
|
||||
while changed:
|
||||
changed = False
|
||||
for user_id in data["members"]:
|
||||
if user_id in generations:
|
||||
continue
|
||||
|
||||
parents = data["members"][user_id].get("parents", [])
|
||||
if parents:
|
||||
parent_gens = [generations[p["id"]] for p in parents if p["id"] in generations]
|
||||
if parent_gens:
|
||||
new_gen = min(parent_gens) + 1
|
||||
generations[user_id] = new_gen
|
||||
changed = True
|
||||
|
||||
# Aligner avec partenaire
|
||||
partner_id = next((c[0] if c[1]==user_id else c[1] for c in data.get("couples",[]) if user_id in c), None)
|
||||
if partner_id and partner_id in data["members"]:
|
||||
generations[partner_id] = new_gen
|
||||
|
||||
# 5. Liens parent-enfant
|
||||
# 3. Organisation des niveaux
|
||||
max_gen = max(generations.values()) if generations else 0
|
||||
|
||||
# Niveau 0: Uniquement les racines
|
||||
roots = [m for m in root_members if m in data["members"]]
|
||||
if roots:
|
||||
G.add_subgraph(roots, name="rank0", rank="same")
|
||||
|
||||
# Niveaux suivants
|
||||
for gen in range(1, max_gen + 1):
|
||||
members = [m for m,g in generations.items() if g == gen]
|
||||
|
||||
# Séparer les couples
|
||||
couples = []
|
||||
for couple in data.get("couples", []):
|
||||
if all(m in members for m in couple):
|
||||
couples.append(couple)
|
||||
members = [m for m in members if m not in couple]
|
||||
|
||||
# Créer les sous-graphes
|
||||
if members:
|
||||
G.add_subgraph(members, name=f"rank{gen}", rank="same")
|
||||
|
||||
for couple in couples:
|
||||
G.add_subgraph(couple, name=f"couple_{couple[0]}_{couple[1]}", rank="same")
|
||||
G.add_edge(couple[0], couple[1], **couple_style)
|
||||
|
||||
# 4. Liens parent-enfant
|
||||
for user_id, info in data["members"].items():
|
||||
for parent in info.get("parents", []):
|
||||
if parent["id"] in data["members"]:
|
||||
|
Reference in New Issue
Block a user