sony9316 commited on
Commit
17ba015
·
verified ·
1 Parent(s): e44926f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -51
app.py CHANGED
@@ -168,29 +168,31 @@ def create_threshold_analysis(df, thresholds, scope="all"):
168
  df = load_data()
169
 
170
  # ========== MAIN DASHBOARD ==========
171
- st.markdown('<h1 class="main-header">🚗 Getaround Delay Analysis</h1>', unsafe_allow_html=True)
172
 
173
- # Sidebar
174
  with st.sidebar:
175
- st.markdown("## 🎛️ Analysis Controls")
 
 
176
 
177
  selected = option_menu(
178
  "Analysis Focus",
179
- ["📊 Overview & Problems", "🎯 Threshold & Scope"],
180
- icons=["bar-chart", "target"],
181
- menu_icon="cast",
182
  default_index=0,
183
  )
184
 
185
- if selected == "🎯 Threshold & Scope":
186
- st.markdown("### Controls")
187
- threshold = st.slider("🕐 Threshold (minutes)", 0, 300, 90, step=30,
188
  help="Minimum delay between consecutive rentals")
189
- scope = st.selectbox("🚗 Scope", ["all", "connect"],
190
  format_func=lambda x: "All Cars" if x == "all" else "Connect Cars Only")
191
 
192
  st.markdown("---")
193
- st.markdown("### 📈 Dataset Info")
194
  st.info(f"""
195
  **Total Rentals:** {len(df):,}
196
  **Connect Rentals:** {len(df[df['checkin_type'].str.lower() == 'connect']):,}
@@ -199,11 +201,11 @@ with st.sidebar:
199
  """)
200
 
201
  # ========== PAGE 1: OVERVIEW & PROBLEMS ==========
202
- if selected == "📊 Overview & Problems":
203
- st.title("📊 Understanding the Delay Problem")
204
 
205
  # Dataset Overview
206
- st.markdown('<div class="section-header">📈 Dataset Overview</div>', unsafe_allow_html=True)
207
 
208
  col1, col2, col3, col4 = st.columns(4)
209
  with col1:
@@ -243,7 +245,7 @@ if selected == "📊 Overview & Problems":
243
  st.plotly_chart(fig_state, use_container_width=True)
244
 
245
  # Key Problem Analysis
246
- st.markdown('<div class="section-header">🚨 Current Problem Scope</div>', unsafe_allow_html=True)
247
 
248
  # Calculate current problems
249
  df_problems = df[df["has_previous_rental"]].copy()
@@ -290,7 +292,7 @@ if selected == "📊 Overview & Problems":
290
  """, unsafe_allow_html=True)
291
 
292
  # Visual analysis
293
- st.markdown('<div class="section-header">📈 Delay Patterns</div>', unsafe_allow_html=True)
294
 
295
  col1, col2 = st.columns(2)
296
 
@@ -324,7 +326,7 @@ if selected == "📊 Overview & Problems":
324
  st.plotly_chart(fig_hist, use_container_width=True)
325
 
326
  # Gap analysis
327
- st.markdown('<div class="section-header">📏 Time Gaps Between Rentals</div>', unsafe_allow_html=True)
328
 
329
  gap_data = df[df["has_previous_rental"]]
330
  gap_filtered = gap_data[gap_data["time_delta_with_previous_rental_in_minutes"].between(0, 480)]
@@ -339,7 +341,7 @@ if selected == "📊 Overview & Problems":
339
  st.plotly_chart(fig_gap, use_container_width=True)
340
 
341
  # Cancellation analysis
342
- st.markdown('<div class="section-header">Cancellation Impact</div>', unsafe_allow_html=True)
343
 
344
  col1, col2 = st.columns(2)
345
 
@@ -371,8 +373,8 @@ if selected == "📊 Overview & Problems":
371
  st.plotly_chart(fig_cancel, use_container_width=True)
372
 
373
  # ========== PAGE 2: THRESHOLD & SCOPE ANALYSIS ==========
374
- elif selected == "🎯 Threshold & Scope":
375
- st.title("🎯 Threshold & Scope Decision")
376
 
377
  st.markdown("""
378
  <div class="insight-box">
