Ajout des sélection par chaines critique dans pda

This commit is contained in:
Fabrication du Numérique 2025-06-03 21:48:38 +02:00
parent 9ca623aef1
commit c55d478660
7 changed files with 116 additions and 45418 deletions

View File

@ -43,7 +43,13 @@ inverse_niveau_labels = {v: k for k, v in niveau_labels.items()}
def interface_plan_d_action(G_temp): def interface_plan_d_action(G_temp):
st.markdown(f"# {str(_('pages.plan_d_action.title'))}")
if "sel_prod" not in st.session_state:
st.session_state.sel_prod = None
if "sel_comp" not in st.session_state:
st.session_state.sel_comp = None
if "sel_miner" not in st.session_state:
st.session_state.sel_miner = None
if "plan_d_action" not in st.session_state: if "plan_d_action" not in st.session_state:
st.session_state["plan_d_action"] = 0 st.session_state["plan_d_action"] = 0
@ -55,6 +61,7 @@ def interface_plan_d_action(G_temp):
st.session_state["G_md"] = f"{JOBS}/{st.session_state["uuid"]}.md" st.session_state["G_md"] = f"{JOBS}/{st.session_state["uuid"]}.md"
if st.session_state["plan_d_action"] == 0: if st.session_state["plan_d_action"] == 0:
st.markdown(f"# {str(_('pages.plan_d_action.title'))}")
html_expander(f"{str(_('pages.plan_d_action.help'))}", content="\n".join(_("pages.plan_d_action.help_content")), open_by_default=False, details_class="details_introduction") html_expander(f"{str(_('pages.plan_d_action.help'))}", content="\n".join(_("pages.plan_d_action.help_content")), open_by_default=False, details_class="details_introduction")
# Préparation du graphe # Préparation du graphe
G_temp, niveaux_temp = preparer_graphe(G_temp) G_temp, niveaux_temp = preparer_graphe(G_temp)
@ -86,8 +93,8 @@ def interface_plan_d_action(G_temp):
st.session_state["plan_d_action"] = 1 st.session_state["plan_d_action"] = 1
st.rerun() # force la réexécution immédiatement avec état mis à jour st.rerun() # force la réexécution immédiatement avec état mis à jour
elif st.session_state["plan_d_action"] == 1: elif st.session_state["plan_d_action"] == 1:
st.markdown("")
# Traitement lourd une seule fois # Traitement lourd une seule fois
if not st.session_state["g_md_done"]: if not st.session_state["g_md_done"]:
write_dot(st.session_state["G_final"], st.session_state["G_dot"]) write_dot(st.session_state["G_final"], st.session_state["G_dot"])
@ -104,6 +111,9 @@ def interface_plan_d_action(G_temp):
if (st.button("Réinitialiser", icon=":material/refresh:")): if (st.button("Réinitialiser", icon=":material/refresh:")):
st.session_state["plan_d_action"] = 0 st.session_state["plan_d_action"] = 0
st.session_state["g_md_done"] = False st.session_state["g_md_done"] = False
st.session_state.sel_prod = None
st.session_state.sel_comp = None
st.session_state.sel_miner = None
for f in JOBS.glob(f"*{st.session_state["uuid"]}*"): for f in JOBS.glob(f"*{st.session_state["uuid"]}*"):
if f.is_file(): if f.is_file():
f.unlink() f.unlink()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -155,3 +155,11 @@ INDICATEURS = {
] ]
} }
} }
poids_operation = {
'Extraction': 1,
'Traitement': 1.5,
'Assemblage': 1.5,
'Fabrication': 2,
'Substitution': 2
}

View File

