+""", unsafe_allow_html=True) + def recuperer_date_dernier_commit_schema(): headers = {"Authorization": f"token " + GITEA_TOKEN} url = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/commits?path=schema.txt&sha={ENV}" @@ -346,15 +420,14 @@ def afficher_sankey( G, niveau_depart, niveau_arrivee, noeuds_depart=None, noeuds_arrivee=None, - filtrer_criticite=False, filtrer_ivc=False, filtrer_ihh=False, - filtrer_isg=False, - logique_filtrage="OU" -): + minerais=None, + filtrer_criticite=False, filtrer_ivc=False, + filtrer_ihh=False, filtrer_isg=False, + logique_filtrage="OU"): niveaux = {} for node, attrs in G.nodes(data=True): - # Conversion du niveau niveau_str = attrs.get("niveau") try: if niveau_str: @@ -362,28 +435,12 @@ def afficher_sankey( except ValueError: logging.warning(f"Niveau non entier pour le noeud {node}: {niveau_str}") - # Suppression des attributs indésirables - ATTRIBUTS_SUPPRIMES = {"fillcolor", "fontcolor", "style", "fontsize"} - for attr in ATTRIBUTS_SUPPRIMES: - attrs.pop(attr, None) - - # Réordonner : label d'abord - if "label" in attrs: - reordered = OrderedDict() - reordered["label"] = attrs["label"] - for k, v in attrs.items(): - if k != "label": - reordered[k] = v - G.nodes[node].clear() - G.nodes[node].update(reordered) - chemins = [] if noeuds_depart and noeuds_arrivee: for nd in noeuds_depart: for na in noeuds_arrivee: tous_chemins = extraire_chemins_depuis(G, nd) - chemins.extend( - [chemin for chemin in tous_chemins if na in chemin]) + chemins.extend([chemin for chemin in tous_chemins if na in chemin]) elif noeuds_depart: for nd in noeuds_depart: chemins.extend(extraire_chemins_depuis(G, nd)) @@ -391,59 +448,60 @@ def afficher_sankey( for na in noeuds_arrivee: chemins.extend(extraire_chemins_vers(G, na, niveau_depart)) else: - sources_depart = [n for n in G.nodes() if niveaux.get(n) - == niveau_depart] + sources_depart = [n for n in G.nodes() if niveaux.get(n) == niveau_depart] for nd in sources_depart: chemins.extend(extraire_chemins_depuis(G, nd)) + if minerais: + chemins = [chemin for chemin in chemins if any(n in minerais for n in chemin)] + def extraire_criticite(u, v): data = G.get_edge_data(u, v) if not data: return 0 if isinstance(data, dict) and all(isinstance(k, int) for k in data): - try: - return float(data[0].get("criticite", 0)) - except: - return 0 + return float(data[0].get("criticite", 0)) return float(data.get("criticite", 0)) liens_chemins = set() chemins_filtres = set() - for chemin in chemins: - has_ihh = False - has_ivc = False - has_criticite = False - has_isg_critique = False + niveaux_speciaux = [1001] + + for chemin in chemins: + has_ihh = has_ivc = has_criticite = has_isg_critique = False + + for i in range(len(chemin) - 1): + u, v = chemin[i], chemin[i + 1] + niveau_u = niveaux.get(u) + niveau_v = niveaux.get(v) + + if ( + (niveau_depart <= niveau_u <= niveau_arrivee or niveau_u in niveaux_speciaux) + and (niveau_depart <= niveau_v <= niveau_arrivee or niveau_v in niveaux_speciaux) + ): + liens_chemins.add((u, v)) + + if filtrer_ihh and ihh_type: + ihh_field = "ihh_pays" if ihh_type == "Pays" else "ihh_acteurs" + if niveau_u == 10 and int(G.nodes[u].get(ihh_field, 0)) > 25: + has_ihh = True + if niveau_v == 10 and int(G.nodes[v].get(ihh_field, 0)) > 25: + has_ihh = True + + if filtrer_ivc and niveau_u == 2 and int(G.nodes[u].get("ivc", 0)) > 30: + has_ivc = True + + if filtrer_criticite and niveau_u == 1 and niveau_v == 2 and extraire_criticite(u, v) > 0.66: + has_criticite = True - for i in range(len(chemin)-1): - u, v = chemin[i], chemin[i+1] - if niveaux.get(u) is not None and niveaux.get(v) is not None: - if niveau_depart <= niveaux.get(u) <= niveau_arrivee and niveau_depart <= niveaux.get(v) <= niveau_arrivee: - liens_chemins.add((u, v)) - # vérification des conditions critiques - if filtrer_ihh: - if filtrer_ihh and ihh_type: - ihh_field = "ihh_pays" if ihh_type == "Pays" else "ihh_acteurs" - if niveaux.get(u) == 10 and G.nodes[u].get(ihh_field) and int(G.nodes[u][ihh_field]) > 25: - has_ihh = True - elif niveaux.get(v) == 10 and G.nodes[v].get(ihh_field) and int(G.nodes[v][ihh_field]) > 25: - has_ihh = True - if filtrer_ivc and niveaux.get(u) == 2 and G.nodes[u].get("ivc") and int(G.nodes[u]["ivc"]) > 30: - has_ivc = True - if filtrer_criticite and niveaux.get(u) == 1 and niveaux.get(v) == 2 and extraire_criticite(u, v) > 0.66: - has_criticite = True - # Vérifie présence d'un isg >= 60 for n in (u, v): - if niveaux.get(n) == 99: - isg = int(G.nodes[n].get("isg", 0)) - if isg >= 60: - has_isg_critique = True + if niveaux.get(n) == 99 and int(G.nodes[n].get("isg", 0)) >= 60: + has_isg_critique = True elif niveaux.get(n) in (11, 12): for succ in G.successors(n): if niveaux.get(succ) == 99 and int(G.nodes[succ].get("isg", 0)) >= 60: has_isg_critique = True - if logique_filtrage == "ET": keep = True if filtrer_ihh: @@ -457,10 +515,7 @@ def afficher_sankey( if keep: chemins_filtres.add(tuple(chemin)) elif logique_filtrage == "OU": - if (filtrer_ihh and has_ihh) or \ - (filtrer_ivc and has_ivc) or \ - (filtrer_criticite and has_criticite) or \ - (filtrer_isg and has_isg_critique): + if (filtrer_ihh and has_ihh) or (filtrer_ivc and has_ivc) or (filtrer_criticite and has_criticite) or (filtrer_isg and has_isg_critique): chemins_filtres.add(tuple(chemin)) if any([filtrer_criticite, filtrer_ivc, filtrer_ihh, filtrer_isg]): @@ -469,7 +524,12 @@ def afficher_sankey( for chemin in chemins: for i in range(len(chemin) - 1): u, v = chemin[i], chemin[i + 1] - if niveau_depart <= niveaux.get(u, 999) <= niveau_arrivee and niveau_depart <= niveaux.get(v, 999) <= niveau_arrivee: + niveau_u = niveaux.get(u, 999) + niveau_v = niveaux.get(v, 999) + if ( + (niveau_depart <= niveau_u <= niveau_arrivee or niveau_u in niveaux_speciaux) + and (niveau_depart <= niveau_v <= niveau_arrivee or niveau_v in niveaux_speciaux) + ): liens_chemins.add((u, v)) if not liens_chemins: @@ -488,7 +548,6 @@ def afficher_sankey( noeuds_utilises = set(df_liens["source"]) | set(df_liens["target"]) sorted_nodes = [n for n in sorted(G.nodes(), key=lambda x: niveaux.get(x, 99), reverse=True) if n in noeuds_utilises] - def couleur_criticite(p): if p <= 0.33: return "darkgreen" @@ -498,8 +557,7 @@ def afficher_sankey( return "darkred" df_liens["color"] = df_liens.apply( - lambda row: couleur_criticite(row["criticite"]) if niveaux.get( - row["source"]) == 1 and niveaux.get(row["target"]) == 2 else "gray", + lambda row: couleur_criticite(row["criticite"]) if row["criticite"] > 0 else "gray", axis=1 ) @@ -568,6 +626,32 @@ def afficher_sankey( ) st.plotly_chart(fig) + if st.session_state.get("logged_in", False): + if liens_chemins: + G_export = nx.DiGraph() + for u, v in liens_chemins: + G_export.add_node(u, **G.nodes[u]) + G_export.add_node(v, **G.nodes[v]) + data = G.get_edge_data(u, v) + if isinstance(data, dict) and all(isinstance(k, int) for k in data): + G_export.add_edge(u, v, **data[0]) + elif isinstance(data, dict): + G_export.add_edge(u, v, **data) + else: + G_export.add_edge(u, v) + + with tempfile.NamedTemporaryFile(delete=False, suffix=".dot", mode="w", encoding="utf-8") as f: + write_dot(G_export, f.name) + dot_path = f.name + + with open(dot_path, encoding="utf-8") as f: + st.download_button( + label="Télécharger le fichier DOT filtré", + data=f.read(), + file_name="graphe_filtré.dot", + mime="text/plain" + ) + def creer_graphes(donnees): if not donnees: st.warning("Aucune donnée à afficher.") @@ -744,231 +828,395 @@ def afficher_fiches(): except Exception as e: st.error(f"Erreur lors du chargement de la fiche : {e}") -def afficher_fiches_old(): - import streamlit as st - from pathlib import Path +def lancer_personnalisation(G): + """ + Affiche et modifie uniquement les produits finaux personnalisables (ceux ajoutés) + et permet d'ajouter de nouveaux produits finaux. + Permet aussi d'importer et d'exporter la configuration personnalisée. - base_path = Path("Fiches") - if not base_path.exists(): - st.warning("Le dossier 'Fiches' est introuvable.") - return - - dossiers = sorted([p for p in base_path.iterdir() if p.is_dir() and 'Criticités' not in p.name]) - criticite_path = next((p for p in base_path.iterdir() if p.is_dir() and 'Criticités' in p.name), None) - if criticite_path: - dossiers.append(criticite_path) - - noms_dossiers = [d.name for d in dossiers] - - dossier_choisi = st.selectbox("📁 Dossiers disponibles", noms_dossiers) - chemin_dossier = base_path / dossier_choisi - fichiers_md = sorted(chemin_dossier.glob("*.md")) - noms_fichiers = [] - fichiers_dict = {} - for f in fichiers_md: - try: - with f.open(encoding="utf-8") as md: - titre = md.readline().strip() - if ':' in titre: - titre = titre.split(':', 1)[1].strip() - else: - titre = f.stem - fichiers_dict[titre] = f.name - noms_fichiers.append(titre) - except Exception as e: - st.error(f"Erreur lecture fichier {f.name} : {e}") - - noms_fichiers.sort() - fiche_label = st.selectbox("🗂️ Fiches Markdown", noms_fichiers) - fichier_choisi = fichiers_dict[fiche_label] - - - chemin_fichier = chemin_dossier / fichier_choisi - with chemin_fichier.open(encoding="utf-8") as f: - contenu = f.read() - st.markdown(contenu, unsafe_allow_html=True) - - -niveau_labels = { - 0: "Produit final", - 1: "Composant", - 2: "Minerai", - 10: "Opération", - 11: "Pays d'opération", - 12: "Acteur d'opération", - 99: "Pays géographique" -} -inverse_niveau_labels = {v: k for k, v in niveau_labels.items()} - -DOT_FILE = "schema.txt" -charger_schema_depuis_gitea(DOT_FILE) - -# Charger le graphe une seule fois -try: - dot_file_path = True - if "G_temp" not in st.session_state: - if charger_schema_depuis_gitea(DOT_FILE): - st.session_state["G_temp"] = read_dot(DOT_FILE) - st.session_state["G_temp_ivc"] = st.session_state["G_temp"].copy() - else: - dot_file_path = False - G_temp = st.session_state["G_temp"] - G_temp_ivc = st.session_state["G_temp_ivc"] -except: - st.error("Erreur de lecture du fichier DOT") - dot_file_path = False - -if dot_file_path: + Retour: + G: le graphe modifié + """ + st.header("Personnalisation des produits finaux") st.markdown(""" -
- """, unsafe_allow_html=True) +--- - with st.sidebar: - st.markdown("---") - st.header("Navigation") - st.markdown("---") - if "onglet" not in st.session_state: - st.session_state.onglet = "Instructions" +Dans cette section, vous pouvez ajouter des produits finaux qui ne sont pas présents dans la liste, +par exemple des produits que vous concevez vous même. - if st.button("📄 Instructions"): - st.session_state.onglet = "Instructions" - if st.button("🔍 Analyse"): - st.session_state.onglet = "Analyse" - if st.button("📊 Visualisations"): - st.session_state.onglet = "Visualisations" - if st.button("📚 Fiches"): - st.session_state.onglet = "Fiches" +Pour chacun de ces produits, vous allez lui associer les composants qui le constituent, et si +cela vous convient, lui associer une opération d'assemblage existante. + +Les modifications que vous faites ne sont pas stockées dans l'application. Vous pouvez toutefois +les enregistrer dans un fichier que vous pourrez recharger ultérieurement. + +--- +""") + + # --- 1. Ajouter un nouveau produit final + st.subheader("Ajouter un nouveau produit final") + new_prod = st.text_input("Nom du nouveau produit (unique)", key="new_prod") + if new_prod: + # Opérations d'assemblage disponibles (niveau 10) + ops_dispo = sorted([ + n for n, d in G.nodes(data=True) + if d.get("niveau") == "10" + and any( + G.has_edge(p, n) and G.nodes[p].get("niveau") == "0" + for p in G.predecessors(n) + ) + ]) + sel_new_op = st.selectbox( + "Opération d'assemblage (optionnelle)", + options=["-- Aucune --"] + ops_dispo, + index=0, + key="new_op" + ) + # Composants de niveau 1 + niveau1 = sorted([ + n for n, d in G.nodes(data=True) + if d.get("niveau") == "1" + ]) + sel_comps = st.multiselect( + "Composants à lier", options=niveau1, key="new_links" + ) + if st.button("Créer le produit", key="btn_new"): + G.add_node(new_prod, niveau="0", personnalisation="oui", label=new_prod) + if sel_new_op != "-- Aucune --": + G.add_edge(new_prod, sel_new_op) + for comp in sel_comps: + G.add_edge(new_prod, comp) + st.success( + f"{new_prod} ajouté : {len(sel_comps)} composant(s)" + + (f", opération {sel_new_op}" if sel_new_op != "-- Aucune --" else "") + ) + + st.markdown("---") + + # --- 2. Modifier un produit final ajouté + st.subheader("Modifier un produit final ajouté") + produits0 = sorted([ + n for n, d in G.nodes(data=True) + if d.get("niveau") == "0" and d.get("personnalisation") == "oui" + ]) + sel_display = st.multiselect( + "Sélectionnez un produit final ajouté à modifier", + options=produits0, + key="prod_sel" + ) + if sel_display: + prod = sel_display[0] + # Bouton de suppression + if st.button(f"Supprimer le produit {prod}", key=f"del_{prod}"): + G.remove_node(prod) + st.success(f"Produit « {prod} » supprimé.") + st.session_state.pop("prod_sel", None) + return G + # Opérations d'assemblage disponibles + ops_dispo = sorted([ + n for n, d in G.nodes(data=True) + if d.get("niveau") == "10" + and any( + G.has_edge(p, n) and G.nodes[p].get("niveau") == "0" + for p in G.predecessors(n) + ) + ]) + # Opération actuelle + curr_ops = [ + succ for succ in G.successors(prod) + if G.nodes[succ].get("niveau") == "10" + ] + default_idx = 0 + if curr_ops and curr_ops[0] in ops_dispo: + default_idx = ops_dispo.index(curr_ops[0]) + 1 + sel_op = st.selectbox( + f"Opération d'assemblage liée à {prod} (optionnelle)", + options=["-- Aucune --"] + ops_dispo, + index=default_idx, + key=f"op_{prod}" + ) + # Composants liés + niveau1 = sorted([ + n for n, d in G.nodes(data=True) + if d.get("niveau") == "1" + ]) + linked = [ + succ for succ in G.successors(prod) + if G.nodes[succ].get("niveau") == "1" + ] + nouveaux = st.multiselect( + f"Composants liés à {prod}", + options=niveau1, + default=linked, + key=f"links_{prod}" + ) + # Mise à jour + if st.button(f"Mettre à jour {prod}", key=f"btn_{prod}"): + # Mettre à jour l'opération + for op in curr_ops: + if sel_op == "-- Aucune --" or op != sel_op: + G.remove_edge(prod, op) + if sel_op != "-- Aucune --" and (not curr_ops or sel_op not in curr_ops): + G.add_edge(prod, sel_op) + # Mettre à jour les composants + for comp in set(linked) - set(nouveaux): + G.remove_edge(prod, comp) + for comp in set(nouveaux) - set(linked): + G.add_edge(prod, comp) + st.success( + f"{prod} mis à jour : {len(nouveaux)} composant(s)" + + (f", opération {sel_op}" if sel_op != "-- Aucune --" else "") + ) + + st.markdown("---") + + # --- 3. Sauvegarder ou restaurer la configuration + st.subheader("Sauvegarder ou restaurer la configuration") + + # Export + if st.button("Exporter configuration", key="export_config"): + nodes = [n for n, d in G.nodes(data=True) if d.get("personnalisation")=="oui"] + edges = [(u, v) for u, v in G.edges() if u in nodes] + conf = {"nodes": nodes, "edges": edges} + json_str = json.dumps(conf, ensure_ascii=False) + st.download_button( + label="Télécharger la config (JSON)", + data=json_str, + file_name="config_personnalisation.json", + mime="application/json" + ) + + # Import + uploaded = st.file_uploader( + "Importer une configuration (JSON) (max 100 Ko)", + type=["json"], key="import_config" + ) + if uploaded: + if uploaded.size > 100 * 1024: + st.error("Fichier trop volumineux (max 100 Ko).") + else: + try: + conf = json.load(uploaded) + for node in conf.get("nodes", []): + if not G.has_node(node): + G.add_node(node, niveau="0", personnalisation="oui", label=node) + for u, v in conf.get("edges", []): + if G.has_node(u) and G.has_node(v) and not G.has_edge(u, v): + G.add_edge(u, v) + st.success("Configuration importée avec succès.") + except Exception as e: + st.error(f"Erreur d'import: {e}") + + return G + +dot_file_path = None + +if st.session_state.onglet == "Instructions": + with open("Instructions.md", "r", encoding="utf-8") as f: + markdown_content = f.read() + st.markdown(markdown_content) + +elif st.session_state.onglet == "Fiches": + st.markdown("---") + st.markdown("**Affichage des fiches**") + st.markdown("Sélectionner d'abord l'opération que vous souhaitez examiner et ensuite choisisez la fiche à lire.") + st.markdown("---") + afficher_fiches() + +else: + # Charger le graphe une seule fois + if "G_temp" not in st.session_state: + try: + if charger_schema_depuis_gitea(DOT_FILE): + st.session_state["G_temp"] = read_dot(DOT_FILE) + st.session_state["G_temp_ivc"] = st.session_state["G_temp"].copy() + dot_file_path = True + else: + dot_file_path = False + except Exception as e: + st.error(f"Erreur de lecture du fichier DOT : {e}") + dot_file_path = False + else: + dot_file_path = True + + if dot_file_path: + G_temp = st.session_state["G_temp"] + G_temp_ivc = st.session_state["G_temp_ivc"] + else: + st.error("Impossible de charger le graphe pour cet onglet.") + +if dot_file_path and st.session_state.onglet == "Analyse": + try: + niveaux_temp = { + node: int(str(attrs.get("niveau")).strip('"')) + for node, attrs in G_temp.nodes(data=True) + if attrs.get("niveau") and str(attrs.get("niveau")).strip('"').isdigit() + } + G_temp.remove_nodes_from([n for n in G_temp.nodes() if n not in niveaux_temp]) + G_temp.remove_nodes_from( + [n for n in G_temp.nodes() if niveaux_temp.get(n) == 10 and 'Reserves' in n]) st.markdown("---") + st.markdown("**Sélection du niveau des nœuds de départ et d'arrivée pour choisir la zone à analyser**") + st.markdown("Sélectionner le niveau de départ qui donnera les nœuds de gauche") + niveau_choix = ["-- Sélectionner un niveau --"] + list(niveau_labels.values()) - if st.session_state.onglet == "Instructions": - with open("Instructions.md", "r", encoding="utf-8") as f: - markdown_content = f.read() - st.markdown(markdown_content) + niveau_depart_label = st.selectbox("Niveau de départ", niveau_choix, key="analyse_niveau_depart") - elif st.session_state.onglet == "Analyse": - try: - niveaux_temp = { - node: int(str(attrs.get("niveau")).strip('"')) - for node, attrs in G_temp.nodes(data=True) - if attrs.get("niveau") and str(attrs.get("niveau")).strip('"').isdigit() - } - G_temp.remove_nodes_from([n for n in G_temp.nodes() if n not in niveaux_temp]) - G_temp.remove_nodes_from( - [n for n in G_temp.nodes() if niveaux_temp.get(n) == 10 and 'Reserves' in n]) + if niveau_depart_label != "-- Sélectionner un niveau --": + niveau_depart = inverse_niveau_labels[niveau_depart_label] + niveaux_arrivee_possibles = [v for k, v in niveau_labels.items() if k > niveau_depart] - st.markdown("---") - st.markdown("**Sélection du niveau des nœuds de départ et d'arrivée pour choisir la zone à analyser**") - st.markdown("Sélectionner le niveau de départ qui donnera les nœuds de gauche") - niveau_choix = ["-- Sélectionner un niveau --"] + list(niveau_labels.values()) + st.markdown("Sélectionner le niveau d'arrivée qui donnera les nœuds de droite") - niveau_depart_label = st.selectbox("Niveau de départ", niveau_choix, key="analyse_niveau_depart") + niveaux_arrivee_choix = ["-- Sélectionner un niveau --"] + niveaux_arrivee_possibles + niveau_arrivee_label = st.selectbox("Niveau d'arrivée", niveaux_arrivee_choix, key="analyse_niveau_arrivee") - if niveau_depart_label != "-- Sélectionner un niveau --": - niveau_depart = inverse_niveau_labels[niveau_depart_label] + if niveau_arrivee_label != "-- Sélectionner un niveau --": + niveau_arrivee = inverse_niveau_labels[niveau_arrivee_label] - niveaux_arrivee_possibles = [v for k, v in niveau_labels.items() if k > niveau_depart] - - st.markdown("Sélectionner le niveau d'arrivée qui donnera les nœuds de droite") - - niveaux_arrivee_choix = ["-- Sélectionner un niveau --"] + niveaux_arrivee_possibles - - niveau_arrivee_label = st.selectbox("Niveau d'arrivée", niveaux_arrivee_choix, key="analyse_niveau_arrivee") + minerais_selection = None + if niveau_depart < 2 < niveau_arrivee: + # Tous les nœuds de niveau 2 (minerai) + minerais_nodes = sorted([ + n for n, d in G_temp.nodes(data=True) + if d.get("niveau") and int(str(d.get("niveau")).strip('"')) == 2 + ]) + minerais_selection = st.multiselect( + "Filtrer par minerais (optionnel)", + options=minerais_nodes, + key="analyse_minerais" + ) st.markdown("---") - if niveau_arrivee_label != "-- Sélectionner un niveau --": - niveau_arrivee = inverse_niveau_labels[niveau_arrivee_label] + depart_nodes = [n for n in G_temp.nodes() if niveaux_temp.get(n) == niveau_depart] + arrivee_nodes = [n for n in G_temp.nodes() if niveaux_temp.get(n) == niveau_arrivee] - depart_nodes = [n for n in G_temp.nodes() if niveaux_temp.get(n) == niveau_depart] - arrivee_nodes = [n for n in G_temp.nodes() if niveaux_temp.get(n) == niveau_arrivee] + st.markdown("**Sélection fine des items du niveau de départ et d'arrivée**") + st.markdown("Sélectionner un ou plusieurs items du niveau de départ") - st.markdown("**Sélection fine des items du niveau de départ et d'arrivée**") - st.markdown("Sélectionner un ou plusieurs items du niveau de départ") + noeuds_depart = st.multiselect("Filtrer par noeuds de départ (optionnel)", sorted(depart_nodes), key="analyse_noeuds_depart") - noeuds_depart = st.multiselect("Filtrer par noeuds de départ (optionnel)", sorted(depart_nodes), key="analyse_noeuds_depart") + st.markdown("Sélectionner un ou plusieurs items du niveau d'arrivée") - st.markdown("Sélectionner un ou plusieurs items du niveau d'arrivée") + noeuds_arrivee = st.multiselect("Filtrer par noeuds d'arrivée (optionnel)", sorted(arrivee_nodes), key="analyse_noeuds_arrivee") - noeuds_arrivee = st.multiselect("Filtrer par noeuds d'arrivée (optionnel)", sorted(arrivee_nodes), key="analyse_noeuds_arrivee") + st.markdown("---") - st.markdown("---") + noeuds_depart = noeuds_depart if noeuds_depart else None + noeuds_arrivee = noeuds_arrivee if noeuds_arrivee else None - noeuds_depart = noeuds_depart if noeuds_depart else None - noeuds_arrivee = noeuds_arrivee if noeuds_arrivee else None + st.markdown("**Sélection des filtres pour identifier les vulnérabilités**") - st.markdown("**Sélection des filtres pour identifier les vulnérabilités**") + filtrer_criticite = st.checkbox("Filtrer les chemins contenant au moins minerai critique pour un composant (ICS > 66 %)", key="analyse_filtrer_criticite") + filtrer_ivc = st.checkbox("Filtrer les chemins contenant au moins un minerai critique par rapport à la concurrence sectorielle (IVC > 30)", key="analyse_filtrer_ivc") + filtrer_ihh = st.checkbox("Filtrer les chemins contenant au moins une opération critique par rapport à la concentration géographique ou industrielle (IHH pays ou acteurs > 25)", key="analyse_filtrer_ihh") - filtrer_criticite = st.checkbox("Filtrer les chemins contenant au moins minerai critique pour un composant (ICS > 66 %)", key="analyse_filtrer_criticite") - filtrer_ivc = st.checkbox("Filtrer les chemins contenant au moins un minerai critique par rapport à la concurrence sectorielle (IVC > 30)", key="analyse_filtrer_ivc") - filtrer_ihh = st.checkbox("Filtrer les chemins contenant au moins une opération critique par rapport à la concentration géographique ou industrielle (IHH pays ou acteurs > 25)", key="analyse_filtrer_ihh") + ihh_type = None + if filtrer_ihh: + ihh_type = st.radio("Appliquer le filtre IHH sur :", ["Pays", "Acteurs"], horizontal=True, key="analyse_ihh_type") - ihh_type = None - if filtrer_ihh: - ihh_type = st.radio("Appliquer le filtre IHH sur :", ["Pays", "Acteurs"], horizontal=True, key="analyse_ihh_type") + filtrer_isg = st.checkbox("Filtrer les chemins contenant un pays instable (ISG ≥ 60)", key="analyse_filtrer_isg") + logique_filtrage = st.radio("Logique de filtrage", ["OU", "ET"], horizontal=True, key="analyse_logique_filtrage") - filtrer_isg = st.checkbox("Filtrer les chemins contenant un pays instable (ISG ≥ 60)", key="analyse_filtrer_isg") - logique_filtrage = st.radio("Logique de filtrage", ["OU", "ET"], horizontal=True, key="analyse_logique_filtrage") + st.markdown("---") - st.markdown("---") + if st.button("Lancer l’analyse", type="primary", key="analyse_lancer"): + afficher_sankey( + G_temp, + niveau_depart=niveau_depart, + niveau_arrivee=niveau_arrivee, + noeuds_depart=noeuds_depart, + noeuds_arrivee=noeuds_arrivee, + minerais=minerais_selection, + filtrer_criticite=filtrer_criticite, + filtrer_ivc=filtrer_ivc, + filtrer_ihh=filtrer_ihh, + filtrer_isg=filtrer_isg, + logique_filtrage=logique_filtrage + ) - if st.button("Lancer l’analyse", type="primary", key="analyse_lancer"): - afficher_sankey( - G_temp, - niveau_depart=niveau_depart, - niveau_arrivee=niveau_arrivee, - noeuds_depart=noeuds_depart, - noeuds_arrivee=noeuds_arrivee, - filtrer_criticite=filtrer_criticite, - filtrer_ivc=filtrer_ivc, - filtrer_ihh=filtrer_ihh, - filtrer_isg=filtrer_isg, - logique_filtrage=logique_filtrage - ) + except Exception as e: + st.error(f"Erreur de prévisualisation du graphe : {e}") - except Exception as e: - st.error(f"Erreur de prévisualisation du graphe : {e}") - - elif st.session_state.onglet == "Visualisations": - st.markdown("""**Indice de Herfindahl-Hirschmann - IHH vs Criticité** +elif dot_file_path and st.session_state.onglet == "Visualisations": + st.markdown("""**Indice de Herfindahl-Hirschmann - IHH vs Criticité** Entre 0 et 15%, concentration faible, entre 15 et 25%, modérée, au-delà, forte. Taille des points = criticité substituabilité du minerai """) - if st.button("Lancer", key="btn_ihh_criticite"): - try: - lancer_visualisation_ihh_criticite(G_temp) - except Exception as e: - st.error(f"Erreur dans la visualisation IHH vs Criticité : {e}") + if st.button("Lancer", key="btn_ihh_criticite"): + try: + lancer_visualisation_ihh_criticite(G_temp) + except Exception as e: + st.error(f"Erreur dans la visualisation IHH vs Criticité : {e}") - st.markdown("""**Indice de Herfindahl-Hirschmann - IHH vs IVC** + st.markdown("""**Indice de Herfindahl-Hirschmann - IHH vs IVC** Entre 0 et 15%, concentration faible, entre 15 et 25%, modérée, au-delà, forte. Taille des points = criticité concurrentielle du minerai """) - if st.button("Lancer", key="btn_ihh_ivc"): - try: - lancer_visualisation_ihh_ivc(G_temp_ivc) - except Exception as e: - st.error(f"Erreur dans la visualisation IHH vs IVC : {e}") + if st.button("Lancer", key="btn_ihh_ivc"): + try: + lancer_visualisation_ihh_ivc(G_temp_ivc) + except Exception as e: + st.error(f"Erreur dans la visualisation IHH vs IVC : {e}") - elif st.session_state.onglet == "Fiches": - st.markdown("---") - st.markdown("**Affichage des fiches**") - st.markdown("Sélectionner d'abord l'opération que vous souhaitez examiner et ensuite choisisez la fiche à lire.") - st.markdown("---") - afficher_fiches() +elif dot_file_path and st.session_state.onglet == "Personnalisation": + G_temp = lancer_personnalisation(G_temp) - st.markdown("
", unsafe_allow_html=True) +st.markdown("