Marcel0123 commited on
Commit
a1a3e12
·
verified ·
1 Parent(s): f9c2e0a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +166 -16
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py — Titanic Data Adventure (alleen blauwe tekst, zonder zwart/vetgedrukt)
2
 
3
  import gradio as gr
4
  import pandas as pd
@@ -117,23 +117,23 @@ def train_and_embed_solid():
117
  return status, fig
118
 
119
  # ======================================================
120
- # TEKSTEN (alleen blauwe kleur, geen vet of zwart)
121
  # ======================================================
122
  INTRO_MD = """
123
  <span style='color:#1B4B91'>
124
- April 1912.
125
- De RMS Titanic vertrekt richting New York: een drijvend paleis, gevuld met verwachtingen.
126
- Aan boord: industriëlen in avondkleding, jonge gezinnen met één koffer, bemanningsleden met routine.
127
- De zee is kalm; de toekomst lijkt maakbaar. Meer dan een eeuw later kijken wij mee — niet met verrekijkers of logboeken, maar met data.
128
- Elk record in deze dataset is een menselijk verhaal: iemand met een plek aan tafel, een ticket, een familie, een keuze.
129
  Door de gegevens te verkennen, begrijpen we beter wie overleefde — en waarom.
130
  </span>
131
  """
132
 
133
  EXPLAIN_MD_SIDE = """
134
  <span style='color:#1B4B91'>
135
- Bij het opstarten traint de computer een RandomForest-model dat leert wie op de Titanic overleefde – en waarom.
136
- Het kijkt naar klasse, geslacht, leeftijd, familieomvang, ticketprijs en haven van vertrek.
137
  De nauwkeurigheid (bijv. 74%) betekent: in 74 van de 100 gevallen voorspelt het model correct.
138
  </span>
139
  """
@@ -156,6 +156,78 @@ def plot_fare_box(dfx):
156
  color_discrete_map={"Overleefd":"#1B4B91","Niet overleefd":"#A3B1C6"})
157
  return make_plot(f, "Ticketprijs per klasse (met overleving)")
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  # ======================================================
160
  # UI + LAYOUT
161
  # ======================================================