@ -3,7 +3,8 @@ import matplotlib.pyplot as plt
from app.plan_d_action.utils.data.config import ( from app.plan_d_action.utils.data.config import (
PRECONISATIONS, PRECONISATIONS,
INDICATEURS INDICATEURS,
poids_operation
) )
from app.plan_d_action.utils.data.data_processing import parse_chains_md from app.plan_d_action.utils.data.data_processing import parse_chains_md
from app.plan_d_action.utils.data.data_utils import ( from app.plan_d_action.utils.data.data_utils import (
@ -17,38 +18,7 @@ from app.plan_d_action.utils.data.pda_interface import (
) )
from app.plan_d_action.utils.data.data_utils import initialiser_seuils from app.plan_d_action.utils.data.data_utils import initialiser_seuils
def tableau_de_bord(chains, produits, composants, mineraux, seuils): def calcul_poids_chaine(poids_A, poids_F, poids_T, poids_E, poids_M):
col_left, col_right = st.columns([1, 1], gap="small", border=True)
with col_left:
st.markdown("**<u>Panneau de sélection</u>**", unsafe_allow_html=True)
produits_disponibles = sorted({c["produit"] for c in chains})
sel_prod = st.selectbox("Produit", produits_disponibles)
composants_dispo = sorted({c["composant"] for c in chains if c["produit"] == sel_prod})
sel_comp = st.selectbox("Composant", composants_dispo)
mineraux_dispo = sorted({c["minerai"] for c in chains if c["produit"] == sel_prod and c["composant"] == sel_comp})
sel_miner = st.selectbox("Minerai", mineraux_dispo)
with col_right:
st.markdown("**<u>Synthèse des criticités</u>**", unsafe_allow_html=True)
poids_A, couleur_A, couleur_A_ihh, couleur_A_isg = set_vulnerability(produits[sel_prod]["IHH_Assemblage"], produits[sel_prod]["ISG_Assemblage"], "IHH", "ISG", seuils)
poids_F, couleur_F, couleur_F_ihh, couleur_F_isg = set_vulnerability(composants[sel_comp]["IHH_Fabrication"], composants[sel_comp]["ISG_Fabrication"], "IHH", "ISG", seuils)
poids_T, couleur_T, couleur_T_ihh, couleur_T_isg = set_vulnerability(mineraux[sel_miner]["IHH_Traitement"], mineraux[sel_miner]["ISG_Traitement"], "IHH", "ISG", seuils)
poids_E, couleur_E, couleur_E_ihh, couleur_E_isg = set_vulnerability(mineraux[sel_miner]["IHH_Extraction"], mineraux[sel_miner]["ISG_Extraction"], "IHH", "ISG", seuils)
poids_M, couleur_M, couleur_M_ics, couleur_M_ivc = set_vulnerability(mineraux[sel_miner]["ICS"], mineraux[sel_miner]["IVC"], "ICS", "IVC", seuils)
st.markdown(f"* **{sel_prod} - Assemblage** : {colorer_couleurs(couleur_A)} ({poids_A})")
st.markdown(f"* **{sel_comp} - Fabrication** : {colorer_couleurs(couleur_F)} ({poids_F})")
st.markdown(f"* **{sel_miner} - Traitement** : {colorer_couleurs(couleur_T)} ({poids_T})")
st.markdown(f"* **{sel_miner} - Extraction** : {colorer_couleurs(couleur_E)} ({poids_E})")
st.markdown(f"* **{sel_miner} - Minerai** : {colorer_couleurs(couleur_M)} ({poids_M})")
poids_operation = {
'Extraction': 1,
'Traitement': 1.5,
'Assemblage': 1.5,
'Fabrication': 2,
'Substitution': 2
}
poids_total = (\ poids_total = (\
poids_A * poids_operation["Assemblage"] + \ poids_A * poids_operation["Assemblage"] + \
poids_F * poids_operation["Fabrication"] + \ poids_F * poids_operation["Fabrication"] + \
@ -67,6 +37,91 @@ def tableau_de_bord(chains, produits, composants, mineraux, seuils):
criticite_chaine = "Critique" criticite_chaine = "Critique"
niveau_criticite = {"Facile", "Modérée", "Difficile"} niveau_criticite = {"Facile", "Modérée", "Difficile"}
return criticite_chaine, niveau_criticite, poids_total
def analyser_chaines(chaines, produits, composants, mineraux, seuils, top_n=None):
resultats = []
for chaine in chaines:
sel_prod = chaine["produit"]
sel_comp = chaine["composant"]
sel_miner = chaine["minerai"]
poids_A, *_ = set_vulnerability(produits[sel_prod]["IHH_Assemblage"], produits[sel_prod]["ISG_Assemblage"], "IHH", "ISG", seuils)
poids_F, *_ = set_vulnerability(composants[sel_comp]["IHH_Fabrication"], composants[sel_comp]["ISG_Fabrication"], "IHH", "ISG", seuils)
poids_T, *_ = set_vulnerability(mineraux[sel_miner]["IHH_Traitement"], mineraux[sel_miner]["ISG_Traitement"], "IHH", "ISG", seuils)
poids_E, *_ = set_vulnerability(mineraux[sel_miner]["IHH_Extraction"], mineraux[sel_miner]["ISG_Extraction"], "IHH", "ISG", seuils)
poids_M, *_ = set_vulnerability(mineraux[sel_miner]["ICS"], mineraux[sel_miner]["IVC"], "ICS", "IVC", seuils)
criticite_chaine, niveau_criticite, poids_total = calcul_poids_chaine(
poids_A, poids_F, poids_T, poids_E, poids_M
)
resultats.append({
"chaine": chaine,
"criticite_chaine": criticite_chaine,
"niveau_criticite": niveau_criticite,
"poids_total": poids_total
})
# Tri décroissant
resultats.sort(key=lambda x: x["poids_total"], reverse=True)
# Si top_n n'est pas spécifié, tout est retourné
if top_n is None or top_n >= len(resultats):
return resultats
# Déterminer le seuil de coupure
seuil_poids = resultats[top_n - 1]["poids_total"]
# Inclure tous ceux dont le poids est égal au seuil
top_resultats = [r for r in resultats if r["poids_total"] >= seuil_poids]
return top_resultats
def tableau_de_bord(chains, produits, composants, mineraux, seuils):
col_left, col_right = st.columns([2, 3], gap="small", border=True)
with col_left:
st.markdown("**<u>Panneau de sélection</u>**", unsafe_allow_html=True)
produits_disponibles = sorted({c["produit"] for c in chains})
sel_prod = st.selectbox("Produit", produits_disponibles, index=produits_disponibles.index(st.session_state.sel_prod) if st.session_state.sel_prod else 0)
composants_dispo = sorted({c["composant"] for c in chains if c["produit"] == sel_prod})
sel_comp = st.selectbox("Composant", composants_dispo, index=composants_dispo.index(st.session_state.sel_comp) if st.session_state.sel_comp else 0)
mineraux_dispo = sorted({c["minerai"] for c in chains if c["produit"] == sel_prod and c["composant"] == sel_comp})
sel_miner = st.selectbox("Minerai", mineraux_dispo, index=mineraux_dispo.index(st.session_state.sel_miner) if st.session_state.sel_miner else 0)
with col_right:
top_chains = analyser_chaines(chains, produits, composants, mineraux, seuils, top_n=5)
st.markdown("**<u>Top chaînes critiques pour sélection rapide</u>**", unsafe_allow_html=True)
for i, entry in enumerate(top_chains):
ch = entry["chaine"]
poids = entry["poids_total"]
criticite = entry["criticite_chaine"]
if st.button(f"**{ch['produit']} <-> {ch['composant']} <-> {ch['minerai']}** : {poids:.2f}{criticite}", key=f"select_{i}"):
st.session_state.sel_prod = ch["produit"]
st.session_state.sel_comp = ch["composant"]
st.session_state.sel_miner = ch["minerai"]
st.rerun()
c1, c2 = st.columns([3, 2], gap="small", border=True, vertical_alignment='center')
with c1:
st.markdown("**<u>Synthèse des criticités</u>**", unsafe_allow_html=True)
poids_A, couleur_A, couleur_A_ihh, couleur_A_isg = set_vulnerability(produits[sel_prod]["IHH_Assemblage"], produits[sel_prod]["ISG_Assemblage"], "IHH", "ISG", seuils)
poids_F, couleur_F, couleur_F_ihh, couleur_F_isg = set_vulnerability(composants[sel_comp]["IHH_Fabrication"], composants[sel_comp]["ISG_Fabrication"], "IHH", "ISG", seuils)
poids_T, couleur_T, couleur_T_ihh, couleur_T_isg = set_vulnerability(mineraux[sel_miner]["IHH_Traitement"], mineraux[sel_miner]["ISG_Traitement"], "IHH", "ISG", seuils)
poids_E, couleur_E, couleur_E_ihh, couleur_E_isg = set_vulnerability(mineraux[sel_miner]["IHH_Extraction"], mineraux[sel_miner]["ISG_Extraction"], "IHH", "ISG", seuils)
poids_M, couleur_M, couleur_M_ics, couleur_M_ivc = set_vulnerability(mineraux[sel_miner]["ICS"], mineraux[sel_miner]["IVC"], "ICS", "IVC", seuils)
st.markdown(f"* **{sel_prod} - Assemblage** : {colorer_couleurs(couleur_A)} ({poids_A})")
st.markdown(f"* **{sel_comp} - Fabrication** : {colorer_couleurs(couleur_F)} ({poids_F})")
st.markdown(f"* **{sel_miner} - Traitement** : {colorer_couleurs(couleur_T)} ({poids_T})")
st.markdown(f"* **{sel_miner} - Extraction** : {colorer_couleurs(couleur_E)} ({poids_E})")
st.markdown(f"* **{sel_miner} - Minerai** : {colorer_couleurs(couleur_M)} ({poids_M})")
criticite_chaine, niveau_criticite, poids_total = calcul_poids_chaine(poids_A, poids_F, poids_T, poids_E, poids_M)
with c2:
st.error(f"**Criticité globale : {criticite_chaine} ({poids_total})**") st.error(f"**Criticité globale : {criticite_chaine} ({poids_total})**")
return ( return (
@ -82,11 +137,11 @@ def afficher_criticites(produits, composants, mineraux, sel_prod, sel_comp, sel_
col_left, col_right = st.columns([1, 1], gap="small", border=True) col_left, col_right = st.columns([1, 1], gap="small", border=True)
with col_left: with col_left:
fig1, ax1 = plt.subplots(figsize=(1, 1)) fig1, ax1 = plt.subplots(figsize=(2, 2.4))
ax1.scatter([produits[sel_prod]["ISG_Assemblage"]], [produits[sel_prod]["IHH_Assemblage"]], label="Assemblage".ljust(20), s=5) ax1.scatter([produits[sel_prod]["ISG_Assemblage"]], [produits[sel_prod]["IHH_Assemblage"]], label="Assemblage", s=5)
ax1.scatter([composants[sel_comp]["ISG_Fabrication"]], [composants[sel_comp]["IHH_Fabrication"]], label="Fabrication".ljust(20), s=5) ax1.scatter([composants[sel_comp]["ISG_Fabrication"]], [composants[sel_comp]["IHH_Fabrication"]], label="Fabrication", s=5)
ax1.scatter([mineraux[sel_miner]["ISG_Extraction"]], [mineraux[sel_miner]["IHH_Extraction"]], label="Extraction".ljust(20), s=5) ax1.scatter([mineraux[sel_miner]["ISG_Extraction"]], [mineraux[sel_miner]["IHH_Extraction"]], label="Extraction", s=5)
ax1.scatter([mineraux[sel_miner]["ISG_Traitement"]], [mineraux[sel_miner]["IHH_Traitement"]], label="Traitement".ljust(20), s=5) ax1.scatter([mineraux[sel_miner]["ISG_Traitement"]], [mineraux[sel_miner]["IHH_Traitement"]], label="Traitement", s=5)
# Seuils ISG (vertical) # Seuils ISG (vertical)
ax1.axvline(seuils["ISG"]["vert"]["max"], linestyle='--', color='green', alpha=0.7, linewidth=0.5) # Seuil vert-orange ax1.axvline(seuils["ISG"]["vert"]["max"], linestyle='--', color='green', alpha=0.7, linewidth=0.5) # Seuil vert-orange
@ -101,13 +156,13 @@ def afficher_criticites(produits, composants, mineraux, sel_prod, sel_comp, sel_
ax1.set_xlabel("ISG", fontsize=4) ax1.set_xlabel("ISG", fontsize=4)
ax1.set_ylabel("IHH", fontsize=4) ax1.set_ylabel("IHH", fontsize=4)
ax1.tick_params(axis='both', which='major', labelsize=4) ax1.tick_params(axis='both', which='major', labelsize=4)
ax1.legend(bbox_to_anchor=(1.05, 1), loc='upper left', fontsize=4) ax1.legend(bbox_to_anchor=(0.5, -0.25), loc='upper center', fontsize=4)
plt.tight_layout() plt.tight_layout()
st.pyplot(fig1) st.pyplot(fig1)
with col_right: with col_right:
fig2, ax2 = plt.subplots(figsize=(1, 1)) fig2, ax2 = plt.subplots(figsize=(2, 2.1))
ax2.scatter([mineraux[sel_miner]["IVC"]], [mineraux[sel_miner]["ICS"]], color='green', s=5, label=sel_miner.ljust(20)) ax2.scatter([mineraux[sel_miner]["IVC"]], [mineraux[sel_miner]["ICS"]], color='green', s=5, label=sel_miner)
# Seuils IVC (vertical) # Seuils IVC (vertical)
ax2.axvline(seuils["IVC"]["vert"]["max"], linestyle='--', color='green', alpha=0.7, linewidth=0.5) # Seuil vert-orange ax2.axvline(seuils["IVC"]["vert"]["max"], linestyle='--', color='green', alpha=0.7, linewidth=0.5) # Seuil vert-orange
@ -122,7 +177,7 @@ def afficher_criticites(produits, composants, mineraux, sel_prod, sel_comp, sel_
ax2.set_xlabel("IVC", fontsize=4) ax2.set_xlabel("IVC", fontsize=4)
ax2.set_ylabel("ICS", fontsize=4) ax2.set_ylabel("ICS", fontsize=4)
ax2.tick_params(axis='both', which='major', labelsize=4) ax2.tick_params(axis='both', which='major', labelsize=4)
ax2.legend(bbox_to_anchor=(1.05, 1), loc='upper left', fontsize=4) ax2.legend(bbox_to_anchor=(0.5, -0.25), loc='upper center', fontsize=4)
plt.tight_layout() plt.tight_layout()
st.pyplot(fig2) st.pyplot(fig2)
@ -269,6 +324,7 @@ def afficher_details_operations(produits, composants, mineraux, sel_prod, sel_co
afficher_caracteristiques_minerai(sel_miner, mineraux[sel_miner], minerai_general) afficher_caracteristiques_minerai(sel_miner, mineraux[sel_miner], minerai_general)
def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml"): def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml"):
produits, composants, mineraux, chains, descriptions, details_sections = parse_chains_md(filepath) produits, composants, mineraux, chains, descriptions, details_sections = parse_chains_md(filepath)
if not chains: if not chains:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff