Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -723,9 +723,9 @@ def generate_objective2_insights(df: pd.DataFrame) -> str:
|
|
| 723 |
|
| 724 |
# === RENDER INSIGHT BOX ===
|
| 725 |
# =============== INSIGHT 2 (Ringkas & Fokus ke Red & Amber) ===============
|
| 726 |
-
# =============== INSIGHT 3 (
|
| 727 |
|
| 728 |
-
#
|
| 729 |
required_cols = {'Alarm Status', 'hour', 'Position'}
|
| 730 |
if not required_cols.issubset(alarm_data.columns) or alarm_data.empty:
|
| 731 |
insight_lines = [
|
|
@@ -733,7 +733,7 @@ if not required_cols.issubset(alarm_data.columns) or alarm_data.empty:
|
|
| 733 |
"β’ Ensure dataset includes 'Alarm Status', 'hour', and 'Position' columns."
|
| 734 |
]
|
| 735 |
else:
|
| 736 |
-
# Filter Red & Amber β case-insensitive,
|
| 737 |
mask_red = alarm_data['Alarm Status'].str.contains(r'\bRed\b', case=False, na=False)
|
| 738 |
mask_amber = alarm_data['Alarm Status'].str.contains(r'\bAmber\b', case=False, na=False)
|
| 739 |
red_amber_data = alarm_data[mask_red | mask_amber].copy()
|
|
@@ -743,82 +743,68 @@ else:
|
|
| 743 |
else:
|
| 744 |
insight_lines = []
|
| 745 |
|
| 746 |
-
#
|
| 747 |
-
# β tanpa def, langsung vectorized
|
| 748 |
red_amber_data['is_red'] = mask_red.loc[red_amber_data.index]
|
| 749 |
red_amber_data['is_amber'] = mask_amber.loc[red_amber_data.index]
|
| 750 |
|
| 751 |
-
# Loop
|
| 752 |
for pos in [1, 2, 3, 4]:
|
| 753 |
-
# Filter by position
|
| 754 |
pos_data = red_amber_data[red_amber_data['Position'] == pos]
|
| 755 |
if pos_data.empty:
|
| 756 |
continue
|
| 757 |
|
| 758 |
-
# Band 1: 12:00β18:00 (
|
| 759 |
band1 = pos_data[(pos_data['hour'] >= 12) & (pos_data['hour'] <= 17)]
|
| 760 |
-
# Band 2: 18:00β00:00 (
|
| 761 |
band2 = pos_data[(pos_data['hour'] >= 18) | (pos_data['hour'] <= 5)]
|
| 762 |
|
| 763 |
-
#
|
| 764 |
if not band1.empty:
|
| 765 |
-
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
|
| 777 |
-
|
| 778 |
-
count = int(hour_counts.max())
|
| 779 |
-
insight_lines.append(f"β’ Position {pos}, 12:00β18:00: Peak Amber alarm at {peak_h:02d}:00 ({count} occurrences).")
|
| 780 |
-
|
| 781 |
-
# βββββ Band 2: 18:00β00:00 βββββ
|
| 782 |
if not band2.empty:
|
| 783 |
-
|
| 784 |
-
if not
|
| 785 |
-
|
| 786 |
-
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
| 791 |
-
|
| 792 |
-
|
| 793 |
-
|
| 794 |
-
|
| 795 |
-
|
| 796 |
-
|
| 797 |
-
# Jika insight_lines masih kosong (misal: semua alarm di pos 5+), tambahkan fallback
|
| 798 |
if not insight_lines:
|
| 799 |
insight_lines = ["β’ Red and Amber alarms occur outside standard wheel positions (1β4)."]
|
| 800 |
|
| 801 |
-
#
|
| 802 |
-
# Catatan: Ini bukan hasil komputasi, tapi insight profesional berdasarkan pola umum.
|
| 803 |
-
# Disesuaikan dengan preferensi: business-ready, actionable, tanpa spekulasi root cause.
|
| 804 |
-
|
| 805 |
-
# Cek apakah ada front tyre (pos 1/2) dan rear tyre (pos 3/4) Red/Amber
|
| 806 |
has_front_red = not red_amber_data[(red_amber_data['Position'].isin([1, 2])) & (red_amber_data['is_red'])].empty
|
| 807 |
has_rear_amber = not red_amber_data[(red_amber_data['Position'].isin([3, 4])) & (red_amber_data['is_amber'])].empty
|
| 808 |
|
| 809 |
if has_front_red or has_rear_amber:
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
insight_lines.append("")
|
| 816 |
-
insight_lines.append("Rear tyres:")
|
| 817 |
-
insight_lines.append("2. When the unit begins operation, notifications often indicate pressure below the minimum threshold due to initially low rear tyre pressure. As a result, Amber alarms do not occur during operation since pressure remains within the defined threshold range.")
|
| 818 |
|
| 819 |
-
#
|
| 820 |
insight_text = "\n".join(insight_lines)
|
| 821 |
|
|
|
|
|
|
|
| 822 |
st.markdown(f"""
|
| 823 |
<div class="insight-box">
|
| 824 |
<div class="content" style="
|
|
|
|
| 723 |
|
| 724 |
# === RENDER INSIGHT BOX ===
|
| 725 |
# =============== INSIGHT 2 (Ringkas & Fokus ke Red & Amber) ===============
|
| 726 |
+
# =============== INSIGHT 3 (Rata kiri, sesuai preferensi Aning) ===============
|
| 727 |
|
| 728 |
+
# βββββ Validasi data βββββ
|
| 729 |
required_cols = {'Alarm Status', 'hour', 'Position'}
|
| 730 |
if not required_cols.issubset(alarm_data.columns) or alarm_data.empty:
|
| 731 |
insight_lines = [
|
|
|
|
| 733 |
"β’ Ensure dataset includes 'Alarm Status', 'hour', and 'Position' columns."
|
| 734 |
]
|
| 735 |
else:
|
| 736 |
+
# Filter Red & Amber β case-insensitive, robust terhadap NaN
|
| 737 |
mask_red = alarm_data['Alarm Status'].str.contains(r'\bRed\b', case=False, na=False)
|
| 738 |
mask_amber = alarm_data['Alarm Status'].str.contains(r'\bAmber\b', case=False, na=False)
|
| 739 |
red_amber_data = alarm_data[mask_red | mask_amber].copy()
|
|
|
|
| 743 |
else:
|
| 744 |
insight_lines = []
|
| 745 |
|
| 746 |
+
# Tambahkan flag
|
|
|
|
| 747 |
red_amber_data['is_red'] = mask_red.loc[red_amber_data.index]
|
| 748 |
red_amber_data['is_amber'] = mask_amber.loc[red_amber_data.index]
|
| 749 |
|
| 750 |
+
# Loop tiap posisi roda (1β4)
|
| 751 |
for pos in [1, 2, 3, 4]:
|
|
|
|
| 752 |
pos_data = red_amber_data[red_amber_data['Position'] == pos]
|
| 753 |
if pos_data.empty:
|
| 754 |
continue
|
| 755 |
|
| 756 |
+
# Band 1: 12:00β18:00 (siang/sore)
|
| 757 |
band1 = pos_data[(pos_data['hour'] >= 12) & (pos_data['hour'] <= 17)]
|
| 758 |
+
# Band 2: 18:00β00:00 (sore/malam/dini hari)
|
| 759 |
band2 = pos_data[(pos_data['hour'] >= 18) | (pos_data['hour'] <= 5)]
|
| 760 |
|
| 761 |
+
# β Band 1 β
|
| 762 |
if not band1.empty:
|
| 763 |
+
red_sub = band1[band1['is_red']]
|
| 764 |
+
if not red_sub.empty:
|
| 765 |
+
h_peak = int(red_sub['hour'].value_counts().idxmax())
|
| 766 |
+
c_peak = int(red_sub['hour'].value_counts().max())
|
| 767 |
+
insight_lines.append(f"β’ Position {pos}, 12:00β18:00: Peak Red alarm at {h_peak:02d}:00 ({c_peak} occurrences).")
|
| 768 |
+
|
| 769 |
+
amber_sub = band1[band1['is_amber']]
|
| 770 |
+
if not amber_sub.empty:
|
| 771 |
+
h_peak = int(amber_sub['hour'].value_counts().idxmax())
|
| 772 |
+
c_peak = int(amber_sub['hour'].value_counts().max())
|
| 773 |
+
insight_lines.append(f"β’ Position {pos}, 12:00β18:00: Peak Amber alarm at {h_peak:02d}:00 ({c_peak} occurrences).")
|
| 774 |
+
|
| 775 |
+
# β Band 2 β
|
|
|
|
|
|
|
|
|
|
|
|
|
| 776 |
if not band2.empty:
|
| 777 |
+
red_sub = band2[band2['is_red']]
|
| 778 |
+
if not red_sub.empty:
|
| 779 |
+
h_peak = int(red_sub['hour'].value_counts().idxmax())
|
| 780 |
+
c_peak = int(red_sub['hour'].value_counts().max())
|
| 781 |
+
insight_lines.append(f"β’ Position {pos}, 18:00β00:00: Peak Red alarm at {h_peak:02d}:00 ({c_peak} occurrences).")
|
| 782 |
+
|
| 783 |
+
amber_sub = band2[band2['is_amber']]
|
| 784 |
+
if not amber_sub.empty:
|
| 785 |
+
h_peak = int(amber_sub['hour'].value_counts().idxmax())
|
| 786 |
+
c_peak = int(amber_sub['hour'].value_counts().max())
|
| 787 |
+
insight_lines.append(f"β’ Position {pos}, 18:00β00:00: Peak Amber alarm at {h_peak:02d}:00 ({c_peak} occurrences).")
|
| 788 |
+
|
| 789 |
+
# Jika tidak ada alarm di posisi 1β4
|
|
|
|
|
|
|
| 790 |
if not insight_lines:
|
| 791 |
insight_lines = ["β’ Red and Amber alarms occur outside standard wheel positions (1β4)."]
|
| 792 |
|
| 793 |
+
# βββββ Tambahkan insight naratif (sesuai contoh Anda) βββββ
|
|
|
|
|
|
|
|
|
|
|
|
|
| 794 |
has_front_red = not red_amber_data[(red_amber_data['Position'].isin([1, 2])) & (red_amber_data['is_red'])].empty
|
| 795 |
has_rear_amber = not red_amber_data[(red_amber_data['Position'].isin([3, 4])) & (red_amber_data['is_amber'])].empty
|
| 796 |
|
| 797 |
if has_front_red or has_rear_amber:
|
| 798 |
+
insight_lines.extend([
|
| 799 |
+
"β’ The front tyre pressure is high, close to threshold, with a small number of Red alarms. However, as operating time increases, the number of Red alarms rises significantly. Furthermore, during 04:00β06:00, operational slowdown likely occurs β leading to a decrease in Red alarm notifications.",
|
| 800 |
+
"β’ When the unit begins operation, notifications often indicate pressure below the minimum threshold due to initially low rear tyre pressure. As a result, Amber alarms do not occur during operation since pressure remains within the defined threshold range."
|
| 801 |
+
])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 802 |
|
| 803 |
+
# Gabungkan jadi satu string, tiap baris baru β \n
|
| 804 |
insight_text = "\n".join(insight_lines)
|
| 805 |
|
| 806 |
+
# βββββ TAMPILKAN (RATA KIRI) βββββ
|
| 807 |
+
st.markdown('<h4 style="text-align:center; margin:10px 0 5px 0; font-weight:bold;">INSIGHTS</h4>', unsafe_allow_html=True)
|
| 808 |
st.markdown(f"""
|
| 809 |
<div class="insight-box">
|
| 810 |
<div class="content" style="
|