Marcel0123 commited on
Commit
13c8514
·
verified ·
1 Parent(s): 4d75dac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +67 -25
app.py CHANGED
@@ -17,23 +17,26 @@ from sklearn.decomposition import PCA
17
  # ======================================================
18
  # DATA LADEN
19
  # ======================================================
20
- REQUIRED = {"survived","pclass","sex","age","sibsp","parch","fare","embarked"}
21
 
22
  def load_data(path="Titanic-Dataset.csv"):
23
  if not os.path.exists(path):
24
  raise FileNotFoundError("❌ Titanic-Dataset.csv niet gevonden in de rootmap.")
25
  df = pd.read_csv(path)
26
  df.columns = [c.lower().strip() for c in df.columns]
27
- missing = REQUIRED - set(df.columns)
28
- if missing:
29
- raise ValueError(f"Ontbrekende kolommen: {', '.join(sorted(missing))}")
 
30
  for c in df.columns:
31
  if df[c].isna().any():
32
  df[c] = df[c].fillna(df[c].mode()[0] if df[c].dtype=='O' else df[c].median())
 
33
  df["family_size"] = df["sibsp"] + df["parch"] + 1
34
  df["status"] = df["survived"].map({0:"Niet overleefd", 1:"Overleefd"})
35
- df["sex"] = df["sex"].astype(str).str.title()
36
- df["embarked"] = df["embarked"].astype(str).str.upper()
 
37
  return df
38
 
39
  df = load_data()
@@ -61,6 +64,46 @@ def make_plot(fig, title):
61
  )
62
  return fig
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  # ======================================================
65
  # MODELTRAINING + 2D VISUALISATIE
66
  # ======================================================
@@ -122,23 +165,18 @@ def train_and_embed_solid():
122
  INTRO_MD = """
123
  # 🛳️ Titanic Data Adventure
124
  ### Een datagedreven reis door hoop, hiërarchie en toeval
125
-
126
  **April 1912.**
127
  De RMS *Titanic* vertrekt richting New York: een drijvend paleis, gevuld met verwachtingen.
128
  Aan boord: industriëlen in avondkleding, jonge gezinnen met één koffer, bemanningsleden met routine.
129
  De zee is kalm; de toekomst lijkt maakbaar.
130
-
131
  Meer dan een eeuw later kijken wij mee — niet met verrekijkers of logboeken, maar met **data**.
132
  Elk record in deze dataset is een menselijk verhaal: iemand met een plek aan tafel, een ticket, een familie, een keuze.
133
  Door de gegevens te verkennen, begrijpen we beter **wie overleefde — en waarom**.
134
-
135
  ---
136
-
137
  ### ⚓ De nacht die geschiedenis werd
138
  Op **14 april 1912**, net voor middernacht, raakte de *Titanic* een **ijsberg** in de ijskoude Noord-Atlantische Oceaan.
139
  Binnen drie uur zonk het schip – het “onzinkbare” symbool van vooruitgang bleek kwetsbaar.
140
  Meer dan **1.500 mensen** kwamen om, slechts een derde van de opvarenden vond redding in de sloepen.
141
-
142
  De verdeling tussen rijk en arm, man en vrouw, jong en oud bleek letterlijk van levensbelang.
143
  In deze applicatie duiken we opnieuw die nacht in – niet met reddingsvesten, maar met grafieken, modellen en cijfers
144
  die het menselijk verhaal achter de ramp zichtbaar maken.
@@ -152,18 +190,14 @@ EXPLAIN_MD_SIDE = """
152
  Bij het opstarten traint de computer een **RandomForest-model** dat leert wie op de Titanic **overleefde** – en waarom.
153
  Het kijkt naar **klasse**, **geslacht**, **leeftijd**, **familieomvang**, **ticketprijs** en **haven van vertrek**.
154
  De nauwkeurigheid (bijv. *74%*) betekent: in 74 van de 100 gevallen voorspelt het model correct.
155
-
156
  ---
157
-
158
  ### 🗺️ Landkaart van passagiers
159
  Elk **bolletje** is één persoon. Met **PCA** brengen we veel kenmerken terug naar **2 dimensies**.
160
  - **Blauw** → overleefd
161
  - **Grijs** → niet overleefd
162
  - **Vorm** → klasse
163
  Dichter bij elkaar = vergelijkbare profielen. **Hover** voor details.
