Djohell commited on
Commit
c367418
·
1 Parent(s): eaf39b6
Files changed (2) hide show
  1. app.py +387 -383
  2. images/Nathalie_Devogelaere.jpg +3 -0
app.py CHANGED
@@ -84,19 +84,19 @@ def load_model_data():
84
  st.error(f"❌ Erreur lors du chargement des données : {e}")
85
  return pd.DataFrame()
86
  #_________________________________________________# Chargement des données d'incendies et de coordonnées#_______________________________________
87
- @st.cache_data
88
- def load_data():
89
- url_incendies = 'https://projet-incendie.s3.eu-west-3.amazonaws.com/Incendies_2006_2024.csv'
90
- return pd.read_csv(url_incendies, sep=';', encoding='utf-8', skiprows=3)
91
 
92
- @st.cache_data
93
- def load_coords():
94
- url_coords = 'https://projet-incendie.s3.eu-west-3.amazonaws.com/coordonnees_villes.csv'
95
- return pd.read_csv(url_coords, sep=',', encoding='utf-8')
96
 
97
  @st.cache_data
98
  def load_df_merge():
99
- url = 'https://projet-incendie.s3.eu-west-3.amazonaws.com/historique_incendies_avec_coordonnees.csv'
100
  return pd.read_csv(url, sep=';', encoding='utf-8')
101
  #------------------------------------------------------- ----------------Notre produit#_________________________________________________
102
  import streamlit as st
@@ -104,6 +104,8 @@ import pandas as pd
104
  import numpy as np
105
  import plotly.express as px
106
  import warnings
 
 
107
  from sklearn.exceptions import UndefinedMetricWarning
108
  from sklearn import set_config
109
  from sklearn.model_selection import train_test_split
@@ -124,8 +126,7 @@ set_config(display="text")
124
  @st.cache_data(show_spinner="🔄 Téléchargement du CSV…", ttl=None)
125
  def load_raw_data() -> pd.DataFrame:
126
  url = (
127
- "https://projet-incendie.s3.eu-west-3.amazonaws.com/"
128
- "dataset_modele_decompte.csv"
129
  )
130
  return pd.read_csv(url, sep=";")
131
 
@@ -164,7 +165,7 @@ def train_model_and_predict(df_raw: pd.DataFrame) -> pd.DataFrame:
164
  ev_test, du_test = y_test["event"], y_test["duration"]
165
 
166
  # d) Pipeline XGBSurv
167
- pipe = Pipeline([
168
  ("imputer", SimpleImputer(strategy="median")),
169
  ("scaler", StandardScaler()),
170
  ("xgb", XGBRegressor(
@@ -176,10 +177,10 @@ def train_model_and_predict(df_raw: pd.DataFrame) -> pd.DataFrame:
176
  random_state=42,
177
  )),
178
  ])
179
- pipe.fit(X_train, du_train, xgb__sample_weight=ev_train)
180
 
181
  # e) Affiche C-index dans la sidebar
182
- log_hr_test = pipe.predict(X_test)
183
  c_index = concordance_index_censored(ev_test, du_test, log_hr_test)[0]
184
  st.sidebar.write(f"**C-index (test)** : {c_index:.3f}")
185
 
@@ -229,7 +230,7 @@ def train_model_and_predict(df_raw: pd.DataFrame) -> pd.DataFrame:
229
  horizons = {7: "proba_7j", 30: "proba_30j", 60: "proba_60j",
230
  90: "proba_90j", 180: "proba_180j"}
231
 
232
- log_hr_all = pipe.predict(df[features])
233
  HR = np.exp(log_hr_all)
234
 
235
  for t, col in horizons.items():
@@ -286,95 +287,95 @@ if page == "Accueil":
286
  st.plotly_chart(fig, use_container_width=True)
287
 
288
  # ---------------------------------------------------------------Carte des casernes de pompiers#______________________________________________
