2025-06-05 09:28:49 +02:00

241 lines
9.6 KiB
Python

from typing import List, Dict, Optional, Any
import networkx as nx
import streamlit as st
import altair as alt
import numpy as np
from collections import Counter
import pandas as pd
from utils.translations import _
def afficher_graphique_altair(df: pd.DataFrame) -> None:
"""
Affiche un graphique Altair pour les données d'IHH.
Args:
df (pd.DataFrame): DataFrame contenant les données de IHH.
Notes:
Cette fonction crée un graphique interactif pour visualiser les
données d'IHH selon différentes catégories et niveaux de gravité.
"""
# Définir les catégories originales (en français) et leur ordre
categories_fr = ["Assemblage", "Fabrication", "Traitement", "Extraction"]
# Créer un dictionnaire de mappage entre les catégories originales et leurs traductions
mappage_categories = {
"Assemblage": str(_("pages.visualisations.categories.assembly")),
"Fabrication": str(_("pages.visualisations.categories.manufacturing")),
"Traitement": str(_("pages.visualisations.categories.processing")),
"Extraction": str(_("pages.visualisations.categories.extraction"))
}
# Filtrer les catégories qui existent dans les données
categories_fr_filtrees = [cat for cat in categories_fr if cat in df['categorie'].unique()]
# Parcourir les catégories dans l'ordre défini
for cat_fr in categories_fr_filtrees:
# Obtenir le nom traduit de la catégorie pour l'affichage
cat_traduit = mappage_categories[cat_fr]
st.markdown(f"### {cat_traduit}")
# Mais filtrer sur le nom original dans les données
df_cat = df[df['categorie'] == cat_fr].copy()
coord_pairs = list(zip(df_cat['ihh_pays'].round(1), df_cat['ihh_acteurs'].round(1)))
counts = Counter(coord_pairs)
offset_x = []
offset_y = {}
seen = Counter()
for pair in coord_pairs:
rank = seen[pair]
seen[pair] += 1
if counts[pair] > 1:
angle = rank * 1.5
radius = 0.8 + 0.4 * rank
offset_x.append(radius * np.cos(angle))
offset_y[pair] = radius * np.sin(angle)
else:
offset_x.append(0)
offset_y[pair] = 0
df_cat['ihh_pays'] += offset_x
df_cat['ihh_acteurs'] += [offset_y[p] for p in coord_pairs]
df_cat['ihh_pays_text'] = df_cat['ihh_pays'] + 0.5
df_cat['ihh_acteurs_text'] = df_cat['ihh_acteurs'] + 0.5
base = alt.Chart(df_cat).encode(
x=alt.X('ihh_pays:Q', title=str(_("pages.visualisations.axis_titles.ihh_countries"))),
y=alt.Y('ihh_acteurs:Q', title=str(_("pages.visualisations.axis_titles.ihh_actors"))),
size=alt.Size('ics_cat:Q', scale=alt.Scale(domain=[1, 2, 3], range=[50, 500, 1000]), legend=None),
color=alt.Color('ics_cat:N', scale=alt.Scale(domain=[1, 2, 3], range=['darkgreen', 'orange', 'darkred']))
)
points = base.mark_circle(opacity=0.6)
lines = alt.Chart(df_cat).mark_rule(strokeWidth=0.5, color='gray').encode(
x='ihh_pays:Q', x2='ihh_pays_text:Q',
y='ihh_acteurs:Q', y2='ihh_acteurs_text:Q'
)
labels = alt.Chart(df_cat).mark_text(
align='left', dx=3, dy=-3, fontSize=8, font='Arial', angle=335
).encode(
x='ihh_pays_text:Q',
y='ihh_acteurs_text:Q',
text='nom:N'
)
hline_15 = alt.Chart(df_cat).mark_rule(strokeDash=[2,2], color='green').encode(y=alt.datum(15))
hline_25 = alt.Chart(df_cat).mark_rule(strokeDash=[2,2], color='red').encode(y=alt.datum(25))
hline_100 = alt.Chart(df_cat).mark_rule(strokeDash=[2,2], color='white').encode(y=alt.datum(100))
vline_15 = alt.Chart(df_cat).mark_rule(strokeDash=[2,2], color='green').encode(x=alt.datum(15))
vline_25 = alt.Chart(df_cat).mark_rule(strokeDash=[2,2], color='red').encode(x=alt.datum(25))
vline_100 = alt.Chart(df_cat).mark_rule(strokeDash=[2,2], color='white').encode(x=alt.datum(100))
chart = (points + lines + labels + hline_15 + hline_25 + hline_100 + vline_15 + vline_25 + vline_100).properties(
width=500,
height=400,
title=str(_("pages.visualisations.chart_titles.concentration_criticality")).format(cat_traduit)
).interactive()
st.altair_chart(chart, use_container_width=True)
def creer_graphes(donnees: Optional[List[Dict[str, Any]]]) -> None:
"""
Crée un graphique Altair pour les données d'IVC.
Args:
donnees (Optional[List[Dict[str, Any]]]): Liste des données d'IVC.
Returns:
None.
Notes:
Cette fonction traite les données d'IVC et crée un graphique
interactif pour visualiser la concentration des ressources.
"""
if not donnees:
st.warning(str(_("pages.visualisations.no_data")))
return
try:
df = pd.DataFrame(donnees)
df['ivc_cat'] = df['ivc'].apply(lambda x: 1 if x <= 15 else (2 if x <= 30 else 3))
from collections import Counter
coord_pairs = list(zip(df['ihh_extraction'].round(1), df['ihh_reserves'].round(1)))
counts = Counter(coord_pairs)
offset_x, offset_y = [], {}
seen = Counter()
for pair in coord_pairs:
rank = seen[pair]
seen[pair] += 1
if counts[pair] > 1:
angle = rank * 1.5
radius = 0.8 + 0.4 * rank
offset_x.append(radius * np.cos(angle))
offset_y[pair] = radius * np.sin(angle)
else:
offset_x.append(0)
offset_y[pair] = 0
df['ihh_extraction'] += offset_x
df['ihh_reserves'] += [offset_y[p] for p in coord_pairs]
df['ihh_extraction_text'] = df['ihh_extraction'] + 0.5
df['ihh_reserves_text'] = df['ihh_reserves'] + 0.5
base = alt.Chart(df).encode(
x=alt.X('ihh_extraction:Q', title=str(_("pages.visualisations.axis_titles.ihh_extraction"))),
y=alt.Y('ihh_reserves:Q', title=str(_("pages.visualisations.axis_titles.ihh_reserves"))),
size=alt.Size('ivc_cat:Q', scale=alt.Scale(domain=[1, 2, 3], range=[50, 500, 1000]), legend=None),
color=alt.Color('ivc_cat:N', scale=alt.Scale(domain=[1, 2, 3], range=['darkgreen', 'orange', 'darkred'])),
tooltip=['nom:N', 'ivc:Q', 'ihh_extraction:Q', 'ihh_reserves:Q']
)
points = base.mark_circle(opacity=0.6)
lines = alt.Chart(df).mark_rule(strokeWidth=0.5, color='gray').encode(
x='ihh_extraction:Q', x2='ihh_extraction_text:Q',
y='ihh_reserves:Q', y2='ihh_reserves_text:Q'
)
labels = alt.Chart(df).mark_text(
align='left', dx=10, dy=-10, fontSize=10, font='Arial', angle=335
).encode(
x='ihh_extraction_text:Q',
y='ihh_reserves_text:Q',
text='nom:N'
)
hline_15 = alt.Chart(df).mark_rule(strokeDash=[2,2], color='green').encode(y=alt.datum(15))
hline_25 = alt.Chart(df).mark_rule(strokeDash=[2,2], color='red').encode(y=alt.datum(25))
hline_100 = alt.Chart(df).mark_rule(strokeDash=[2,2], color='red').encode(y=alt.datum(100))
vline_15 = alt.Chart(df).mark_rule(strokeDash=[2,2], color='green').encode(x=alt.datum(15))
vline_25 = alt.Chart(df).mark_rule(strokeDash=[2,2], color='red').encode(x=alt.datum(25))
vline_100 = alt.Chart(df).mark_rule(strokeDash=[2,2], color='red').encode(x=alt.datum(100))
chart = (points + lines + labels + hline_15 + hline_25 + hline_100 + vline_15 + vline_25 + vline_100).properties(
width=600,
height=500,
title=str(_("pages.visualisations.chart_titles.concentration_resources"))
).interactive()
st.altair_chart(chart, use_container_width=True)
except Exception as e:
st.error(f"{str(_('errors.graph_creation_error'))} {e}")
def lancer_visualisation_ihh_ics(graph: nx.DiGraph) -> None:
"""
Lance une visualisation Altair pour les données d'IHH critique.
Args:
graph (nx.DiGraph): Le graphe NetworkX contenant les données de IHH.
Notes:
Cette fonction traite le graphe et crée un graphique Altair
pour visualiser les données d'IHH critique.
"""
try:
import networkx as nx
from utils.graph_utils import recuperer_donnees
niveaux = nx.get_node_attributes(graph, "niveau")
noeuds = [n for n, v in niveaux.items() if v == "10" and "Reserves" not in n]
noeuds.sort()
df = recuperer_donnees(graph, noeuds)
if df.empty:
st.warning(str(_("pages.visualisations.no_data")))
else:
afficher_graphique_altair(df)
except Exception as e:
st.error(f"{str(_('errors.ihh_criticality_error'))} {e}")
def lancer_visualisation_ihh_ivc(graph: nx.DiGraph) -> None:
"""
Lance une visualisation Altair pour les données d'IVC.
Args:
graph (Annx.Graphy): Le graphe NetworkX contenant les données de IV C.
Notes:
Cette fonction traite le graphe et crée un graphique Altair
pour visualiser les données d'IV C.
"""
try:
from utils.graph_utils import recuperer_donnees_2
noeuds_niveau_2 = [
n for n, data in graph.nodes(data=True)
if data.get("niveau") == "2" and "ivc" in data
]
if not noeuds_niveau_2:
return
data = recuperer_donnees_2(graph, noeuds_niveau_2)
creer_graphes(data)
except Exception as e:
st.error(f"{str(_('errors.ihh_ivc_error'))} {e}")