164
-
165
  ---
166
-
167
  ### 💬 Jij in dit verhaal
168
  Vul onderaan je **eigen profiel** in, ontdek jouw kans en lees je scène uit die nacht.
169
  """
@@ -214,11 +248,8 @@ def predict_and_story(pclass, sex, age, sibsp, parch, fare, embarked):
214
  tone, ending = ("Het ziet er somber uit.",
215
  "Je klampt je vast terwijl de oceaan meedogenloos wordt.")
216
  return f"""### 🔮 Jouw overlevingskans: **{pct:.1f}%**
217
-
218
  **Situatie:** {rol_txt}, **{klasse_txt} klasse**, inscheping **{haven_txt}** — leeftijd **{int(age)}**, familie **{int(sibsp)}+{int(parch)}** (totaal {int(sibsp)+int(parch)+1}), ticket **£{float(fare):.2f}**.
219
-
220
  **Analyse:** {tone} Het model weegt o.a. klasse, geslacht, leeftijd en familieomvang mee.
221
-
222
  **Avontuur:** De nacht is stil; fluiten, geroep, voetstappen. {ending}
223
  """
224
 
@@ -275,6 +306,9 @@ h1, h2, h3, h4 { color:#1B4B91; }
275
  .kpi .value { font-size:1.6rem; font-weight:800; color:#1B4B91; }
276
  .kpi .label { font-size:.9rem; color:#3F557A; }
277
  .explain-card { background:#EAF0FF; border-radius:12px; padding:18px; border:1px solid #D5E0FA; }
 
 
 
278
  """
279
 
280
  with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default(primary_hue="blue")) as demo:
@@ -287,6 +321,18 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default(primary_hue="blue")) as d
287
  if hp: gr.Image(value=hp, interactive=False, show_label=False, elem_classes=["hero-img"])
288
  else: gr.Markdown("⚠️ **Geen afbeelding gevonden.** Plaats `titanic_bg.png` of `titanic_bg.jpg` in de root.")
289
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  # Panel: status + 2D-plot links en uitleg rechts
291
  with gr.Column(elem_classes=["panel"]):
292
  gr.Markdown("## 🔧 Initialisatie & Modeltraining")
@@ -297,7 +343,7 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default(primary_hue="blue")) as d
297
  with gr.Column(scale=1, min_width=320):
298
  gr.Markdown(EXPLAIN_MD_SIDE, elem_classes=["explain-card"])
299
 
300
- # KPIs
301
  with gr.Row():
302
  gr.HTML(f"<div class='kpi'><div class='value'>{len(df):,}</div><div class='label'>Totaal passagiers</div></div>")
303
  gr.HTML(f"<div class='kpi'><div class='value'>{int(df['survived'].sum()):,}</div><div class='label'>Overlevenden</div></div>")
@@ -319,7 +365,6 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default(primary_hue="blue")) as d
319
  with gr.Column(scale=2, min_width=420):
320
  gr.Markdown("""## 🔮 Jouw scenario — bereken je overlevingskans en lees je scène
321
  Hier kun je ontdekken **hoe groot jouw kans op overleving** zou zijn geweest aan boord van de *Titanic* — en meteen het **verhaal van jouw nacht** lezen.
322
-
323
  1. **Kies je profiel**
324
  - **Klasse:** 1e, 2e of 3e klasse (je reiscomfort en dekpositie).
325
  - **Geslacht:** man of vrouw — dit had invloed op reddingsvoorrang.
@@ -327,14 +372,11 @@ Hier kun je ontdekken **hoe groot jouw kans op overleving** zou zijn geweest aan
327
  - **Broers/zussen** en **ouders/kinderen**: hoeveel familieleden reisden met je mee.
328
  - **Ticketprijs (£):** hoe duur je passage was.
329
  - **Vertrekhaven:** Cherbourg (C), Queenstown (Q) of Southampton (S).
330
-
331
  2. **Klik op de knop “🎲 Bereken én vertel mijn verhaal”**
332
  Het model schat jouw **overlevingskans** op basis van historische patronen.
333
-
334
  3. **Lees je persoonlijke scène**
335
  Onder de knop verschijnt een korte beschrijving die je meeneemt naar die nacht —
336
  gebaseerd op jouw ingevulde profiel en de berekende kans.
337
-
338
  > 💡 *De voorspelling is een statistische schatting, geen oordeel.
339
  > Ze helpt je zien hoe factoren zoals klasse, geslacht en leeftijd destijds iemands lot konden bepalen.*""")
340
  with gr.Column(scale=1, min_width=320):
@@ -352,11 +394,11 @@ Hier kun je ontdekken **hoe groot jouw kans op overleving** zou zijn geweest aan
352
  btn = gr.Button("🎲 Bereken én vertel mijn verhaal", variant="primary")
353
  story_out = gr.Markdown()
354
 
355
- # Loads & acties
356
  demo.load(fn=train_and_embed_solid, inputs=[], outputs=[status_md, train_plot])
357
  demo.load(lambda: (plot_age_hist(df), plot_gender(df), plot_fare_box(df)), inputs=[], outputs=[g2, g3, g4])
358
 
359
- # Initiele gauge (na modeltraining): gebruik de default UI-waarden
360
  demo.load(lambda: live_viz(2, "Man", 30, 1, 0, 50, "S"), inputs=[], outputs=[viz_plot])
361
 
362
  # Live updates bij elke wijziging
 
17
  # ======================================================
18
  # DATA LADEN
19
  # ======================================================
20
+ VEREISTE_KOLOMMEN = {"survived","pclass","sex","age","sibsp","parch","fare","embarked"}
21
 
22
  def load_data(path="Titanic-Dataset.csv"):
23
  if not os.path.exists(path):
24
  raise FileNotFoundError("❌ Titanic-Dataset.csv niet gevonden in de rootmap.")
25
  df = pd.read_csv(path)
26
  df.columns = [c.lower().strip() for c in df.columns]
27
+ ontbrekend = VEREISTE_KOLOMMEN - set(df.columns)
28
+ if ontbrekend:
29
+ raise ValueError(f"Ontbrekende kolommen: {', '.join(sorted(ontbrekend))}")
30
+ # Missende waarden invullen (modus voor categorisch, mediaan voor numeriek)
31
  for c in df.columns:
32
  if df[c].isna().any():
33
  df[c] = df[c].fillna(df[c].mode()[0] if df[c].dtype=='O' else df[c].median())
34
+ # Afgeleide kolommen
35
  df["family_size"] = df["sibsp"] + df["parch"] + 1
36
  df["status"] = df["survived"].map({0:"Niet overleefd", 1:"Overleefd"})
37
+ # Consistente casing (laat intern Engels voor model/plots; vertaling doen we alleen in de preview-tabel)
38
+ df["sex"] = df["sex"].astype(str).str.title() # 'Male'/'Female'
39
+ df["embarked"] = df["embarked"].astype(str).str.upper() # 'S'/'C'/'Q'
40
  return df
41
 
42
  df = load_data()
 
64
  )
65
  return fig
66
 
67
+ def maak_passagiers_preview(df_src: pd.DataFrame) -> pd.DataFrame:
68
+ """
69
+ Maakt een weergavetabel met Nederlandse kolomnamen/waarden (alleen voor tonen in de UI).
70
+ We wijzigen het originele df niet (het model gebruikt nog steeds de Engelse kolommen/waarden).
71
+ """
72
+ kolommen = ["pclass","sex","age","sibsp","parch","fare","embarked","family_size","status"]
73
+ optioneel = ["name","ticket","cabin"]
74
+ aanwezig_opt = [c for c in optioneel if c in df_src.columns]
75
+ selectie = kolommen + aanwezig_opt
76
+
77
+ d = df_src[selectie].copy()
78
+
79
+ # Waarde-vertalingen voor weergave
80
+ d["sex"] = d["sex"].map({"Male":"Man", "Female":"Vrouw"}).fillna(d["sex"])
81
+ d["embarked"] = d["embarked"].map({"S":"Southampton","C":"Cherbourg","Q":"Queenstown"}).fillna(d["embarked"])
82
+
83
+ # Kolomnamen naar NL
84
+ mapping = {
85
+ "pclass":"Klasse",
86
+ "sex":"Geslacht",
87
+ "age":"Leeftijd",
88
+ "sibsp":"Broers/Zussen",
89
+ "parch":"Ouders/Kinderen",
90
+ "fare":"Ticketprijs (£)",
91
+ "embarked":"Vertrekhaven",
92
+ "family_size":"Familieomvang",
93
+ "status":"Uitkomst",
94
+ "name":"Naam",
95
+ "ticket":"Ticket",
96
+ "cabin":"Hut",
97
+ }
98
+ d = d.rename(columns=mapping)
99
+
100
+ # Sorteer kolommen op een prettige volgorde
101
+ volgorde = [k for k in ["Naam","Klasse","Geslacht","Leeftijd","Familieomvang",
102
+ "Broers/Zussen","Ouders/Kinderen","Ticketprijs (£)",
103
+ "Vertrekhaven","Uitkomst","Ticket","Hut"] if k in d.columns]
104
+ d = d[volgorde]
105
+ return d.head(10)
106
+
107
  # ======================================================
108
  # MODELTRAINING + 2D VISUALISATIE
109
  # ======================================================
 
165
  INTRO_MD = """
166
  # 🛳️ Titanic Data Adventure
167
  ### Een datagedreven reis door hoop, hiërarchie en toeval
 
168
  **April 1912.**
169
  De RMS *Titanic* vertrekt richting New York: een drijvend paleis, gevuld met verwachtingen.
170
  Aan boord: industriëlen in avondkleding, jonge gezinnen met één koffer, bemanningsleden met routine.
171
  De zee is kalm; de toekomst lijkt maakbaar.
 
172
  Meer dan een eeuw later kijken wij mee — niet met verrekijkers of logboeken, maar met **data**.
173
  Elk record in deze dataset is een menselijk verhaal: iemand met een plek aan tafel, een ticket, een familie, een keuze.
174
  Door de gegevens te verkennen, begrijpen we beter **wie overleefde — en waarom**.
 
175
  ---
 
176
  ### ⚓ De nacht die geschiedenis werd
177
  Op **14 april 1912**, net voor middernacht, raakte de *Titanic* een **ijsberg** in de ijskoude Noord-Atlantische Oceaan.
178
  Binnen drie uur zonk het schip – het “onzinkbare” symbool van vooruitgang bleek kwetsbaar.
179
  Meer dan **1.500 mensen** kwamen om, slechts een derde van de opvarenden vond redding in de sloepen.
 
180
  De verdeling tussen rijk en arm, man en vrouw, jong en oud bleek letterlijk van levensbelang.
181
  In deze applicatie duiken we opnieuw die nacht in – niet met reddingsvesten, maar met grafieken, modellen en cijfers
182
  die het menselijk verhaal achter de ramp zichtbaar maken.
 
190
  Bij het opstarten traint de computer een **RandomForest-model** dat leert wie op de Titanic **overleefde** – en waarom.
191
  Het kijkt naar **klasse**, **geslacht**, **leeftijd**, **familieomvang**, **ticketprijs** en **haven van vertrek**.
192
  De nauwkeurigheid (bijv. *74%*) betekent: in 74 van de 100 gevallen voorspelt het model correct.
 
193
  ---
 
194
  ### 🗺️ Landkaart van passagiers
195
  Elk **bolletje** is één persoon. Met **PCA** brengen we veel kenmerken terug naar **2 dimensies**.
196
  - **Blauw** → overleefd
197
  - **Grijs** → niet overleefd
198
  - **Vorm** → klasse
199
  Dichter bij elkaar = vergelijkbare profielen. **Hover** voor details.
 
200
  ---
 
201
  ### 💬 Jij in dit verhaal
202
  Vul onderaan je **eigen profiel** in, ontdek jouw kans en lees je scène uit die nacht.
203
  """
 
248
  tone, ending = ("Het ziet er somber uit.",
249
  "Je klampt je vast terwijl de oceaan meedogenloos wordt.")
250
  return f"""### 🔮 Jouw overlevingskans: **{pct:.1f}%**
 
251
  **Situatie:** {rol_txt}, **{klasse_txt} klasse**, inscheping **{haven_txt}** — leeftijd **{int(age)}**, familie **{int(sibsp)}+{int(parch)}** (totaal {int(sibsp)+int(parch)+1}), ticket **£{float(fare):.2f}**.
 
252
  **Analyse:** {tone} Het model weegt o.a. klasse, geslacht, leeftijd en familieomvang mee.
 
253
  **Avontuur:** De nacht is stil; fluiten, geroep, voetstappen. {ending}
254
  """