289
- from branca.element import Template, MacroElement # Import nécessaire
290
-
291
- import folium
292
- from folium import DivIcon
293
- from streamlit_folium import st_folium
294
-
295
- if page == "Accueil":
296
-
297
- # Chargement des données des casernes
298
- df_casernes = pd.read_csv(
299
- 'https://projet-incendie.s3.eu-west-3.amazonaws.com/casernes_corses.csv',
300
- sep=',',
301
- encoding='utf8'
302
- )
303
-
304
- # Nettoyage des coordonnées
305
- df_casernes['latitude'] = df_casernes['latitude'].astype(str).str.replace(',', '.').astype(float)
306
- df_casernes['longitude'] = df_casernes['longitude'].astype(str).str.replace(',', '.').astype(float)
307
- df_casernes = df_casernes.dropna(subset=['latitude', 'longitude'])
308
-
309
- # Catégorisation des casernes
310
- df_casernes['categorie'] = np.select(
311
- [
312
- df_casernes['nom'].str.contains('centre', case=False, na=False),
313
- df_casernes['nom'].str.contains('base', case=False, na=False),
314
- df_casernes['nom'].str.contains('SSLIA', case=False, na=False),
315
- df_casernes['nom'].str.contains('citerne', case=False, na=False),
316
- df_casernes['nom'].str.contains('borne', case=False, na=False),
317
- ],
318
- [
319
- "Centre d'incendie et de secours",
320
- 'Base forestière',
321
- 'SSLIA (aérodromes)',
322
- 'Citerne',
323
- 'Borne incendie'
324
- ],
325
- default='Autre'
326
- )
327
-
328
- # Dictionnaire d'emojis
329
- emoji_legende = {
330
- "Centre d'incendie et de secours": "🚒",
331
- "Base forestière": "🌲",
332
- "SSLIA (aérodromes)": "✈️",
333
- "Citerne": "💦"
334
- }
335
-
336
- # Carte centrée sur la Corse
337
- m = folium.Map(location=[42.0396, 9.0129], zoom_start=8)
338
-
339
- for _, row in df_casernes.iterrows():
340
- emoji = emoji_legende.get(row['categorie'], '❓')
341
- folium.Marker(
342
- location=[row['latitude'], row['longitude']],
343
- popup=f"{emoji} {row['nom']}",
344
- icon=DivIcon(html=f"""<div style="font-size:24px">{emoji}</div>""")
345
- ).add_to(m)
346
-
347
- # Légende HTML
348
- legend_html = """
349
- {% macro html(this, kwargs) %}
350
- <div style="
351
- position: fixed;
352
- bottom: 50px; left: 50px; width: 280px;
353
- background-color: white;
354
- border: 2px solid grey;
355
- z-index: 9999;
356
- font-size: 14px;
357
- color: black;
358
- padding: 10px;
359
- border-radius: 10px;
360
- box-shadow: 2px 2px 6px rgba(0,0,0,0.3);
361
- ">
362
- <b>📘 Légende</b><br>
363
- 🚒 Centre d'incendie et de secours<br>
364
- 🌲 Base forestière<br>
365
- ✈️ SSLIA (aérodromes)<br>
366
- 💦 Citerne<br>
367
- </div>
368
- {% endmacro %}
369
- """
370
-
371
- legend = MacroElement()
372
- legend._template = Template(legend_html)
373
-
374
- m.get_root().add_child(legend)
375
-
376
- st.subheader("🗺️ Carte des casernes et équipements de lutte contre les incendies")
377
- st_folium(m, width=1000, height=800)
378
  #----------------------------------------------------------------------Page Notre Projet---------------------------------------------------
379
  if page == "Notre Projet":
380
  st.title("🔥 Projet Analyse des Incendies 🔥")