@@ -385,7 +387,7 @@ elif selected == "🎯 Threshold & Scope":
385
  # Current impact
386
  current_metrics = calculate_metrics(df, threshold, scope)
387
 
388
- st.markdown('<div class="section-header">📊 Impact at Current Settings</div>', unsafe_allow_html=True)
389
 
390
  col1, col2, col3, col4 = st.columns(4)
391
  with col1:
@@ -429,7 +431,7 @@ elif selected == "🎯 Threshold & Scope":
429
  st.caption("Formula: blocked_rentals / total_rentals * 100")
430
 
431
  # Threshold analysis
432
- st.markdown('<div class="section-header">📈 Threshold Analysis</div>', unsafe_allow_html=True)
433
 
434
  thresholds = list(range(0, 301, 30))
435
  threshold_data = create_threshold_analysis(df, thresholds, scope)
@@ -481,7 +483,7 @@ elif selected == "🎯 Threshold & Scope":
481
  st.plotly_chart(fig, use_container_width=True)
482
 
483
  # Scope comparison
484
- st.markdown('<div class="section-header">🚗 Scope Comparison: All Cars vs Connect Only</div>', unsafe_allow_html=True)
485
 
486
  all_metrics = calculate_metrics(df, threshold, "all")
487
  connect_metrics = calculate_metrics(df, threshold, "connect")
@@ -489,7 +491,7 @@ elif selected == "🎯 Threshold & Scope":
489
  col1, col2 = st.columns(2)
490
 
491
  with col1:
492
- st.markdown("### 🚗 All Cars")
493
  st.markdown(f"""
494
  **Problems Solved:** {all_metrics['problems_solved']:,}
495
  **Blocked Rentals:** {all_metrics['blocked_rentals']:,} ({all_metrics['blocked_percentage']:.1f}%)
@@ -498,7 +500,7 @@ elif selected == "🎯 Threshold & Scope":
498
  """)
499
 
500
  with col2:
501
- st.markdown("### 🔌 Connect Cars Only")
502
  st.markdown(f"""
503
  **Problems Solved:** {connect_metrics['problems_solved']:,}
504
  **Blocked Rentals:** {connect_metrics['blocked_rentals']:,} ({connect_metrics['blocked_percentage']:.1f}%)
@@ -511,45 +513,58 @@ elif selected == "🎯 Threshold & Scope":
511
  connect_data = create_threshold_analysis(df, thresholds, "connect")
512
 
513
  fig_scope = go.Figure()
514
- fig_scope.add_trace(go.Scatter(x=all_data["threshold"], y=all_data["problems_solved"],
515
- mode="lines+markers", name="All Cars - Problems Solved"))
516
- fig_scope.add_trace(go.Scatter(x=connect_data["threshold"], y=connect_data["problems_solved"],
517
- mode="lines+markers", name="Connect Only - Problems Solved"))
 
 
 
 
 
518
  fig_scope.add_vline(x=threshold, line_dash="dash", line_color="red",
519
  annotation_text=f"Current: {threshold}min")
520
- fig_scope.update_layout(title="Problems Solved by Scope",
521
  xaxis_title="Threshold (minutes)",
522
- yaxis_title="Problems Solved")
523
  st.plotly_chart(fig_scope, use_container_width=True)
524
 
525
  # Recommendations
526
- st.markdown('<div class="section-header">💡 Recommendations</div>', unsafe_allow_html=True)
527
 
528
- # Find optimal threshold
529
  viable_thresholds = threshold_data[
530
  (threshold_data["problems_solved"] > 0) &
531
  (threshold_data["threshold"] >= 30) &
532
- (threshold_data["threshold"] <= 120) # More reasonable max
533
  ]
534
 
535
  if len(viable_thresholds) > 0:
536
- # Find sweet spot: solve at least 80% of max problems with reasonable efficiency
537
- max_problems = viable_thresholds["problems_solved"].max()
538
- good_options = viable_thresholds[viable_thresholds["problems_solved"] >= max_problems * 0.8]
539
 
540
- if len(good_options) > 0:
541
- # Among good options, pick the one with best efficiency and lowest revenue loss
542
- good_options["combined_score"] = (
543
- good_options["solve_efficiency"] / 100 * 0.6 + # 60% weight on efficiency
544
- (100 - good_options["revenue_loss_percent"]) / 100 * 0.4 # 40% weight on low revenue loss
545
- )
546
- optimal = good_options.sort_values("combined_score", ascending=False).iloc[0]
 
 
 
 
 
 
 
547
  else:
548
- optimal = viable_thresholds.sort_values(["problems_solved", "solve_efficiency"], ascending=[False, False]).iloc[0]
 
549
 
550
  optimal_threshold = int(optimal["threshold"])
551
  else:
552
- optimal_threshold = 60 # Sensible fallback
553
 
554
  # Scope recommendation
555
  if connect_metrics['solve_efficiency'] > all_metrics['solve_efficiency'] and connect_metrics['problems_solved'] >= all_metrics['problems_solved'] * 0.7:
@@ -564,17 +579,17 @@ elif selected == "🎯 Threshold & Scope":
564
  with col1:
565
  st.markdown(f"""
566
  <div class="recommendation-box">
567
- <h3>🎯 Recommended Threshold</h3>
568
  <h2>{optimal_threshold} minutes</h2>
569
  <p>Balances problem solving with availability impact</p>
570
- <small>Logic: Solve ≥80% of max problems with best efficiency/revenue trade-off</small>
571
  </div>
572
  """, unsafe_allow_html=True)
573
 
574
  with col2:
575
  st.markdown(f"""
576
  <div class="recommendation-box">
577
- <h3>🚗 Recommended Scope</h3>
578
  <h2>{recommended_scope}</h2>
579
  <p>{scope_reason}</p>
580
  <small>Logic: Compare efficiency and problems solved between all cars vs connect only</small>
@@ -582,7 +597,7 @@ elif selected == "🎯 Threshold & Scope":
582
  """, unsafe_allow_html=True)
583
 
584
  # Summary table
585
- st.markdown("### 📋 Key Threshold Options")
586
  summary_thresholds = [60, 90, 120, 150]
587
  summary_data = []
588
 
@@ -604,6 +619,6 @@ elif selected == "🎯 Threshold & Scope":
604
  st.markdown("---")
605
  st.markdown("""
606
  <div style='text-align: center; color: #666; padding: 1rem;'>
607
- <p>🚗 <strong>Getaround Delay Analysis</strong> - Supporting threshold and scope decisions</p>
608
  </div>
609
  """, unsafe_allow_html=True)
 
168
  df = load_data()
169
 
170
  # ========== MAIN DASHBOARD ==========
171
+ st.markdown('<h1 class="main-header">Getaround Delay Analysis</h1>', unsafe_allow_html=True)
172
 
173
+ # Sidebar with controls
174
  with st.sidebar:
175
+ st.image("Getaround_logo.png", width=200)
176
+
177
+ st.markdown("## Analysis Controls")
178
 
179
  selected = option_menu(
180
  "Analysis Focus",
181
+ ["Overview & Problems", "Threshold & Scope"],
182
+ icons=["graph-up", "sliders"], # More professional icons
183
+ menu_icon="house-gear",
184
  default_index=0,
185
  )
186
 
187
+ if selected == "Threshold & Scope":
188
+ st.markdown("### Settings")
189
+ threshold = st.slider("Threshold (minutes)", 0, 300, 90, step=30,
190
  help="Minimum delay between consecutive rentals")
191
+ scope = st.selectbox("Implementation Scope", ["all", "connect"],
192
  format_func=lambda x: "All Cars" if x == "all" else "Connect Cars Only")
193
 
194
  st.markdown("---")
195
+ st.markdown("### Dataset Summary")
196
  st.info(f"""
197
  **Total Rentals:** {len(df):,}
198
  **Connect Rentals:** {len(df[df['checkin_type'].str.lower() == 'connect']):,}
 
201
  """)
202
 
203
  # ========== PAGE 1: OVERVIEW & PROBLEMS ==========
204
+ if selected == "Overview & Problems":
205
+ st.title("Understanding the Delay Problem")
206
 
207
  # Dataset Overview
208
+ st.markdown('<div class="section-header">Dataset Overview</div>', unsafe_allow_html=True)
209
 
210
  col1, col2, col3, col4 = st.columns(4)
211
  with col1:
 
245
  st.plotly_chart(fig_state, use_container_width=True)
246
 
247
  # Key Problem Analysis
248
+ st.markdown('<div class="section-header">Current Problem Scope</div>', unsafe_allow_html=True)
249
 
250
  # Calculate current problems
251
  df_problems = df[df["has_previous_rental"]].copy()
 
292
  """, unsafe_allow_html=True)
