Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -725,7 +725,7 @@ st.markdown(f"""
|
|
| 725 |
# """, unsafe_allow_html=True)
|
| 726 |
st.markdown("""
|
| 727 |
<h3 class="objective-title">OBJECTIVE 3: Alarm Frequency Analysis — When, Where, and Which Tyres Matter Most?</h3>
|
| 728 |
-
<small>*Showing all alarm types: Normal (Green),
|
| 729 |
""", unsafe_allow_html=True)
|
| 730 |
|
| 731 |
# Filter semua data (termasuk alarm normal)
|
|
@@ -744,7 +744,7 @@ with col_b:
|
|
| 744 |
alarm_data['Alarm_Category'] = alarm_data['Alarm Status'].apply(
|
| 745 |
lambda x: 'Normal' if x == 'No Alarm'
|
| 746 |
else 'Red Alarm' if x == 'Red High Pressure'
|
| 747 |
-
else 'Amber Alarm'
|
| 748 |
)
|
| 749 |
|
| 750 |
# Buat 4 donut chart
|
|
@@ -796,9 +796,9 @@ with col_b:
|
|
| 796 |
)
|
| 797 |
st.plotly_chart(fig_donut, use_container_width=True)
|
| 798 |
|
| 799 |
-
# =============== COL A: Radial Charts (Count Alarm per Jam -
|
| 800 |
with col_a:
|
| 801 |
-
st.markdown('<h5 style="text-align:center; margin-top: 0;">Alarm Count by Hour (Radial)</h5>', unsafe_allow_html=True)
|
| 802 |
|
| 803 |
if alarm_data.empty:
|
| 804 |
st.warning("No data to display.")
|
|
@@ -814,29 +814,53 @@ with col_a:
|
|
| 814 |
for i, pos in enumerate([1, 2, 3, 4], 1):
|
| 815 |
pos_data = alarm_data[alarm_data['Position'] == pos].copy()
|
| 816 |
if not pos_data.empty:
|
| 817 |
-
# Kelompokkan jam
|
| 818 |
-
|
| 819 |
|
| 820 |
-
#
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
lambda x: 'Normal' if (x == 'No Alarm').all() else 'Abnormal'
|
| 825 |
-
).reindex(range(24), fill_value='Normal')
|
| 826 |
|
| 827 |
-
#
|
| 828 |
-
|
| 829 |
-
colorscale = [color_map.get(status, '#2E7D32') for status in hourly_status]
|
| 830 |
|
| 831 |
-
# Sudut: jam
|
| 832 |
-
theta = [h * 15 for h in range(24)] #
|
| 833 |
|
|
|
|
| 834 |
fig_radial.add_trace(
|
| 835 |
go.Barpolar(
|
| 836 |
-
r=
|
| 837 |
theta=theta,
|
| 838 |
-
name=
|
| 839 |
-
marker_color=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 840 |
opacity=0.8
|
| 841 |
),
|
| 842 |
row=(i - 1) // 2 + 1,
|
|
@@ -851,14 +875,14 @@ with col_a:
|
|
| 851 |
angularaxis=dict(
|
| 852 |
direction="clockwise",
|
| 853 |
period=24,
|
| 854 |
-
rotation=
|
| 855 |
tickvals=[0, 90, 180, 270],
|
| 856 |
-
ticktext=["
|
| 857 |
tickfont=dict(size=12)
|
| 858 |
),
|
| 859 |
radialaxis=dict(
|
| 860 |
visible=True,
|
| 861 |
-
range=[0, max(
|
| 862 |
)
|
| 863 |
)
|
| 864 |
)
|
|
|
|
| 725 |
# """, unsafe_allow_html=True)
|
| 726 |
st.markdown("""
|
| 727 |
<h3 class="objective-title">OBJECTIVE 3: Alarm Frequency Analysis — When, Where, and Which Tyres Matter Most?</h3>
|
| 728 |
+
<small>*Showing all alarm types: Normal (Green), Amber (Yellow), Red (Red)</small>
|
| 729 |
""", unsafe_allow_html=True)
|
| 730 |
|
| 731 |
# Filter semua data (termasuk alarm normal)
|
|
|
|
| 744 |
alarm_data['Alarm_Category'] = alarm_data['Alarm Status'].apply(
|
| 745 |
lambda x: 'Normal' if x == 'No Alarm'
|
| 746 |
else 'Red Alarm' if x == 'Red High Pressure'
|
| 747 |
+
else 'Amber Alarm'
|
| 748 |
)
|
| 749 |
|
| 750 |
# Buat 4 donut chart
|
|
|
|
| 796 |
)
|
| 797 |
st.plotly_chart(fig_donut, use_container_width=True)
|
| 798 |
|
| 799 |
+
# =============== COL A: Radial Charts (Count Alarm per Jam - Stacked by Status) ===============
|
| 800 |
with col_a:
|
| 801 |
+
st.markdown('<h5 style="text-align:center; margin-top: 0;">Alarm Count by Hour (Radial - Stacked)</h5>', unsafe_allow_html=True)
|
| 802 |
|
| 803 |
if alarm_data.empty:
|
| 804 |
st.warning("No data to display.")
|
|
|
|
| 814 |
for i, pos in enumerate([1, 2, 3, 4], 1):
|
| 815 |
pos_data = alarm_data[alarm_data['Position'] == pos].copy()
|
| 816 |
if not pos_data.empty:
|
| 817 |
+
# Kelompokkan jam dan status
|
| 818 |
+
hourly_status_counts = pos_data.groupby(['hour', 'Alarm Status']).size().unstack(fill_value=0)
|
| 819 |
|
| 820 |
+
# Ambil masing-masing kategori
|
| 821 |
+
hourly_normal = hourly_status_counts.get('No Alarm', pd.Series(0, index=range(24)))
|
| 822 |
+
hourly_amber = hourly_status_counts.get('Amber High Pressure', pd.Series(0, index=range(24))) # Ganti sesuai nama kolom Anda
|
| 823 |
+
hourly_red = hourly_status_counts.get('Red High Pressure', pd.Series(0, index=range(24)))
|
|
|
|
|
|
|
| 824 |
|
| 825 |
+
# Total per jam
|
| 826 |
+
total_per_hour = hourly_normal + hourly_amber + hourly_red
|
|
|
|
| 827 |
|
| 828 |
+
# Sudut: jam 3 → 0° (atas), jam 12 → 90° (kanan), jam 9 → 180° (bawah), jam 6 → 270° (kiri)
|
| 829 |
+
theta = [(h - 3) * 15 % 360 for h in range(24)] # Jam 3 pagi = 0°
|
| 830 |
|
| 831 |
+
# Tambahkan bar polar untuk Normal (hijau)
|
| 832 |
fig_radial.add_trace(
|
| 833 |
go.Barpolar(
|
| 834 |
+
r=hourly_normal.values,
|
| 835 |
theta=theta,
|
| 836 |
+
name='Normal',
|
| 837 |
+
marker_color='#2E7D32', # Hijau
|
| 838 |
+
opacity=0.8
|
| 839 |
+
),
|
| 840 |
+
row=(i - 1) // 2 + 1,
|
| 841 |
+
col=(i - 1) % 2 + 1
|
| 842 |
+
)
|
| 843 |
+
|
| 844 |
+
# Tambahkan bar polar untuk Amber (kuning) — ditumpuk di atas Normal
|
| 845 |
+
fig_radial.add_trace(
|
| 846 |
+
go.Barpolar(
|
| 847 |
+
r=hourly_amber.values,
|
| 848 |
+
theta=theta,
|
| 849 |
+
name='Amber',
|
| 850 |
+
marker_color='#FFC107', # Kuning
|
| 851 |
+
opacity=0.8
|
| 852 |
+
),
|
| 853 |
+
row=(i - 1) // 2 + 1,
|
| 854 |
+
col=(i - 1) % 2 + 1
|
| 855 |
+
)
|
| 856 |
+
|
| 857 |
+
# Tambahkan bar polar untuk Red (merah) — ditumpuk di atas Amber
|
| 858 |
+
fig_radial.add_trace(
|
| 859 |
+
go.Barpolar(
|
| 860 |
+
r=hourly_red.values,
|
| 861 |
+
theta=theta,
|
| 862 |
+
name='Red',
|
| 863 |
+
marker_color='#D32F2F', # Merah
|
| 864 |
opacity=0.8
|
| 865 |
),
|
| 866 |
row=(i - 1) // 2 + 1,
|
|
|
|
| 875 |
angularaxis=dict(
|
| 876 |
direction="clockwise",
|
| 877 |
period=24,
|
| 878 |
+
rotation=0, # Jam 3 pagi di atas
|
| 879 |
tickvals=[0, 90, 180, 270],
|
| 880 |
+
ticktext=["03:00", "12:00", "21:00", "18:00"],
|
| 881 |
tickfont=dict(size=12)
|
| 882 |
),
|
| 883 |
radialaxis=dict(
|
| 884 |
visible=True,
|
| 885 |
+
range=[0, max(total_per_hour.max() * 1.1, 1)]
|
| 886 |
)
|
| 887 |
)
|
| 888 |
)
|