@@ -479,7 +480,7 @@ if page == "Notre Projet":
479
  """)
480
  #---------------------------------------------------Equipe du projet---------------------------------------------------
481
  st.subheader("👨‍💻 Équipe du projet")
482
- col1, col2, col3, col4 = st.columns(4)
483
  with col1:
484
  st.image("images/Francois_Minaret.jpg", width=150)
485
  st.markdown("**Francois Minaret**")
@@ -492,6 +493,9 @@ if page == "Notre Projet":
492
  with col4:
493
  st.image("images/Gilles_Akakpo.jpg", width=150)
494
  st.markdown("**Gilles Akakpo**")
 
 
 
495
  #---------------------------------------------------Notre Objectif --------------------------------------------------------
496
 
497
  st.subheader("🎯 Notre Objectif")
@@ -561,337 +565,337 @@ L’**analyse de survie** (ou **Survival Analysis**) est une méthode statistiqu
561
 
562
  #---------------------------------------------------# Page EDA -----------------------------------------------------------------
563
 
564
- if page == "Exploration des données":
565
- st.title("🗺️ Visualisation des incendies entre 2006 et 2024")
566
 
567
- df = load_data()
568
- coords = load_coords()
569
- df_merge = load_df_merge()
570
 
571
- st.subheader("Aperçu des coordonnées des villes")
572
 
573
- fig = px.scatter_map(
574
- coords,
575
- lat="latitude",
576
- lon="longitude",
577
- hover_name="ville",
578
- height=800,
579
- zoom=5,
580
- map_style="carto-positron",
581
- title="Carte interactive des communes (coordonnées)"
582
- )
583
- st.plotly_chart(fig, use_container_width=True)
584
 
585
  #---------------------------------------------------# DBSCAN Clustering---------------------------------------------------
586
- st.subheader("🔥 Détection des clusters d'incendies avec DBSCAN")
587
 
588
- commune_counts = df_merge.groupby(['Nom de la commune', 'latitude', 'longitude']).size().reset_index(name='frequence')
589
- df_expanded = commune_counts.loc[commune_counts.index.repeat(commune_counts['frequence'])].reset_index(drop=True)
590
 
591
- X = df_expanded[['latitude', 'longitude']]
592
- coords_rad = np.radians(X)
593
- kms_per_radian = 6371.0088
594
- eps_km = 5
595
- eps = eps_km / kms_per_radian
596
 
597
- db = DBSCAN(eps=eps, min_samples=20, metric='haversine').fit(coords_rad)
598
- df_expanded['cluster'] = db.labels_
599
 
600
- clustered_data = df_expanded[df_expanded['cluster'] != -1]
601
 
602
- fig = px.scatter_map(
603
- clustered_data,
604
- lat="latitude",
605
- lon="longitude",
606
- color="cluster",
607
- hover_name="Nom de la commune",
608
- zoom=5,
609
- height=900,
610
- title="🔥 Clusters d'incendies en France (2006-2024) détectés par DBSCAN",
611
- map_style="carto-positron"
612
- )
613
- st.plotly_chart(fig, use_container_width=True)
614
 
615
 
616
  #---------------------------------------------------Histogramme mensuel#---------------------------------------------------
617
- st.title("Comparaison mensuelle des incendies par année")
618
-
619
- df_temp = df_merge.copy()
620
- df_temp['Date'] = pd.to_datetime(df_temp['Date'], errors='coerce')
621
- df_temp = df_temp.dropna(subset=['Date'])
622
-
623
- df_temp['mois'] = df_temp['Date'].dt.month
624
- df_temp['année'] = df_temp['Date'].dt.year
625
-
626
- mois_abbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
627
- 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
628
- df_temp['mois_nom'] = df_temp['mois'].apply(lambda x: mois_abbr[x - 1])
629
- df_temp['mois_nom'] = pd.Categorical(df_temp['mois_nom'], categories=mois_abbr, ordered=True)
630
-
631
- df_grouped = df_temp.groupby(['mois_nom', 'année']).size().reset_index(name='nombre_feux')
632
-
633
- fig = px.bar(
634
- df_grouped,
635
- x='mois_nom',
636
- y='nombre_feux',
637
- color='année',
638
- barmode='group',
639
- title='Comparaison mensuelle des incendies par année',
640
- height=600,
641
- width=1000
642
- )
643
- st.plotly_chart(fig, use_container_width=True)
644
-
645
- show_footer()
646
-
647
- #--------------------------------------------------- Analyse des causes---------------------------------------------------
648
- causes = df_merge['Nature'].value_counts()
649
- st.subheader("Répartition des causes d'incendies")
650
- fig, ax = plt.subplots(figsize=(8, 6))
651
- ax.pie(
652
- causes.values,
653
- labels=causes.index,
654
- autopct='%1.1f%%',
655
- startangle=140,
656
- shadow=True,
657
- explode=[0.05]*len(causes)
658
- )
659
- ax.set_title("Répartition des causes d'incendies")
660
- ax.axis('equal')
661
- st.pyplot(fig)
662
 
663
- #---------------------------------------------------- Nombre total d’incendies par année-----------------------------------------
 
 
664
 
665
- if page == "Exploration des données":
666
- st.title("Analyse des incendies par année 🔥")
667
 
668
- # Copie du DataFrame
669
- df_temp = df_merge.copy()
 
 
670
 
671
- # Conversion de la colonne Date
672
- df_temp['Date'] = pd.to_datetime(df_temp['Date'])
673
- df_temp['année'] = df_temp['Date'].dt.year
674
 
675
- # Regroupement par année uniquement
676
- df_grouped = df_temp.groupby('année').size().reset_index(name='nombre_feux')
 
 
 
 
 
 
 
 
 
677
 
678
- # Création du graphique en barres
679
- fig = px.bar(
680
- df_grouped,
681
- x='année',
682
- y='nombre_feux',
683
- title='Nombre total d’incendies par année',
684
- height=600,
685
- width=1200,
686
- text='nombre_feux'
687
- )
688
 
689
- fig.update_xaxes(
690
- tickmode='linear',
691
- dtick=1 # une année à chaque tick
692
- )
 
 
 
 
 
 
 
 
 
 
 
693
 
694
- fig.update_layout(
695
- xaxis_title='Année',
696
- yaxis_title='Nombre de feux',
697
- xaxis_tickangle=0
698
- )
699
 
700
- st.plotly_chart(fig)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
701
  #---------------------------------------------------- Page Exploration des données -----------------------------------------
702
 
703
- if page == "Exploration des données":
704
 
705
  #---------------------------------------------------- Les 10 départements avec le plus d’incendies -----------------------------------------
706
 
707
- # Copie du DataFrame
708
- df_temp = df_merge.copy()
709
 
710
- # Regroupement par département
711
- df_grouped = df_temp.groupby('Département').size().reset_index(name='nombre_feux')
712
 
713
- # Classement décroissant et sélection du top 10
714
- df_top10 = df_grouped.sort_values(by='nombre_feux', ascending=False).head(10)
715
 
716
- # Graphique en barres
717
- fig = px.bar(
718
- df_top10,
719
- x='Département',
720
- y='nombre_feux',
721
- title='Les 10 départements avec le plus d’incendies',
722
- height=600,
723
- width=1000,
724
- text='nombre_feux'
725
- )
726
 
727
- # Fond clair
728
- fig.update_layout(
729
- template='plotly_white',
730
- xaxis_title='Département',
731
- yaxis_title='Nombre de feux',
732
- xaxis_tickangle=-45,
733
- )
734
 
735
- # Texte au-dessus des barres
736
- fig.update_traces(textposition='outside')
737
 
738
- # Affichage dans l'app
739
- st.plotly_chart(fig)
740
 
741
 
742
  #---------------------------------------------------- Les 10 départements les plus touchés -----------------------------------------
743
 
744
- if page == "Exploration des données":
745
 
746
- # 🔎 Vérification rapide du DataFrame
747
- if "Département" not in df_merge.columns:
748
- st.error("❌ La colonne 'Département' est absente du DataFrame.")
749
- elif df_merge.empty:
750
- st.warning("⚠️ Le DataFrame est vide.")
751
- else:
752
- # ✅ Copie et nettoyage du DataFrame
753
- df_temp = df_merge.copy()
754
- df_temp = df_temp[df_temp['Département'].notna()] # Supprime les lignes sans département
755
 
756
- # 📊 Regroupement par département
757
- df_grouped = df_temp.groupby('Département').size().reset_index(name='nombre_feux')
758
 
759
- # 🔢 Total général
760
- total_feux = df_grouped['nombre_feux'].sum()
761
 
762
- # 🔝 Top 10 des départements
763
- df_top10 = df_grouped.sort_values(by='nombre_feux', ascending=False).head(10)
764
 
765
- # 📈 Calcul des proportions
766
- df_top10['proportion_totale'] = df_top10['nombre_feux'] / total_feux
767
 
768
- # 🥧 Création du graphique circulaire
769
- fig_pie = px.pie(
770
- df_top10,
771
- names='Département',
772
- values='nombre_feux',
773
- title='Les 10 départements les plus touchés (proportion sur le total global)',
774
- )
775
- fig_pie.update_traces(textinfo='label+percent')
776
 
777
- # 📌 Affichage dans l'app
778
- st.plotly_chart(fig_pie)
779
 
780
  #---------------------------------------------------- Carte des feux par département (2006-2024) ---------------------------------------------------------
781
 
782
- if page == "Exploration des données":
783
- st.subheader("Carte des feux par département (2006-2024)")
784
-
785
- # Copie du dataset
786
- df_temp = df_merge.copy()
787
-
788
- # Codes départements formatés
789
- df_temp['Département'] = df_temp['Département'].astype(str).str.zfill(2)
790
- df_grouped = df_temp.groupby('Département').size().reset_index(name='nombre_feux')
791
-
792
- # Chargement GeoJSON
793
- url_geojson = 'https://raw.githubusercontent.com/gregoiredavid/france-geojson/master/departements-version-simplifiee.geojson'
794
- with urllib.request.urlopen(url_geojson) as response:
795
- departements_geojson = json.load(response)
796
-
797
- # Carte choroplèthe
798
- fig = px.choropleth(
799
- df_grouped,
800
- geojson=departements_geojson,
801
- locations='Département',
802
- featureidkey='properties.code',
803
- color='nombre_feux',
804
- color_continuous_scale='OrRd',
805
- title='Total des feux par département (2006-2024)',
806
- labels={'nombre_feux': 'Feux'},
807
- )
808
-
809
- # Style géographique
810
- fig.update_geos(
811
- visible=False,
812
- lataxis_range=[41, 52],
813
- lonaxis_range=[-5.5, 10],
814
- showcountries=False,
815
- showcoastlines=False,
816
- showland=True,
817
- landcolor='white',
818
- fitbounds="locations"
819
- )
820
-
821
- # Mise en page
822
- fig.update_layout(
823
- template='plotly_white',
824
- width=1000,
825
- height=700,
826
- margin=dict(l=0, r=20, t=40, b=0),
827
- coloraxis_colorbar=dict(
828
- title="Feux",
829
- thickness=15,
830
- len=0.4,
831
- y=0.5
832
- )
833
- )
834
-
835
- # Affichage Streamlit
836
- st.plotly_chart(fig)
837
  #---------------------------------------------------- Les 10 départements avec le plus d’incendies -----------------------------------------
838
  # import plotly.graph_objects as go
839
 
840
  # -----------------------------------------------------------
841
  # 🔥 Top-10 des départements par nombre de feux – version GO
842
  # -----------------------------------------------------------
843
- if page == "Exploration des données":
844
- df_temp = df_merge.copy()
845
- df_temp["Département"] = df_temp["Département"].replace(
846
- {"2A": "2A/2B", "2B": "2A/2B"}
847
- )
848
-
849
- df_count = (
850
- df_temp.groupby("Département")
851
- .size()
852
- .reset_index(name="Nombre de feux")
853
- .sort_values("Nombre de feux", ascending=False)
854
- .head(10)
855
- )
856
-
857
- # ── Barres avec labels (Graph Objects)
858
- fig_top10_feux = go.Figure(
859
- data=go.Bar(
860
- x=df_count["Département"],
861
- y=df_count["Nombre de feux"],
862
- text=df_count["Nombre de feux"].apply(lambda x: f"{x:,}"),
863
- textposition="outside",
864
- textfont=dict(size=16, color="#2e2e2e"), # police foncée
865
- marker=dict(
866
- color="#627CFF",
867
- line=dict(color="black", width=1.5),
868
- ),
869
- )
870
- )
871
-
872
- # ── Mise en page inspirée de ta Fig 1
873
- fig_top10_feux.update_layout(
874
- title="🔥 Top 10 des départements avec le plus d’incendies",
875
- title_font_size=28,
876
- template="plotly_white", # fond clair + grille
877
- plot_bgcolor="rgba(245,248,255,1)",
878
- paper_bgcolor="rgba(245,248,255,1)",
879
- margin=dict(l=80, r=80, t=110, b=120),
880
- font=dict(size=18, color="#2e2e2e"), # police par défaut foncée
881
- xaxis=dict(
882
- title="Département",
883
- tickangle=-35,
884
- tickfont=dict(size=16),
885
- ),
886
- yaxis=dict(
887
- title="Nombre de feux",
888
- tickformat=",d",
889
- tickfont=dict(size=16),
890
- ),
891
- bargap=0.05,
892
- )
893
-
894
- st.plotly_chart(fig_top10_feux, use_container_width=True)
895
 
896
 
897
  #---------------------------------------------------- Page Résultats des modèles -----------------------------------------
 
84
  st.error(f"❌ Erreur lors du chargement des données : {e}")
85
  return pd.DataFrame()
86
  #_________________________________________________# Chargement des données d'incendies et de coordonnées#_______________________________________
87
+ # @st.cache_data
88
+ # def load_data():
89
+ # url_incendies = 'https://projet-incendie.s3.eu-west-3.amazonaws.com/Incendies_2006_2024.csv'
90
+ # return pd.read_csv(url_incendies, sep=';', encoding='utf-8', skiprows=3)
91
 
92
+ # @st.cache_data
93
+ # def load_coords():
94
+ # url_coords = 'https://projet-incendie.s3.eu-west-3.amazonaws.com/coordonnees_villes.csv'
95
+ # return pd.read_csv(url_coords, sep=',', encoding='utf-8')
96
 
97
  @st.cache_data
98
  def load_df_merge():
99
+ url = 'https://fireprojectbislead.s3.us-east-1.amazonaws.com/dataset/historique_incendies_avec_coordonnees.csv'
100
  return pd.read_csv(url, sep=';', encoding='utf-8')
101
  #------------------------------------------------------- ----------------Notre produit#_________________________________________________
102
  import streamlit as st
 
104
  import numpy as np
105
  import plotly.express as px
106
  import warnings
107
+ import mlflow
108
+ import mlflow.sklearn
109
  from sklearn.exceptions import UndefinedMetricWarning
110
  from sklearn import set_config
111
  from sklearn.model_selection import train_test_split
 
126
  @st.cache_data(show_spinner="🔄 Téléchargement du CSV…", ttl=None)
127
  def load_raw_data() -> pd.DataFrame:
128
  url = (
129
+ "https://fireprojectbislead.s3.us-east-1.amazonaws.com/compile/dataset_complet_meteo.csv"
 
130
  )
131
  return pd.read_csv(url, sep=";")
132
 
 
165
  ev_test, du_test = y_test["event"], y_test["duration"]
166
 
167
  # d) Pipeline XGBSurv
168
+ model = Pipeline([
169
  ("imputer", SimpleImputer(strategy="median")),
170
  ("scaler", StandardScaler()),
171
  ("xgb", XGBRegressor(
 
177
  random_state=42,
178
  )),
179
  ])
180
+ model.fit(X_train, du_train, xgb__sample_weight=ev_train)
181
 
182
  # e) Affiche C-index dans la sidebar
183
+ log_hr_test = model.predict(X_test)
184
  c_index = concordance_index_censored(ev_test, du_test, log_hr_test)[0]
185
  st.sidebar.write(f"**C-index (test)** : {c_index:.3f}")
186
 
 
230
  horizons = {7: "proba_7j", 30: "proba_30j", 60: "proba_60j",
231
  90: "proba_90j", 180: "proba_180j"}
232
 
233
+ log_hr_all = model.predict(df[features])
234
  HR = np.exp(log_hr_all)
235
 
236
  for t, col in horizons.items():
 
287
  st.plotly_chart(fig, use_container_width=True)
288
 
289
  # ---------------------------------------------------------------Carte des casernes de pompiers#______________________________________________
290
+ # from branca.element import Template, MacroElement # Import nécessaire
291
+
292
+ # import folium
293
+ # from folium import DivIcon
294
+ # from streamlit_folium import st_folium
295
+
296
+ # if page == "Accueil":
297
+
298
+ # # Chargement des données des casernes
299
+ # df_casernes = pd.read_csv(
300
+ # 'https://projet-incendie.s3.eu-west-3.amazonaws.com/casernes_corses.csv',
301
+ # sep=',',
302
+ # encoding='utf8'
303
+ # )
304
+
305
+ # # Nettoyage des coordonnées
306
+ # df_casernes['latitude'] = df_casernes['latitude'].astype(str).str.replace(',', '.').astype(float)
307
+ # df_casernes['longitude'] = df_casernes['longitude'].astype(str).str.replace(',', '.').astype(float)
308
+ # df_casernes = df_casernes.dropna(subset=['latitude', 'longitude'])
309
+
310
+ # # Catégorisation des casernes
311
+ # df_casernes['categorie'] = np.select(
312
+ # [
313
+ # df_casernes['nom'].str.contains('centre', case=False, na=False),
314
+ # df_casernes['nom'].str.contains('base', case=False, na=False),
315
+ # df_casernes['nom'].str.contains('SSLIA', case=False, na=False),
316
+ # df_casernes['nom'].str.contains('citerne', case=False, na=False),
317
+ # df_casernes['nom'].str.contains('borne', case=False, na=False),
318
+ # ],
319
+ # [
320
+ # "Centre d'incendie et de secours",
321
+ # 'Base forestière',
322
+ # 'SSLIA (aérodromes)',
323
+ # 'Citerne',
324
+ # 'Borne incendie'
325
+ # ],
326
+ # default='Autre'
327
+ # )
328
+
329
+ # # Dictionnaire d'emojis
330
+ # emoji_legende = {
331
+ # "Centre d'incendie et de secours": "🚒",
332
+ # "Base forestière": "🌲",
333
+ # "SSLIA (aérodromes)": "✈️",
334
+ # "Citerne": "💦"
335
+ # }
336
+
337
+ # # Carte centrée sur la Corse
338
+ # m = folium.Map(location=[42.0396, 9.0129], zoom_start=8)
339
+
340
+ # for _, row in df_casernes.iterrows():
341
+ # emoji = emoji_legende.get(row['categorie'], '❓')
342
+ # folium.Marker(
343
+ # location=[row['latitude'], row['longitude']],
344
+ # popup=f"{emoji} {row['nom']}",
345
+ # icon=DivIcon(html=f"""<div style="font-size:24px">{emoji}</div>""")
346
+ # ).add_to(m)
347
+
348
+ # # Légende HTML
349
+ # legend_html = """
350
+ # {% macro html(this, kwargs) %}
351
+ # <div style="
352
+ # position: fixed;
353
+ # bottom: 50px; left: 50px; width: 280px;
354
+ # background-color: white;
355
+ # border: 2px solid grey;
356
+ # z-index: 9999;
357
+ # font-size: 14px;
358
+ # color: black;
359
+ # padding: 10px;
360
+ # border-radius: 10px;
361
+ # box-shadow: 2px 2px 6px rgba(0,0,0,0.3);
362
+ # ">
363
+ # <b>📘 Légende</b><br>
364
+ # 🚒 Centre d'incendie et de secours<br>
365
+ # 🌲 Base forestière<br>
366
+ # ✈️ SSLIA (aérodromes)<br>
367
+ # 💦 Citerne<br>
368
+ # </div>
369
+ # {% endmacro %}
370
+ # """
371
+
372
+ # legend = MacroElement()
373
+ # legend._template = Template(legend_html)
374
+
375
+ # m.get_root().add_child(legend)
376
+
377
+ # st.subheader("🗺️ Carte des casernes et équipements de lutte contre les incendies")
378
+ # st_folium(m, width=1000, height=800)
379
  #----------------------------------------------------------------------Page Notre Projet---------------------------------------------------
