Code/app/visualisations/graphes.py
2025-05-13 16:31:53 +02:00

196 lines
8.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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):
# 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", "Assemblage")),
"Fabrication": str(_("pages.visualisations.categories.manufacturing", "Fabrication")),
"Traitement": str(_("pages.visualisations.categories.processing", "Traitement")),
"Extraction": str(_("pages.visualisations.categories.extraction", "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", "IHH Pays (%)"))),
y=alt.Y('ihh_acteurs:Q', title=str(_("pages.visualisations.axis_titles.ihh_actors", "IHH Acteurs (%)"))),
size=alt.Size('criticite_cat:Q', scale=alt.Scale(domain=[1, 2, 3], range=[50, 500, 1000]), legend=None),
color=alt.Color('criticite_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", "Concentration et criticité {0}")).format(cat_traduit)
).interactive()
st.altair_chart(chart, use_container_width=True)
def creer_graphes(donnees):
if not donnees:
st.warning(str(_("pages.visualisations.no_data", "Aucune donnée à afficher.")))
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", "IHH Extraction (%)"))),
y=alt.Y('ihh_reserves:Q', title=str(_("pages.visualisations.axis_titles.ihh_reserves", "IHH Réserves (%)"))),
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", "Concentration des ressources critiques vs vulnérabilité IVC"))
).interactive()
st.altair_chart(chart, use_container_width=True)
except Exception as e:
st.error(f"{str(_('errors.graph_creation_error', 'Erreur lors de la création du graphique :'))} {e}")
def lancer_visualisation_ihh_criticite(graph):
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", "Aucune donnée à visualiser.")))
else:
afficher_graphique_altair(df)
except Exception as e:
st.error(f"{str(_('errors.ihh_criticality_error', 'Erreur dans la visualisation IHH vs Criticité :'))} {e}")
def lancer_visualisation_ihh_ivc(graph):
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', 'Erreur dans la visualisation IHH vs IVC :'))} {e}")