SHELLAPANDIANGANHUNGING commited on
Commit
da3a740
Β·
verified Β·
1 Parent(s): 6627432

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -102
app.py CHANGED
@@ -679,7 +679,7 @@ with col8:
679
  else:
680
  st.warning("No data for Position 4 (18:00–06:00)")
681
 
682
- # =============== INSIGHT 2 (Ringkas) ===============
683
  if alarm_data.empty:
684
  insight_text = "β€’ No data available for analysis."
685
  else:
@@ -710,97 +710,47 @@ else:
710
 
711
  # Insight Spesifik Per Position dan Shift
712
  insight_lines = [
713
- f""
 
714
  ]
715
 
716
- # Position 1 (Shift Pagi)
717
- pos1_pagi = alarm_data[(alarm_data['Position'] == 1) & (alarm_data['hour'].between(6, 17, inclusive='both'))]
718
- if not pos1_pagi.empty:
719
- pos1_pagi_total = pos1_pagi.groupby('hour').size()
720
- if not pos1_pagi_total.empty:
721
- dominant_hour_p1_pagi = pos1_pagi_total.idxmax()
722
- dominant_count_p1_pagi = pos1_pagi_total.max()
723
- insight_lines.append(f"β€’ Position 1 Shift 1 (06:00–18:00): Peak at {dominant_hour_p1_pagi:02d}:00 ({dominant_count_p1_pagi} alarms)")
724
- # # Position 1 (Shift Sore)
725
- # pos1_sore = alarm_data[(alarm_data['Position'] == 1) & (~alarm_data['hour'].between(6, 17, inclusive='both'))]
726
- # if not pos1_sore.empty:
727
- # pos1_sore_red = pos1_sore[pos1_sore['Alarm Status'].str.contains('Red', na=False)]
728
- # if not pos1_sore_red.empty:
729
- # red_percentage_p1_sore = (len(pos1_sore_red) / len(pos1_sore)) * 100
730
- # insight_lines.append(f"β€’ Position 1 Shift 2 (18:00–06:00): {red_percentage_p1_sore:.1f}% are Red alarms")
731
- pos1_pagi = alarm_data[(alarm_data['Position'] == 1) & (alarm_data['hour'].between(18, 24, inclusive='both'))]
732
- if not pos1_pagi.empty:
733
- pos1_pagi_total = pos1_pagi.groupby('hour').size()
734
- if not pos1_pagi_total.empty:
735
- dominant_hour_p1_pagi = pos1_pagi_total.idxmax()
736
- dominant_count_p1_pagi = pos1_pagi_total.max()
737
- insight_lines.append(f"β€’ Position 1 Shift 2 (18:00–00:00): Peak at {dominant_hour_p1_pagi:02d}:00 ({dominant_count_p1_pagi} alarms)")
738
- # Position 1 (Shift Pagi)
739
- pos1_pagi = alarm_data[(alarm_data['Position'] == 2) & (alarm_data['hour'].between(6, 17, inclusive='both'))]
740
- if not pos1_pagi.empty:
741
- pos1_pagi_total = pos1_pagi.groupby('hour').size()
742
- if not pos1_pagi_total.empty:
743
- dominant_hour_p1_pagi = pos1_pagi_total.idxmax()
744
- dominant_count_p1_pagi = pos1_pagi_total.max()
745
- insight_lines.append(f"β€’ Position 2 Shift 1 (06:00–18:00): Peak at {dominant_hour_p1_pagi:02d}:00 ({dominant_count_p1_pagi} alarms)")
746
- # # Position 1 (Shift Sore)
747
- # pos1_sore = alarm_data[(alarm_data['Position'] == 1) & (~alarm_data['hour'].between(6, 17, inclusive='both'))]
748
- # if not pos1_sore.empty:
749
- # pos1_sore_red = pos1_sore[pos1_sore['Alarm Status'].str.contains('Red', na=False)]
750
- # if not pos1_sore_red.empty:
751
- # red_percentage_p1_sore = (len(pos1_sore_red) / len(pos1_sore)) * 100
752
- # insight_lines.append(f"β€’ Position 1 Shift 2 (18:00–06:00): {red_percentage_p1_sore:.1f}% are Red alarms")
753
- pos1_pagi = alarm_data[(alarm_data['Position'] == 2) & (alarm_data['hour'].between(18, 24, inclusive='both'))]
754
- if not pos1_pagi.empty:
755
- pos1_pagi_total = pos1_pagi.groupby('hour').size()
756
- if not pos1_pagi_total.empty:
757
- dominant_hour_p1_pagi = pos1_pagi_total.idxmax()
758
- dominant_count_p1_pagi = pos1_pagi_total.max()
759
- insight_lines.append(f"β€’ Position 2 Shift 2 (18:00–00:00): Peak at {dominant_hour_p1_pagi:02d}:00 ({dominant_count_p1_pagi} alarms)")
760
- # Position 1 (Shift Pagi)
761
- pos1_pagi = alarm_data[(alarm_data['Position'] == 3) & (alarm_data['hour'].between(6, 17, inclusive='both'))]
762
- if not pos1_pagi.empty:
763
- pos1_pagi_total = pos1_pagi.groupby('hour').size()
764
- if not pos1_pagi_total.empty:
765
- dominant_hour_p1_pagi = pos1_pagi_total.idxmax()
766
- dominant_count_p1_pagi = pos1_pagi_total.max()
767
- insight_lines.append(f"β€’ Position 3 Shift 1 (06:00–18:00): Peak at {dominant_hour_p1_pagi:02d}:00 ({dominant_count_p1_pagi} alarms)")
768
- # # Position 1 (Shift Sore)
769
- # pos1_sore = alarm_data[(alarm_data['Position'] == 1) & (~alarm_data['hour'].between(6, 17, inclusive='both'))]
770
- # if not pos1_sore.empty:
771
- # pos1_sore_red = pos1_sore[pos1_sore['Alarm Status'].str.contains('Red', na=False)]
772
- # if not pos1_sore_red.empty:
773
- # red_percentage_p1_sore = (len(pos1_sore_red) / len(pos1_sore)) * 100
774
- # insight_lines.append(f"β€’ Position 1 Shift 2 (18:00–06:00): {red_percentage_p1_sore:.1f}% are Red alarms")
775
- pos1_pagi = alarm_data[(alarm_data['Position'] == 3) & (alarm_data['hour'].between(18, 24, inclusive='both'))]
776
- if not pos1_pagi.empty:
777
- pos1_pagi_total = pos1_pagi.groupby('hour').size()
778
- if not pos1_pagi_total.empty:
779
- dominant_hour_p1_pagi = pos1_pagi_total.idxmax()
780
- dominant_count_p1_pagi = pos1_pagi_total.max()
781
- insight_lines.append(f"β€’ Position 3 Shift 2 (18:00–00:00): Peak at {dominant_hour_p1_pagi:02d}:00 ({dominant_count_p1_pagi} alarms)")
782
- # Position 1 (Shift Pagi)
783
- pos1_pagi = alarm_data[(alarm_data['Position'] == 4) & (alarm_data['hour'].between(6, 17, inclusive='both'))]
784
- if not pos1_pagi.empty:
785
- pos1_pagi_total = pos1_pagi.groupby('hour').size()
786
- if not pos1_pagi_total.empty:
787
- dominant_hour_p1_pagi = pos1_pagi_total.idxmax()
788
- dominant_count_p1_pagi = pos1_pagi_total.max()
789
- insight_lines.append(f"β€’ Position 4 Shift 1 (06:00–18:00): Peak at {dominant_hour_p1_pagi:02d}:00 ({dominant_count_p1_pagi} alarms)")
790
- # # Position 1 (Shift Sore)
791
- # pos1_sore = alarm_data[(alarm_data['Position'] == 1) & (~alarm_data['hour'].between(6, 17, inclusive='both'))]
792
- # if not pos1_sore.empty:
793
- # pos1_sore_red = pos1_sore[pos1_sore['Alarm Status'].str.contains('Red', na=False)]
794
- # if not pos1_sore_red.empty:
795
- # red_percentage_p1_sore = (len(pos1_sore_red) / len(pos1_sore)) * 100
796
- # insight_lines.append(f"β€’ Position 1 Shift 2 (18:00–06:00): {red_percentage_p1_sore:.1f}% are Red alarms")
797
- pos1_pagi = alarm_data[(alarm_data['Position'] == 4) & (alarm_data['hour'].between(18, 24, inclusive='both'))]
798
- if not pos1_pagi.empty:
799
- pos1_pagi_total = pos1_pagi.groupby('hour').size()
800
- if not pos1_pagi_total.empty:
801
- dominant_hour_p1_pagi = pos1_pagi_total.idxmax()
802
- dominant_count_p1_pagi = pos1_pagi_total.max()
803
- insight_lines.append(f"β€’ Position 4 Shift 2 (18:00–00:00): Peak at {dominant_hour_p1_pagi:02d}:00 ({dominant_count_p1_pagi} alarms)")
804
  insight_text = "\n".join(insight_lines)
805
 
806
  # =============== DISPLAY INSIGHT ===============
@@ -1261,6 +1211,7 @@ st.markdown(f"""
1261
  # ================= OBJECTIVE 5 =================
1262
  # ================= OBJECTIVE 5 =================
1263
  # ================= OBJECTIVE 5 =================
 
1264
  st.markdown('<h3 class="objective-title">OBJECTIVE 5: Insights & Mitigation β€” How Can Red Pressure Alarms Be Reduced?</h3>', unsafe_allow_html=True)
1265
 
1266
  # --- DATA PREP ---
@@ -1342,23 +1293,23 @@ else:
1342
  # Insight dari Objective 1-4
1343
  insight_text = f"""
1344
  1. Pressure & Temperature Distribution (Objective 1):
1345
- Front tyres (Pos 1 & 2) show lower pressure ({front_pressure_avg:.1f} psi) and higher temperature ({front_temp_avg:.1f}Β°C) due to higher stress from braking/steering.
1346
- Rear tyres (Pos 3 & 4) show higher pressure ({front_pressure_avg + 19.1:.1f} psi) and lower temperature ({front_temp_avg - 5.3:.1f}Β°C), indicating stable operation.
1347
 
1348
  2. Alarm Distribution by Shift (Objective 2):
1349
- Position 1 (06:00–18:00): Dominant alarm at {dominant_hour}:00 with {hourly_counts[dominant_hour]} alarms.
1350
- Position 1 (18:00–06:00): Red alarms account for {(len(pos1_sore[pos1_sore['Alarm Status'].str.contains('Red', na=False)]) / len(pos1_sore)) * 100:.1f}% of total alarms.
1351
- Position 3 (06:00–18:00): Dominant alarm at {dominant_hour}:00 with {hourly_counts[dominant_hour]} alarms.
1352
- Position 3 (18:00–06:00): Amber alarms account for {(len(pos3_sore[pos3_sore['Alarm Status'].str.contains('Amber', na=False)]) / len(pos3_sore)) * 100:.1f}% of total alarms.
1353
 
1354
  3. Correlation Analysis (Objective 3):
1355
- Strong correlation between temperature and pressure in front tyres (r = {corr_front:.2f}) vs rear (r = {corr_rear:.2f}).
1356
- At temperatures β‰₯52Β°C, front tyres trigger {red_high_pressure_count} Red High Pressure alarms.
1357
- Pressure vs (T/v) shows weak correlation (r = {corr_p_tv_front:.2f}), suggesting speed alone is not primary heat factor.
1358
 
1359
  4. Spatial Risk Mapping (Objective 4):
1360
- Alarm concentration is highest in {top_zone_obj4}, with {top_zone_count_obj4} alarms representing {percentage_obj4:.1f}% of total alarms.
1361
- Front tyres account for {front_percentage_obj4:.1f}% of all alarms, indicating higher alarm occurrence compared to rear tyres.
1362
  """
1363
 
1364
  try:
@@ -1432,8 +1383,10 @@ except:
1432
  st.markdown('<h4 style="text-align:left; margin:10px 0 5px 0; font-weight:bold;">INSIGHT</h4>', unsafe_allow_html=True)
1433
  st.markdown(f"""
1434
  <div class="insight-box">
1435
- <div class="content" style="text-align:left;">
 
1436
  {insight_text.strip()}
 
1437
  </div>
1438
  </div>
1439
  """, unsafe_allow_html=True)
 
679
  else:
680
  st.warning("No data for Position 4 (18:00–06:00)")
681
 
682
+ # =============== INSIGHT 2 (Ringkas & Fokus ke Red & Amber) ===============
683
  if alarm_data.empty:
684
  insight_text = "β€’ No data available for analysis."
685
  else:
 
710
 
711
  # Insight Spesifik Per Position dan Shift
712
  insight_lines = [
713
+ f"β€’ Total alarms: Normal={normal_alarms}, Amber={amber_alarms}, Red={red_alarms}",
714
+ f"β€’ Dominant period: {dominant_band} ({dominant_pct:.1f}%), Second: {second_dominant_band} ({second_pct:.1f}%)"
715
  ]
716
 
717
+ # Fungsi helper untuk mencari jam dengan count maksimum untuk alarm Red/Amber
718
+ def get_max_alarm_hour(pos_data, alarm_type):
719
+ filtered_data = pos_data[pos_data['Alarm Status'].str.contains(alarm_type, na=False)]
720
+ if not filtered_data.empty:
721
+ hourly_counts = filtered_data.groupby('hour').size()
722
+ if not hourly_counts.empty:
723
+ max_hour = hourly_counts.idxmax()
724
+ max_count = hourly_counts.max()
725
+ return max_hour, max_count
726
+ return None, 0
727
+
728
+ # Loop untuk semua Position (1, 2, 3, 4)
729
+ for pos in [1, 2, 3, 4]:
730
+ # Shift Pagi (06:00–17:59)
731
+ pos_pagi = alarm_data[(alarm_data['Position'] == pos) & (alarm_data['hour'].between(6, 17, inclusive='both'))]
732
+ if not pos_pagi.empty:
733
+ # Cari jam dengan alarm Red maksimum
734
+ red_hour, red_count = get_max_alarm_hour(pos_pagi, 'Red')
735
+ if red_hour is not None:
736
+ insight_lines.append(f"β€’ Position {pos} Shift 1 (06:00–18:00): Peak Red alarm at {red_hour:02d}:00 ({red_count} alarms)")
737
+ # Cari jam dengan alarm Amber maksimum
738
+ amber_hour, amber_count = get_max_alarm_hour(pos_pagi, 'Amber')
739
+ if amber_hour is not None:
740
+ insight_lines.append(f"β€’ Position {pos} Shift 1 (06:00–18:00): Peak Amber alarm at {amber_hour:02d}:00 ({amber_count} alarms)")
741
+
742
+ # Shift Sore (18:00–05:59)
743
+ pos_sore = alarm_data[(alarm_data['Position'] == pos) & ((alarm_data['hour'] >= 18) | (alarm_data['hour'] <= 5))]
744
+ if not pos_sore.empty:
745
+ # Cari jam dengan alarm Red maksimum
746
+ red_hour, red_count = get_max_alarm_hour(pos_sore, 'Red')
747
+ if red_hour is not None:
748
+ insight_lines.append(f"β€’ Position {pos} Shift 2 (18:00–06:00): Peak Red alarm at {red_hour:02d}:00 ({red_count} alarms)")
749
+ # Cari jam dengan alarm Amber maksimum
750
+ amber_hour, amber_count = get_max_alarm_hour(pos_sore, 'Amber')
751
+ if amber_hour is not None:
752
+ insight_lines.append(f"β€’ Position {pos} Shift 2 (18:00–06:00): Peak Amber alarm at {amber_hour:02d}:00 ({amber_count} alarms)")
753
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
754
  insight_text = "\n".join(insight_lines)
755
 
756
  # =============== DISPLAY INSIGHT ===============
 
1211
  # ================= OBJECTIVE 5 =================
1212
  # ================= OBJECTIVE 5 =================
1213
  # ================= OBJECTIVE 5 =================
1214
+ # ================= OBJECTIVE 5 =================
1215
  st.markdown('<h3 class="objective-title">OBJECTIVE 5: Insights & Mitigation β€” How Can Red Pressure Alarms Be Reduced?</h3>', unsafe_allow_html=True)
1216
 
1217
  # --- DATA PREP ---
 
1293
  # Insight dari Objective 1-4
1294
  insight_text = f"""
1295
  1. Pressure & Temperature Distribution (Objective 1):
1296
+ Front tyres (Pos 1 & 2) show lower pressure ({front_pressure_avg:.1f} psi) and higher temperature ({front_temp_avg:.1f}Β°C) due to higher stress from braking/steering.
1297
+ Rear tyres (Pos 3 & 4) show higher pressure ({front_pressure_avg + 19.1:.1f} psi) and lower temperature ({front_temp_avg - 5.3:.1f}Β°C), indicating stable operation.
1298
 
1299
  2. Alarm Distribution by Shift (Objective 2):
1300
+ Position 1 (06:00–18:00): Dominant alarm at {dominant_hour}:00 with {hourly_counts[dominant_hour]} alarms.
1301
+ Position 1 (18:00–06:00): Red alarms account for {(len(pos1_sore[pos1_sore['Alarm Status'].str.contains('Red', na=False)]) / len(pos1_sore)) * 100:.1f}% of total alarms.
1302
+ Position 3 (06:00–18:00): Dominant alarm at {dominant_hour}:00 with {hourly_counts[dominant_hour]} alarms.
1303
+ Position 3 (18:00–06:00): Amber alarms account for {(len(pos3_sore[pos3_sore['Alarm Status'].str.contains('Amber', na=False)]) / len(pos3_sore)) * 100:.1f}% of total alarms.
1304
 
1305
  3. Correlation Analysis (Objective 3):
1306
+ Strong correlation between temperature and pressure in front tyres (r = {corr_front:.2f}) vs rear (r = {corr_rear:.2f}).
1307
+ At temperatures β‰₯52Β°C, front tyres trigger {red_high_pressure_count} Red High Pressure alarms.
1308
+ Pressure vs (T/v) shows weak correlation (r = {corr_p_tv_front:.2f}), suggesting speed alone is not primary heat factor.
1309
 
1310
  4. Spatial Risk Mapping (Objective 4):
1311
+ Alarm concentration is highest in {top_zone_obj4}, with {top_zone_count_obj4} alarms representing {percentage_obj4:.1f}% of total alarms.
1312
+ Front tyres account for {front_percentage_obj4:.1f}% of all alarms, indicating higher alarm occurrence compared to rear tyres.
1313
  """
1314
 
1315
  try:
 
1383
  st.markdown('<h4 style="text-align:left; margin:10px 0 5px 0; font-weight:bold;">INSIGHT</h4>', unsafe_allow_html=True)
1384
  st.markdown(f"""
1385
  <div class="insight-box">
1386
+ <div class="content">
1387
+ <div style="text-align:left; white-space: pre-line;">
1388
  {insight_text.strip()}
1389
+ </div>
1390
  </div>
1391
  </div>
1392
  """, unsafe_allow_html=True)