@@ -165,21 +237,41 @@ body { background:#FFFFFF; color:#0B1C3F; }
165
  h1, h2, h3, h4 { color:#1B4B91; }
166
  .panel, .intro-card { background:#F9FBFF; border:1px solid #E0E6F3; border-radius:12px; padding:16px; }
167
  .hero-img img { border-radius:12px; border:1px solid #E0E6F3; }
 
 
 
 
 
168
  """
169
 
170
  with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default(primary_hue="blue")) as demo:
 
171
  with gr.Row():
172
  with gr.Column(scale=2, min_width=420):
173
- gr.Markdown(INTRO_MD, elem_classes=["intro-card"], unsafe_allow_html=True)
 
174
  with gr.Column(scale=1, min_width=320):
175
  hp = hero_path()
176
- if hp:
177
  gr.Image(value=hp, interactive=False, show_label=False, elem_classes=["hero-img"])
178
- else:
179
  gr.Markdown("⚠️ **Geen afbeelding gevonden.** Plaats `titanic_bg.png` of `titanic_bg.jpg` in de root.")
180
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  gr.Markdown("")
182
 
 
183
  with gr.Column(elem_classes=["panel"]):
184
  gr.Markdown("## 🔧 Initialisatie & Modeltraining")
185
  status_md = gr.Markdown("⏳ Initialiseren…")
@@ -187,13 +279,17 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default(primary_hue="blue")) as d
187
  with gr.Column(scale=2, min_width=420):
188
  train_plot = gr.Plot(label="2D-projectie — elk bolletje is een passagier")
189
  with gr.Column(scale=1, min_width=320):
190
- gr.Markdown(EXPLAIN_MD_SIDE, elem_classes=["explain-card"], unsafe_allow_html=True)
 
191
 
 
192
  with gr.Row():
193
- gr.HTML(f"<div style='color:#1B4B91;'><strong>Totaal passagiers:</strong> {len(df):,}</div>")
194
- gr.HTML(f"<div style='color:#1B4B91;'><strong>Overlevenden:</strong> {int(df['survived'].sum()):,}</div>")
195
- gr.HTML(f"<div style='color:#1B4B91;'><strong>Percentage overleefd:</strong> {df['survived'].mean()*100:.1f}%</div>")
 
196
 
 
197
  gr.Markdown("## 📊 Verken de data", elem_classes=["panel"])
198
  with gr.Row():
199
  g2 = gr.Plot(label="Leeftijdsverdeling per status")
@@ -201,7 +297,61 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default(primary_hue="blue")) as d
201
  with gr.Row():
202
  g4 = gr.Plot(label="Ticketprijs per klasse")
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  demo.load(fn=train_and_embed_solid, inputs=[], outputs=[status_md, train_plot])
205
  demo.load(lambda: (plot_age_hist(df), plot_gender(df), plot_fare_box(df)), inputs=[], outputs=[g2, g3, g4])
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  demo.launch()
 
1
+ # app.py — Titanic Data Adventure (met uitgebreide introductie naast foto)
2
 
3
  import gradio as gr
4
  import pandas as pd
 
117
  return status, fig
118
 
119
  # ======================================================
120
+ # TEKSTBLOKKEN ALLEEN BLAUW, GEEN ZWART/GEEN VET
121
  # ======================================================
122
  INTRO_MD = """
123
  <span style='color:#1B4B91'>
124
+ April 1912.<br>
125
+ De RMS Titanic vertrekt richting New York: een drijvend paleis, gevuld met verwachtingen.<br>
126
+ Aan boord: industriëlen in avondkleding, jonge gezinnen met één koffer, bemanningsleden met routine.<br>
127
+ De zee is kalm; de toekomst lijkt maakbaar. Meer dan een eeuw later kijken wij mee — niet met verrekijkers of logboeken, maar met data.<br>
128
+ Elk record in deze dataset is een menselijk verhaal: iemand met een plek aan tafel, een ticket, een familie, een keuze.<br>
129
  Door de gegevens te verkennen, begrijpen we beter wie overleefde — en waarom.
130
  </span>
131
  """
132
 
133
  EXPLAIN_MD_SIDE = """
134
  <span style='color:#1B4B91'>
135
+ Bij het opstarten traint de computer een RandomForest-model dat leert wie op de Titanic overleefde – en waarom.<br>
136
+ Het kijkt naar klasse, geslacht, leeftijd, familieomvang, ticketprijs en haven van vertrek.<br>
137
  De nauwkeurigheid (bijv. 74%) betekent: in 74 van de 100 gevallen voorspelt het model correct.
138
  </span>
139
  """
 
156
  color_discrete_map={"Overleefd":"#1B4B91","Niet overleefd":"#A3B1C6"})
157
  return make_plot(f, "Ticketprijs per klasse (met overleving)")
158
 
159
+ # ======================================================
160
+ # INTERACTIEVE VOORSPELLING
161
+ # ======================================================
162
+ def predict_and_story(pclass, sex, age, sibsp, parch, fare, embarked):
163
+ if MODEL is None:
164
+ return "⏳ Het model initialiseert nog. Probeer het zo nog eens."
165
+ X_row = pd.DataFrame([{
166
+ "pclass": int(pclass), "sex": sex, "age": float(age),
167
+ "sibsp": int(sibsp), "parch": int(parch), "fare": float(fare),
168
+ "embarked": embarked, "family_size": int(sibsp)+int(parch)+1
169
+ }])
170
+ prob = float(MODEL.predict_proba(X_row)[0,1]); pct = prob*100
171
+ klasse_txt = {1:"eerste",2:"tweede",3:"derde"}[int(pclass)]
172
+ haven_txt = {"C":"Cherbourg","Q":"Queenstown","S":"Southampton"}[embarked]
173
+ rol_txt = "vrouw" if sex.lower().startswith("v") else "man"
174
+ if pct>=75:
175
+ tone, ending = ("Je kansen zijn uitzonderlijk goed.",
176
+ "Je bereikt de sloep; het schip helt achter je, maar je leeft.")
177
+ elif pct>=50:
178
+ tone, ending = ("Je kansen zijn behoorlijk goed.",
179
+ "In de chaos vind je een plek in een halfgevulde sloep.")
180
+ elif pct>=25:
181
+ tone, ending = ("De kansen zijn fifty-fifty.",
182
+ "Op het laatste moment spring je; de nacht is lang, maar de horizon gloeit.")
183
+ else:
184
+ tone, ending = ("Het ziet er somber uit.",
185
+ "Je klampt je vast terwijl de oceaan meedogenloos wordt.")
186
+ return f"""### 🔮 Jouw overlevingskans: **{pct:.1f}%**
187
+ **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}**.
188
+ **Analyse:** {tone} Het model weegt o.a. klasse, geslacht, leeftijd en familieomvang mee.
189
+ **Avontuur:** De nacht is stil; fluiten, geroep, voetstappen. {ending}
190
+ """
191
+
192
+ # ======================================================
193
+ # LIVE GAUGE VOOR JOUW SCENARIO (met kleurbanden + threshold)
194
+ # ======================================================
195
+ def live_viz(pclass, sex, age, sibsp, parch, fare, embarked):
196
+ # Retourneer een gauge die live de kans toont (0–100%) met kleurbanden
197
+ if MODEL is None:
198
+ return make_plot(go.Figure(), "Jouw overlevingskans (live)")
199
+ X_row = pd.DataFrame([{
200
+ "pclass": int(pclass), "sex": sex, "age": float(age),
201
+ "sibsp": int(sibsp), "parch": int(parch), "fare": float(fare),
202
+ "embarked": embarked, "family_size": int(sibsp)+int(parch)+1
203
+ }])
204
+ prob = float(MODEL.predict_proba(X_row)[0,1]) * 100.0
205
+
206
+ fig = go.Figure(go.Indicator(
207
+ mode="gauge+number",
208
+ value=prob,
209
+ number={"suffix": "%", "valueformat": ".1f"},
210
+ gauge={
211
+ "axis": {"range": [0, 100]},
212
+ "bar": {"thickness": 0.25},
213
+ # Kleurbanden (0–25 rood, 25–50 oranje, 50–75 geel, 75–100 groen)
214
+ "steps": [
215
+ {"range": [0, 25], "color": "#FDECEC"},
216
+ {"range": [25, 50], "color": "#FFF2E0"},
217
+ {"range": [50, 75], "color": "#FFF9D6"},
218
+ {"range": [75, 100], "color": "#E8F6EA"},
219
+ ],
220
+ # Threshold-lijn op actuele waarde
221
+ "threshold": {
222
+ "line": {"color": "#1B4B91", "width": 4},
223
+ "thickness": 0.9,
224
+ "value": prob
225
+ },
226
+ },
227
+ title={"text": "Jouw overlevingskans (live)"}
228
+ ))
229
+ return make_plot(fig, "Jouw overlevingskans (live)")
230
+
231
  # ======================================================
232
  # UI + LAYOUT
233
  # ======================================================
 
237
  h1, h2, h3, h4 { color:#1B4B91; }
238
  .panel, .intro-card { background:#F9FBFF; border:1px solid #E0E6F3; border-radius:12px; padding:16px; }
239
  .hero-img img { border-radius:12px; border:1px solid #E0E6F3; }
240
+ .kpi { display:flex; flex-direction:column; align-items:center; justify-content:center;
241
+ background:#FFFFFF; border:1px solid #E0E6F3; border-radius:12px; padding:14px; }
242
+ .kpi .value { font-size:1.6rem; font-weight:800; color:#1B4B91; }
243
+ .kpi .label { font-size:.9rem; color:#3F557A; }
244
+ .explain-card { background:#EAF0FF; border-radius:12px; padding:18px; border:1px solid #D5E0FA; }
245
  """
246
 
247
  with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Default(primary_hue="blue")) as demo:
248
+ # Header-intro + foto
249
  with gr.Row():
250
  with gr.Column(scale=2, min_width=420):
251
+ # Alleen blauwe tekst (HTML inline), geen vet/zwart
252
+ gr.Markdown(INTRO_MD, elem_classes=["intro-card"])
253
  with gr.Column(scale=1, min_width=320):
254
  hp = hero_path()
255
+ if hp:
256
  gr.Image(value=hp, interactive=False, show_label=False, elem_classes=["hero-img"])
257
+ else:
258
  gr.Markdown("⚠️ **Geen afbeelding gevonden.** Plaats `titanic_bg.png` of `titanic_bg.jpg` in de root.")
259
 
260
+ # Passagierslijst — volledige dataset, scrollbaar
261
+ with gr.Column(elem_classes=["panel"]):
262
+ gr.Markdown("## 👥 Passagierslijst — volledige dataset (scrollbaar)")
263
+ gr.DataFrame(
264
+ value=df, # volledige dataset
265
+ wrap=True,
266
+ interactive=False, # alleen-lezen
267
+ label="Titanic-passagiers",
268
+ max_height=320 # vaste hoogte -> scroll binnen de tabel
269
+ )
270
+
271
+ # Spacer om overlap te voorkomen
272
  gr.Markdown("")
273
 
274
+ # Panel: status + 2D-plot links en uitleg rechts
275
  with gr.Column(elem_classes=["panel"]):
276
  gr.Markdown("## 🔧 Initialisatie & Modeltraining")
277
  status_md = gr.Markdown("⏳ Initialiseren…")
 
279
  with gr.Column(scale=2, min_width=420):
280
  train_plot = gr.Plot(label="2D-projectie — elk bolletje is een passagier")
281
  with gr.Column(scale=1, min_width=320):
282
+ # Alleen blauwe tekst (HTML inline), geen vet/zwart
283
+ gr.Markdown(EXPLAIN_MD_SIDE, elem_classes=["explain-card"])
284
 
285
+ # KPIs
286
  with gr.Row():
287
+ gr.HTML(f"<div class='kpi'><div class='value'>{len(df):,}</div><div class='label'>Totaal passagiers</div></div>")
288
+ gr.HTML(f"<div class='kpi'><div class='value'>{int(df['survived'].sum()):,}</div><div class='label'>Overlevenden</div></div>")
289
+ gr.HTML(f"<div class='kpi'><div class='value'>{df['survived'].mean()*100:.1f}%</div><div class='label'>% Overleefd</div></div>")
290
+ gr.HTML(f"<div class='kpi'><div class='value'>{', '.join(map(str, sorted(df['pclass'].unique())))}</div><div class='label'>Klassen</div></div>")
291
 
292
+ # Overige visualisaties
293
  gr.Markdown("## 📊 Verken de data", elem_classes=["panel"])
294
  with gr.Row():
295
  g2 = gr.Plot(label="Leeftijdsverdeling per status")
 
297
  with gr.Row():
298
  g4 = gr.Plot(label="Ticketprijs per klasse")
299
 
300
+ # Interactieve voorspelling
301
+ with gr.Column(elem_classes=["panel"]):
302
+ # Tekstblok + gauge naast elkaar
303
+ with gr.Row():
304
+ with gr.Column(scale=2, min_width=420):
305
+ gr.Markdown("""## 🔮 Jouw scenario — bereken je overlevingskans en lees je scène
306
+ 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.
307
+ 1. **Kies je profiel**
308
+ - **Klasse:** 1e, 2e of 3e klasse (je reiscomfort en dekpositie).
309
+ - **Geslacht:** man of vrouw — dit had invloed op reddingsvoorrang.
310
+ - **Leeftijd:** jouw leeftijd in jaren.
311
+ - **Broers/zussen** en **ouders/kinderen**: hoeveel familieleden reisden met je mee.
312
+ - **Ticketprijs (£):** hoe duur je passage was.
313
+ - **Vertrekhaven:** Cherbourg (C), Queenstown (Q) of Southampton (S).
314
+ 2. **Klik op de knop “🎲 Bereken én vertel mijn verhaal”**
315
+ Het model schat jouw **overlevingskans** op basis van historische patronen.
316
+ 3. **Lees je persoonlijke scène**
317
+ Onder de knop verschijnt een korte beschrijving die je meeneemt naar die nacht —
318
+ gebaseerd op jouw ingevulde profiel en de berekende kans.
319
+ > 💡 *De voorspelling is een statistische schatting, geen oordeel.
320
+ > Ze helpt je zien hoe factoren zoals klasse, geslacht en leeftijd destijds iemands lot konden bepalen.*""")
321
+ with gr.Column(scale=1, min_width=320):
322
+ viz_plot = gr.Plot(label="Jouw overlevingskans (live)")
323
+
324
+ with gr.Row():
325
+ ui_pclass = gr.Slider(1, 3, value=2, step=1, label="Klasse (1=1e, 3=3e)")
326
+ ui_sex = gr.Radio(["Man","Vrouw"], value="Man", label="Geslacht")
327
+ ui_age = gr.Slider(0, 80, value=30, label="Leeftijd")
328
+ with gr.Row():
329
+ ui_sibsp = gr.Slider(0, 8, value=1, step=1, label="Broers/Zussen aan boord")
330
+ ui_parch = gr.Slider(0, 6, value=0, step=1, label="Ouders/Kinder(en) aan boord")
331
+ ui_fare = gr.Slider(0, 600, value=50, label="Ticketprijs (£)")
332
+ ui_emb = gr.Radio(["C","Q","S"], value="S", label="Vertrekhaven")
333
+ btn = gr.Button("🎲 Bereken én vertel mijn verhaal", variant="primary")
334
+ story_out = gr.Markdown()
335
+
336
+ # Loads & acties
337
  demo.load(fn=train_and_embed_solid, inputs=[], outputs=[status_md, train_plot])
338
  demo.load(lambda: (plot_age_hist(df), plot_gender(df), plot_fare_box(df)), inputs=[], outputs=[g2, g3, g4])
339
 
340
+ # Initiele gauge (na modeltraining): gebruik de default UI-waarden
341
+ demo.load(lambda: live_viz(2, "Man", 30, 1, 0, 50, "S"), inputs=[], outputs=[viz_plot])
342
+
343
+ # Live updates bij elke wijziging
344
+ for comp in [ui_pclass, ui_sex, ui_age, ui_sibsp, ui_parch, ui_fare, ui_emb]:
345
+ comp.change(live_viz,
346
+ inputs=[ui_pclass, ui_sex, ui_age, ui_sibsp, ui_parch, ui_fare, ui_emb],
347
+ outputs=viz_plot)
348
+
349
+ # Ook updaten bij de knop
350
+ btn.click(predict_and_story,
351
+ inputs=[ui_pclass, ui_sex, ui_age, ui_sibsp, ui_parch, ui_fare, ui_emb],
352
+ outputs=story_out)
353
+ btn.click(live_viz,
354
+ inputs=[ui_pclass, ui_sex, ui_age, ui_sibsp, ui_parch, ui_fare, ui_emb],
355
+ outputs=viz_plot)
356
+
357
  demo.launch()