Spaces:
Sleeping
Sleeping
Update app.py
Browse files
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 |
-
#
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
#
|
| 728 |
-
|
| 729 |
-
|
| 730 |
-
|
| 731 |
-
|
| 732 |
-
|
| 733 |
-
|
| 734 |
-
|
| 735 |
-
|
| 736 |
-
|
| 737 |
-
|
| 738 |
-
|
| 739 |
-
|
| 740 |
-
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
|
| 744 |
-
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
|
| 752 |
-
|
| 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 |
-
|
| 1346 |
-
|
| 1347 |
|
| 1348 |
2. Alarm Distribution by Shift (Objective 2):
|
| 1349 |
-
|
| 1350 |
-
|
| 1351 |
-
|
| 1352 |
-
|
| 1353 |
|
| 1354 |
3. Correlation Analysis (Objective 3):
|
| 1355 |
-
|
| 1356 |
-
|
| 1357 |
-
|
| 1358 |
|
| 1359 |
4. Spatial Risk Mapping (Objective 4):
|
| 1360 |
-
|
| 1361 |
-
|
| 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"
|
|
|
|
| 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)
|