293
 
294
  # Visual analysis
295
+ st.markdown('<div class="section-header">Delay Patterns</div>', unsafe_allow_html=True)
296
 
297
  col1, col2 = st.columns(2)
298
 
 
326
  st.plotly_chart(fig_hist, use_container_width=True)
327
 
328
  # Gap analysis
329
+ st.markdown('<div class="section-header">Time Gaps Between Rentals</div>', unsafe_allow_html=True)
330
 
331
  gap_data = df[df["has_previous_rental"]]
332
  gap_filtered = gap_data[gap_data["time_delta_with_previous_rental_in_minutes"].between(0, 480)]
 
341
  st.plotly_chart(fig_gap, use_container_width=True)
342
 
343
  # Cancellation analysis
344
+ st.markdown('<div class="section-header">Cancellation Impact</div>', unsafe_allow_html=True)
345
 
346
  col1, col2 = st.columns(2)
347
 
 
373
  st.plotly_chart(fig_cancel, use_container_width=True)
374
 
375
  # ========== PAGE 2: THRESHOLD & SCOPE ANALYSIS ==========
376
+ elif selected == "Threshold & Scope":
377
+ st.title("Threshold & Scope Decision")
378
 
379
  st.markdown("""
380
  <div class="insight-box">
 
387
  # Current impact
388
  current_metrics = calculate_metrics(df, threshold, scope)
389
 
390
+ st.markdown('<div class="section-header">Impact at Current Settings</div>', unsafe_allow_html=True)
391
 
392
  col1, col2, col3, col4 = st.columns(4)
393
  with col1:
 
431
  st.caption("Formula: blocked_rentals / total_rentals * 100")
432
 
433
  # Threshold analysis
434
+ st.markdown('<div class="section-header">Threshold Analysis</div>', unsafe_allow_html=True)
435
 
436
  thresholds = list(range(0, 301, 30))
437
  threshold_data = create_threshold_analysis(df, thresholds, scope)
 
483
  st.plotly_chart(fig, use_container_width=True)
484
 
485
  # Scope comparison
486
+ st.markdown('<div class="section-header">Scope Comparison: All Cars vs Connect Only</div>', unsafe_allow_html=True)
487
 
488
  all_metrics = calculate_metrics(df, threshold, "all")
489
  connect_metrics = calculate_metrics(df, threshold, "connect")
 
491
  col1, col2 = st.columns(2)
492
 
493
  with col1:
494
+ st.markdown("### All Cars")
495
  st.markdown(f"""
496
  **Problems Solved:** {all_metrics['problems_solved']:,}
497
  **Blocked Rentals:** {all_metrics['blocked_rentals']:,} ({all_metrics['blocked_percentage']:.1f}%)
 
500
  """)
501
 
502
  with col2:
503
+ st.markdown("### Connect Cars Only")
504
  st.markdown(f"""
505
  **Problems Solved:** {connect_metrics['problems_solved']:,}
506
  **Blocked Rentals:** {connect_metrics['blocked_rentals']:,} ({connect_metrics['blocked_percentage']:.1f}%)
 
513
  connect_data = create_threshold_analysis(df, thresholds, "connect")
514
 
515
  fig_scope = go.Figure()
516
+
517
+ # Calculate percentage of problems solved for fair comparison
518
+ all_data["problems_solved_percent"] = (all_data["problems_solved"] / all_data["current_problems"].iloc[0] * 100).fillna(0)
519
+ connect_data["problems_solved_percent"] = (connect_data["problems_solved"] / connect_data["current_problems"].iloc[0] * 100).fillna(0)
520
+
521
+ fig_scope.add_trace(go.Scatter(x=all_data["threshold"], y=all_data["problems_solved_percent"],
522
+ mode="lines+markers", name="All Cars - % Problems Solved"))
523
+ fig_scope.add_trace(go.Scatter(x=connect_data["threshold"], y=connect_data["problems_solved_percent"],
524
+ mode="lines+markers", name="Connect Only - % Problems Solved"))
525
  fig_scope.add_vline(x=threshold, line_dash="dash", line_color="red",
526
  annotation_text=f"Current: {threshold}min")
527
+ fig_scope.update_layout(title="Percentage of Problems Solved by Scope",
528
  xaxis_title="Threshold (minutes)",
529
+ yaxis_title="% of Problems Solved")
530
  st.plotly_chart(fig_scope, use_container_width=True)
531
 
532
  # Recommendations
533
+ st.markdown('<div class="section-header">Recommendations</div>', unsafe_allow_html=True)
534
 
535
+ # Find optimal threshold - look for efficiency/revenue loss crossover point
536
  viable_thresholds = threshold_data[
537
  (threshold_data["problems_solved"] > 0) &
538
  (threshold_data["threshold"] >= 30) &
539
+ (threshold_data["threshold"] <= 150)
540
  ]
541
 
542
  if len(viable_thresholds) > 0:
543
+ # Find crossover point where efficiency starts declining and revenue loss increases significantly
544
+ # Look for the "knee" where efficiency curve meets revenue loss curve
545
+ viable_thresholds = viable_thresholds.sort_values("threshold")
546
 
547
+ # Normalize both metrics to 0-100 scale for comparison
548
+ viable_thresholds["efficiency_norm"] = viable_thresholds["solve_efficiency"]
549
+ viable_thresholds["revenue_loss_norm"] = viable_thresholds["revenue_loss_percent"]
550
+
551
+ # Find point where efficiency is still high but revenue loss hasn't grown too much
552
+ # Look for threshold where efficiency > 20% and revenue loss < 8%
553
+ good_balance = viable_thresholds[
554
+ (viable_thresholds["efficiency_norm"] >= 20) &
555
+ (viable_thresholds["revenue_loss_norm"] <= 8.0)
556
+ ]
557
+
558
+ if len(good_balance) > 0:
559
+ # Among balanced options, pick the one that solves most problems
560
+ optimal = good_balance.sort_values("problems_solved", ascending=False).iloc[0]
561
  else:
562
+ # Fallback: find best efficiency among viable options
563
+ optimal = viable_thresholds.sort_values("solve_efficiency", ascending=False).iloc[0]
564
 
565
  optimal_threshold = int(optimal["threshold"])
566
  else:
567
+ optimal_threshold = 90 # Sensible fallback
568
 
569
  # Scope recommendation
570
  if connect_metrics['solve_efficiency'] > all_metrics['solve_efficiency'] and connect_metrics['problems_solved'] >= all_metrics['problems_solved'] * 0.7:
 
579
  with col1:
580
  st.markdown(f"""
581
  <div class="recommendation-box">
582
+ <h3>Recommended Threshold</h3>
583
  <h2>{optimal_threshold} minutes</h2>
584
  <p>Balances problem solving with availability impact</p>
585
+ <small>Logic: Find crossover point where efficiency ≥20% and revenue loss ≤8%</small>
586
  </div>
587
  """, unsafe_allow_html=True)
588
 
589
  with col2:
590
  st.markdown(f"""
591
  <div class="recommendation-box">
592
+ <h3>Recommended Scope</h3>
593
  <h2>{recommended_scope}</h2>
594
  <p>{scope_reason}</p>
595
  <small>Logic: Compare efficiency and problems solved between all cars vs connect only</small>
 
597
  """, unsafe_allow_html=True)
598
 
599
  # Summary table
600
+ st.markdown("### Key Threshold Options")
601
  summary_thresholds = [60, 90, 120, 150]
602
  summary_data = []
603
 
 
619
  st.markdown("---")
620
  st.markdown("""
621
  <div style='text-align: center; color: #666; padding: 1rem;'>
622
+ <p><strong>Getaround Delay Analysis</strong> - Supporting threshold and scope decisions</p>
623
  </div>
624
  """, unsafe_allow_html=True)