255
 
 
306
  .kpi .value { font-size:1.6rem; font-weight:800; color:#1B4B91; }
307
  .kpi .label { font-size:.9rem; color:#3F557A; }
308
  .explain-card { background:#EAF0FF; border-radius:12px; padding:18px; border:1px solid #D5E0FA; }
309
+
310
+ /* Scrollbaar venster voor de passagierstabel */
311
+ #passenger_table { overflow:auto; max-height:250px; }
312
  """
313
 
314
  with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default(primary_hue="blue")) as demo:
 
321
  if hp: gr.Image(value=hp, interactive=False, show_label=False, elem_classes=["hero-img"])
322
  else: gr.Markdown("⚠️ **Geen afbeelding gevonden.** Plaats `titanic_bg.png` of `titanic_bg.jpg` in de root.")
323
 
324
+ # NIEUW PANEEL: Passagierslijst (eerste 10 rijen) — scrollbaar
325
+ with gr.Column(elem_classes=["panel"]):
326
+ gr.Markdown("## 👥 Passagierslijst — eerste 10 rijen van de dataset")
327
+ gr.DataFrame(
328
+ value=maak_passagiers_preview(df),
329
+ wrap=True,
330
+ interactive=False,
331
+ label="Titanic-passagiers (voorbeeld)",
332
+ elem_id="passenger_table",
333
+ max_height=250
334
+ )
335
+
336
  # Panel: status + 2D-plot links en uitleg rechts
337
  with gr.Column(elem_classes=["panel"]):
338
  gr.Markdown("## 🔧 Initialisatie & Modeltraining")
 
343
  with gr.Column(scale=1, min_width=320):
344
  gr.Markdown(EXPLAIN_MD_SIDE, elem_classes=["explain-card"])
345
 
346
+ # KPI-tegels
347
  with gr.Row():
348
  gr.HTML(f"<div class='kpi'><div class='value'>{len(df):,}</div><div class='label'>Totaal passagiers</div></div>")
349
  gr.HTML(f"<div class='kpi'><div class='value'>{int(df['survived'].sum()):,}</div><div class='label'>Overlevenden</div></div>")
 
365
  with gr.Column(scale=2, min_width=420):
366
  gr.Markdown("""## 🔮 Jouw scenario — bereken je overlevingskans en lees je scène
367
  Hier kun je ontdekken **hoe groot jouw kans op overleving** zou zijn geweest aan boord van de *Titanic* — en meteen het **verhaal van jouw nacht** lezen.
 
368
  1. **Kies je profiel**
369
  - **Klasse:** 1e, 2e of 3e klasse (je reiscomfort en dekpositie).
370
  - **Geslacht:** man of vrouw — dit had invloed op reddingsvoorrang.
 
372
  - **Broers/zussen** en **ouders/kinderen**: hoeveel familieleden reisden met je mee.
373
  - **Ticketprijs (£):** hoe duur je passage was.
374
  - **Vertrekhaven:** Cherbourg (C), Queenstown (Q) of Southampton (S).
 
375
  2. **Klik op de knop “🎲 Bereken én vertel mijn verhaal”**
376
  Het model schat jouw **overlevingskans** op basis van historische patronen.
 
377
  3. **Lees je persoonlijke scène**
378
  Onder de knop verschijnt een korte beschrijving die je meeneemt naar die nacht —
379
  gebaseerd op jouw ingevulde profiel en de berekende kans.
 
380
  > 💡 *De voorspelling is een statistische schatting, geen oordeel.
381
  > Ze helpt je zien hoe factoren zoals klasse, geslacht en leeftijd destijds iemands lot konden bepalen.*""")
382
  with gr.Column(scale=1, min_width=320):
 
394
  btn = gr.Button("🎲 Bereken én vertel mijn verhaal", variant="primary")
395
  story_out = gr.Markdown()
396
 
397
+ # Laden & acties
398
  demo.load(fn=train_and_embed_solid, inputs=[], outputs=[status_md, train_plot])
399
  demo.load(lambda: (plot_age_hist(df), plot_gender(df), plot_fare_box(df)), inputs=[], outputs=[g2, g3, g4])
400
 
401
+ # Initiële gauge (na modeltraining): gebruik de default UI-waarden
402
  demo.load(lambda: live_viz(2, "Man", 30, 1, 0, 50, "S"), inputs=[], outputs=[viz_plot])
403
 
404
  # Live updates bij elke wijziging