380
  if page == "Notre Projet":
381
  st.title("🔥 Projet Analyse des Incendies 🔥")
 
480
  """)
481
  #---------------------------------------------------Equipe du projet---------------------------------------------------
482
  st.subheader("👨‍💻 Équipe du projet")
483
+ col1, col2, col3, col4, col5 = st.columns(5)
484
  with col1:
485
  st.image("images/Francois_Minaret.jpg", width=150)
486
  st.markdown("**Francois Minaret**")
 
493
  with col4:
494
  st.image("images/Gilles_Akakpo.jpg", width=150)
495
  st.markdown("**Gilles Akakpo**")
496
+ with col5:
497
+ st.image("images/Nathalie_Devogelaere.jpg", width=150)
498
+ st.markdown("**Nathalie Devogelaere**")
499
  #---------------------------------------------------Notre Objectif --------------------------------------------------------
500
 
501
  st.subheader("🎯 Notre Objectif")
 
565
 
566
  #---------------------------------------------------# Page EDA -----------------------------------------------------------------
567
 
568
+ # if page == "Exploration des données":
569
+ # st.title("🗺️ Visualisation des incendies entre 2006 et 2024")
570
 
571
+ # df = load_data()
572
+ # coords = load_coords()
573
+ # df_merge = load_df_merge()
574
 
575
+ # st.subheader("Aperçu des coordonnées des villes")
576
 
577
+ # fig = px.scatter_map(
578
+ # coords,
579
+ # lat="latitude",
580
+ # lon="longitude",
581
+ # hover_name="ville",
582
+ # height=800,
583
+ # zoom=5,
584
+ # map_style="carto-positron",
585
+ # title="Carte interactive des communes (coordonnées)"
586
+ # )
587
+ # st.plotly_chart(fig, use_container_width=True)
588
 
589
  #---------------------------------------------------# DBSCAN Clustering---------------------------------------------------
590
+ # st.subheader("🔥 Détection des clusters d'incendies avec DBSCAN")
591
 
592
+ # commune_counts = df_merge.groupby(['Nom de la commune', 'latitude', 'longitude']).size().reset_index(name='frequence')
593
+ # df_expanded = commune_counts.loc[commune_counts.index.repeat(commune_counts['frequence'])].reset_index(drop=True)
594
 
595
+ # X = df_expanded[['latitude', 'longitude']]
596
+ # coords_rad = np.radians(X)
597
+ # kms_per_radian = 6371.0088
598
+ # eps_km = 5
599
+ # eps = eps_km / kms_per_radian
600
 
601
+ # db = DBSCAN(eps=eps, min_samples=20, metric='haversine').fit(coords_rad)
602
+ # df_expanded['cluster'] = db.labels_
603
 
604
+ # clustered_data = df_expanded[df_expanded['cluster'] != -1]
605
 
606
+ # fig = px.scatter_map(
607
+ # clustered_data,
608
+ # lat="latitude",
609
+ # lon="longitude",
610
+ # color="cluster",
611
+ # hover_name="Nom de la commune",
612
+ # zoom=5,
613
+ # height=900,
614
+ # title="🔥 Clusters d'incendies en France (2006-2024) détectés par DBSCAN",
615
+ # map_style="carto-positron"
616
+ # )
617
+ # st.plotly_chart(fig, use_container_width=True)
618
 
619
 
620
  #---------------------------------------------------Histogramme mensuel#---------------------------------------------------
621
+ # st.title("Comparaison mensuelle des incendies par année")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
622
 
623
+ # df_temp = df_merge.copy()
624
+ # df_temp['Date'] = pd.to_datetime(df_temp['Date'], errors='coerce')
625
+ # df_temp = df_temp.dropna(subset=['Date'])
626
 
627
+ # df_temp['mois'] = df_temp['Date'].dt.month
628
+ # df_temp['année'] = df_temp['Date'].dt.year
629
 
630
+ # mois_abbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
631
+ # 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
632
+ # df_temp['mois_nom'] = df_temp['mois'].apply(lambda x: mois_abbr[x - 1])
633
+ # df_temp['mois_nom'] = pd.Categorical(df_temp['mois_nom'], categories=mois_abbr, ordered=True)
634
 
635
+ # df_grouped = df_temp.groupby(['mois_nom', 'année']).size().reset_index(name='nombre_feux')
 
 
636
 
637
+ # fig = px.bar(
638
+ # df_grouped,
639
+ # x='mois_nom',
640
+ # y='nombre_feux',
641
+ # color='année',
642
+ # barmode='group',
643
+ # title='Comparaison mensuelle des incendies par année',
644
+ # height=600,
645
+ # width=1000
646
+ # )
647
+ # st.plotly_chart(fig, use_container_width=True)
648
 
649
+ # show_footer()
 
 
 
 
 
 
 
 
 
650
 
651
+ #--------------------------------------------------- Analyse des causes---------------------------------------------------
652
+ # causes = df_merge['Nature'].value_counts()
653
+ # st.subheader("Répartition des causes d'incendies")
654
+ # fig, ax = plt.subplots(figsize=(8, 6))
655
+ # ax.pie(
656
+ # causes.values,
657
+ # labels=causes.index,
658
+ # autopct='%1.1f%%',
659
+ # startangle=140,
660
+ # shadow=True,
661
+ # explode=[0.05]*len(causes)
662
+ # )
663
+ # ax.set_title("Répartition des causes d'incendies")
664
+ # ax.axis('equal')
665
+ # st.pyplot(fig)
666
 
667
+ #---------------------------------------------------- Nombre total d’incendies par année-----------------------------------------
 
 
 
 
668
 
669
+ # if page == "Exploration des données":
670
+ # st.title("Analyse des incendies par année 🔥")
671
+
672
+ # # Copie du DataFrame
673
+ # df_temp = df_merge.copy()
674
+
675
+ # # Conversion de la colonne Date
676
+ # df_temp['Date'] = pd.to_datetime(df_temp['Date'])
677
+ # df_temp['année'] = df_temp['Date'].dt.year
678
+
679
+ # # Regroupement par année uniquement
680
+ # df_grouped = df_temp.groupby('année').size().reset_index(name='nombre_feux')
681
+
682
+ # # Création du graphique en barres
683
+ # fig = px.bar(
684
+ # df_grouped,
685
+ # x='année',
686
+ # y='nombre_feux',
687
+ # title='Nombre total d’incendies par année',
688
+ # height=600,
689
+ # width=1200,
690
+ # text='nombre_feux'
691
+ # )
692
+
693
+ # fig.update_xaxes(
694
+ # tickmode='linear',
695
+ # dtick=1 # une année à chaque tick
696
+ # )
697
+
698
+ # fig.update_layout(
699
+ # xaxis_title='Année',
700
+ # yaxis_title='Nombre de feux',
701
+ # xaxis_tickangle=0
702
+ # )
703
+
704
+ # st.plotly_chart(fig)
705
  #---------------------------------------------------- Page Exploration des données -----------------------------------------
706
 
707
+ # if page == "Exploration des données":
708
 
709
  #---------------------------------------------------- Les 10 départements avec le plus d’incendies -----------------------------------------
710
 
711
+ # # Copie du DataFrame
712
+ # df_temp = df_merge.copy()
713
 
714
+ # # Regroupement par département
715
+ # df_grouped = df_temp.groupby('Département').size().reset_index(name='nombre_feux')
716
 
717
+ # # Classement décroissant et sélection du top 10
718
+ # df_top10 = df_grouped.sort_values(by='nombre_feux', ascending=False).head(10)
719
 
720
+ # # Graphique en barres
721
+ # fig = px.bar(
722
+ # df_top10,
723
+ # x='Département',
724
+ # y='nombre_feux',
725
+ # title='Les 10 départements avec le plus d’incendies',
726
+ # height=600,
727
+ # width=1000,
728
+ # text='nombre_feux'
729
+ # )
730
 
731
+ # # Fond clair
732
+ # fig.update_layout(
733
+ # template='plotly_white',
734
+ # xaxis_title='Département',
735
+ # yaxis_title='Nombre de feux',
736
+ # xaxis_tickangle=-45,
737
+ # )
738
 
739
+ # # Texte au-dessus des barres
740
+ # fig.update_traces(textposition='outside')
741
 
742
+ # # Affichage dans l'app
743
+ # st.plotly_chart(fig)
744
 
745
 
746
  #---------------------------------------------------- Les 10 départements les plus touchés -----------------------------------------
747
 
748
+ # if page == "Exploration des données":
749
 
750
+ # # 🔎 Vérification rapide du DataFrame
751
+ # if "Département" not in df_merge.columns:
752
+ # st.error("❌ La colonne 'Département' est absente du DataFrame.")
753
+ # elif df_merge.empty:
754
+ # st.warning("⚠️ Le DataFrame est vide.")
755
+ # else:
756
+ # # ✅ Copie et nettoyage du DataFrame
757
+ # df_temp = df_merge.copy()
758
+ # df_temp = df_temp[df_temp['Département'].notna()] # Supprime les lignes sans département
759
 
760
+ # # 📊 Regroupement par département
761
+ # df_grouped = df_temp.groupby('Département').size().reset_index(name='nombre_feux')
762
 
763
+ # # 🔢 Total général
764
+ # total_feux = df_grouped['nombre_feux'].sum()
765
 
766
+ # # 🔝 Top 10 des départements
767
+ # df_top10 = df_grouped.sort_values(by='nombre_feux', ascending=False).head(10)
768
 
769
+ # # 📈 Calcul des proportions
770
+ # df_top10['proportion_totale'] = df_top10['nombre_feux'] / total_feux
771
 
772
+ # # 🥧 Création du graphique circulaire
773
+ # fig_pie = px.pie(
774
+ # df_top10,
775
+ # names='Département',
776
+ # values='nombre_feux',
777
+ # title='Les 10 départements les plus touchés (proportion sur le total global)',
778
+ # )
779
+ # fig_pie.update_traces(textinfo='label+percent')
780
 
781
+ # # 📌 Affichage dans l'app
782
+ # st.plotly_chart(fig_pie)
783
 
784
  #---------------------------------------------------- Carte des feux par département (2006-2024) ---------------------------------------------------------
785
 
786
+ # if page == "Exploration des données":
787
+ # st.subheader("Carte des feux par département (2006-2024)")
788
+
789
+ # # Copie du dataset
790
+ # df_temp = df_merge.copy()
791
+
792
+ # # Codes départements formatés
793
+ # df_temp['Département'] = df_temp['Département'].astype(str).str.zfill(2)
794
+ # df_grouped = df_temp.groupby('Département').size().reset_index(name='nombre_feux')
795
+
796
+ # # Chargement GeoJSON
797
+ # url_geojson = 'https://raw.githubusercontent.com/gregoiredavid/france-geojson/master/departements-version-simplifiee.geojson'
798
+ # with urllib.request.urlopen(url_geojson) as response:
799
+ # departements_geojson = json.load(response)
800
+
801
+ # # Carte choroplèthe
802
+ # fig = px.choropleth(
803
+ # df_grouped,
804
+ # geojson=departements_geojson,
805
+ # locations='Département',
806
+ # featureidkey='properties.code',
807
+ # color='nombre_feux',
808
+ # color_continuous_scale='OrRd',
809
+ # title='Total des feux par département (2006-2024)',
810
+ # labels={'nombre_feux': 'Feux'},
811
+ # )
812
+
813
+ # # Style géographique
814
+ # fig.update_geos(
815
+ # visible=False,
816
+ # lataxis_range=[41, 52],
817
+ # lonaxis_range=[-5.5, 10],
818
+ # showcountries=False,
819
+ # showcoastlines=False,
820
+ # showland=True,
821
+ # landcolor='white',
822
+ # fitbounds="locations"
823
+ # )
824
+
825
+ # # Mise en page
826
+ # fig.update_layout(
827
+ # template='plotly_white',
828
+ # width=1000,
829
+ # height=700,
830
+ # margin=dict(l=0, r=20, t=40, b=0),
831
+ # coloraxis_colorbar=dict(
832
+ # title="Feux",
833
+ # thickness=15,
834
+ # len=0.4,
835
+ # y=0.5
836
+ # )
837
+ # )
838
+
839
+ # # Affichage Streamlit
840
+ # st.plotly_chart(fig)
841
  #---------------------------------------------------- Les 10 départements avec le plus d’incendies -----------------------------------------
842
  # import plotly.graph_objects as go
843
 
844
  # -----------------------------------------------------------
845
  # 🔥 Top-10 des départements par nombre de feux – version GO
846
  # -----------------------------------------------------------
847
+ # if page == "Exploration des données":
848
+ # df_temp = df_merge.copy()
849
+ # df_temp["Département"] = df_temp["Département"].replace(
850
+ # {"2A": "2A/2B", "2B": "2A/2B"}
851
+ # )
852
+
853
+ # df_count = (
854
+ # df_temp.groupby("Département")
855
+ # .size()
856
+ # .reset_index(name="Nombre de feux")
857
+ # .sort_values("Nombre de feux", ascending=False)
858
+ # .head(10)
859
+ # )
860
+
861
+ # # ── Barres avec labels (Graph Objects)
862
+ # fig_top10_feux = go.Figure(
863
+ # data=go.Bar(
864
+ # x=df_count["Département"],
865
+ # y=df_count["Nombre de feux"],
866
+ # text=df_count["Nombre de feux"].apply(lambda x: f"{x:,}"),
867
+ # textposition="outside",
868
+ # textfont=dict(size=16, color="#2e2e2e"), # police foncée
869
+ # marker=dict(
870
+ # color="#627CFF",
871
+ # line=dict(color="black", width=1.5),
872
+ # ),
873
+ # )
874
+ # )
875
+
876
+ # # ── Mise en page inspirée de ta Fig 1
877
+ # fig_top10_feux.update_layout(
878
+ # title="🔥 Top 10 des départements avec le plus d’incendies",
879
+ # title_font_size=28,
880
+ # template="plotly_white", # fond clair + grille
881
+ # plot_bgcolor="rgba(245,248,255,1)",
882
+ # paper_bgcolor="rgba(245,248,255,1)",
883
+ # margin=dict(l=80, r=80, t=110, b=120),
884
+ # font=dict(size=18, color="#2e2e2e"), # police par défaut foncée
885
+ # xaxis=dict(
886
+ # title="Département",
887
+ # tickangle=-35,
888
+ # tickfont=dict(size=16),
889
+ # ),
890
+ # yaxis=dict(
891
+ # title="Nombre de feux",
892
+ # tickformat=",d",
893
+ # tickfont=dict(size=16),
894
+ # ),
895
+ # bargap=0.05,
896
+ # )
897
+
898
+ # st.plotly_chart(fig_top10_feux, use_container_width=True)
899
 
900
 
901
  #---------------------------------------------------- Page Résultats des modèles -----------------------------------------
images/Nathalie_Devogelaere.jpg ADDED

Git LFS Details

  • SHA256: 45a0ec6a6fc121d379a7d7c4e76c819142becbd4bf70c75f1f340ed84da68aa1
  • Pointer size: 130 Bytes
  • Size of remote file: 47.5 kB