Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -197,19 +197,20 @@ def load_data():
|
|
| 197 |
|
| 198 |
df = load_data()
|
| 199 |
|
|
|
|
| 200 |
# ================= HEADER β FIX FINAL (LOGO PASTI MUNCUL) =================
|
| 201 |
with st.container():
|
| 202 |
col1, col2, col3 = st.columns([1.2, 6, 1.2])
|
| 203 |
|
| 204 |
# LEFT β Michelin Logo
|
| 205 |
with col1:
|
| 206 |
-
if os.path.
|
| 207 |
-
|
|
|
|
|
|
|
|
|
|
| 208 |
else:
|
| 209 |
-
st.markdown(
|
| 210 |
-
"<h4 style='color:#003A8F; text-align:center;'>Michelin</h4>",
|
| 211 |
-
unsafe_allow_html=True
|
| 212 |
-
)
|
| 213 |
|
| 214 |
# CENTER β Title
|
| 215 |
with col2:
|
|
@@ -226,14 +227,13 @@ with st.container():
|
|
| 226 |
|
| 227 |
# RIGHT β BTech Logo
|
| 228 |
with col3:
|
| 229 |
-
if os.path.
|
| 230 |
-
|
|
|
|
|
|
|
|
|
|
| 231 |
else:
|
| 232 |
-
st.markdown(
|
| 233 |
-
"<h4 style='color:#7d7d7d; text-align:center;'>BTech</h4>",
|
| 234 |
-
unsafe_allow_html=True
|
| 235 |
-
)
|
| 236 |
-
|
| 237 |
# # ================= HEADER =================
|
| 238 |
# st.markdown("""
|
| 239 |
# <div class="main-header" style="text-align:center;">
|
|
@@ -248,45 +248,45 @@ with st.container():
|
|
| 248 |
|
| 249 |
# ================= LOGO (Perbaikan: Base64 Embed - Selalu Muncul) =================
|
| 250 |
# ================= LOGO (Pakai File Lokal - Selalu Muncul di Pojok Kanan Atas) =================
|
| 251 |
-
import os
|
| 252 |
-
import streamlit as st
|
| 253 |
-
|
| 254 |
-
# ================= PATH AMAN (WAJIB) =================
|
| 255 |
-
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 256 |
|
| 257 |
-
|
| 258 |
-
|
| 259 |
|
| 260 |
-
#
|
| 261 |
-
|
| 262 |
-
col1, col2, col3 = st.columns([1.5, 6, 1.5])
|
| 263 |
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
|
| 291 |
# ================= SIDEBAR FILTERS =================
|
| 292 |
with st.sidebar:
|
|
@@ -1382,118 +1382,118 @@ import numpy as np
|
|
| 1382 |
st.markdown('<h3 class="objective-title">OBJECTIVE 6: Insights & Mitigation β How Can Red Pressure Alarms Be Reduced?</h3>', unsafe_allow_html=True)
|
| 1383 |
|
| 1384 |
# ββββββββββββββββββββββββ DATA PREP (HARD-CODED, NO DEF) βββββοΏ½οΏ½ββββββββββββββββββ
|
| 1385 |
-
# Cek apakah kolom 'Alarm Type' ada
|
| 1386 |
-
has_alarm_type = 'Alarm Type' in dff.columns
|
| 1387 |
-
|
| 1388 |
-
# Front tyre stats β fallback ke "β" jika NaN/empty/error
|
| 1389 |
-
try:
|
| 1390 |
-
|
| 1391 |
-
|
| 1392 |
-
except Exception:
|
| 1393 |
-
|
| 1394 |
-
|
| 1395 |
-
|
| 1396 |
-
front_pressure_avg_str = f"{front_pressure_avg:.1f}" if pd.notna(front_pressure_avg) else "β"
|
| 1397 |
-
front_temp_avg_str = f"{front_temp_avg:.1f}" if pd.notna(front_temp_avg) else "β"
|
| 1398 |
-
|
| 1399 |
-
# Alarm filtering β hanya Red & Amber, jika 'Alarm Type' tidak ada β anggap 0 alarm
|
| 1400 |
-
if has_alarm_type:
|
| 1401 |
-
|
| 1402 |
-
|
| 1403 |
-
else:
|
| 1404 |
-
|
| 1405 |
-
|
| 1406 |
-
hourly_counts = alarm_df['hour'].value_counts().reindex(range(24), fill_value=0) if 'hour' in alarm_df.columns else pd.Series([0]*24, index=range(24))
|
| 1407 |
-
total_alarms = hourly_counts.sum()
|
| 1408 |
-
|
| 1409 |
-
dominant_hour = None
|
| 1410 |
-
dominant_percentage = 0.0
|
| 1411 |
-
if total_alarms > 0 and not hourly_counts.empty:
|
| 1412 |
-
|
| 1413 |
-
|
| 1414 |
-
|
| 1415 |
-
# Zone alarm stats
|
| 1416 |
-
if 'Zone' in alarm_df.columns and not alarm_df.empty:
|
| 1417 |
-
|
| 1418 |
-
|
| 1419 |
-
|
| 1420 |
-
|
| 1421 |
-
|
| 1422 |
-
|
| 1423 |
-
|
| 1424 |
-
else:
|
| 1425 |
-
|
| 1426 |
-
|
| 1427 |
-
|
| 1428 |
-
# Korelasi β aman tanpa fungsi
|
| 1429 |
-
corr_pressure_temp_front = 0.0
|
| 1430 |
-
corr_speed_temp_rear = 0.0
|
| 1431 |
-
|
| 1432 |
-
try:
|
| 1433 |
-
|
| 1434 |
-
|
| 1435 |
-
|
| 1436 |
-
|
| 1437 |
-
|
| 1438 |
-
|
| 1439 |
-
|
| 1440 |
-
|
| 1441 |
-
|
| 1442 |
-
|
| 1443 |
-
|
| 1444 |
-
|
| 1445 |
-
|
| 1446 |
-
|
| 1447 |
-
|
| 1448 |
-
|
| 1449 |
-
except Exception:
|
| 1450 |
-
|
| 1451 |
-
|
| 1452 |
-
# Format Β±0.xx, hindari -0.00
|
| 1453 |
-
corr_pressure_temp_front_str = f"{corr_pressure_temp_front:+.2f}".replace("-0.00", "0.00")
|
| 1454 |
-
corr_speed_temp_rear_str = f"{corr_speed_temp_rear:+.2f}".replace("-0.00", "0.00")
|
| 1455 |
-
|
| 1456 |
-
# Position 1 alarm count
|
| 1457 |
-
pos1_alarm_count = alarm_df[alarm_df['Position'] == 1].shape[0] if 'Position' in alarm_df.columns else 0
|
| 1458 |
-
|
| 1459 |
-
# ββββββββββββββββββββββββ INSIGHTS ββββββββββββββββββββββββ
|
| 1460 |
-
insight_lines = []
|
| 1461 |
-
|
| 1462 |
-
# 1. Front tyre avg
|
| 1463 |
-
line1 = f"1. Front tyres (Pos 1 & 2): avg pressure {front_pressure_avg_str} psi, avg temperature {front_temp_avg_str}Β°C."
|
| 1464 |
-
if pd.notna(front_pressure_avg) and front_pressure_avg > 115:
|
| 1465 |
-
|
| 1466 |
-
insight_lines.append(line1)
|
| 1467 |
-
|
| 1468 |
-
# 2. Dominant hour
|
| 1469 |
-
if dominant_hour is not None:
|
| 1470 |
-
|
| 1471 |
-
|
| 1472 |
-
|
| 1473 |
-
else:
|
| 1474 |
-
|
| 1475 |
-
|
| 1476 |
-
# 3. Correlations
|
| 1477 |
-
insight_lines.append(
|
| 1478 |
-
|
| 1479 |
-
|
| 1480 |
-
)
|
| 1481 |
-
|
| 1482 |
-
# 4. Top zone
|
| 1483 |
-
if top_zone != "β" and top_zone_percentage >= 10.0:
|
| 1484 |
-
|
| 1485 |
-
|
| 1486 |
-
|
| 1487 |
-
else:
|
| 1488 |
-
|
| 1489 |
-
|
| 1490 |
-
# 5. Position 1 alarms
|
| 1491 |
-
if pos1_alarm_count > 0:
|
| 1492 |
-
|
| 1493 |
-
|
| 1494 |
-
|
| 1495 |
-
|
| 1496 |
-
insight_text = "<br>".join(insight_lines)
|
| 1497 |
|
| 1498 |
# ββββββββββββββββββββββββ SUMMARY (HARD-CODED) ββββββββββββββββββββββββ
|
| 1499 |
summary_text = """\
|
|
@@ -1512,14 +1512,14 @@ recommendation_text = """\
|
|
| 1512 |
"""
|
| 1513 |
|
| 1514 |
# ββββββββββββββββββββββββ RENDER ββββββββββββββββββββββββ
|
| 1515 |
-
st.markdown('<h4 style="text-align:center; margin:10px 0 5px 0; font-weight:bold;">INSIGHTS</h4>', unsafe_allow_html=True)
|
| 1516 |
-
st.markdown(f"""
|
| 1517 |
-
<div class="insight-box">
|
| 1518 |
-
|
| 1519 |
-
{insight_text}
|
| 1520 |
-
|
| 1521 |
-
</div>
|
| 1522 |
-
""", unsafe_allow_html=True)
|
| 1523 |
|
| 1524 |
st.markdown('<h4 style="text-align:center; margin:15px 0 5px 0; font-weight:bold;">SUMMARY</h4>', unsafe_allow_html=True)
|
| 1525 |
st.markdown(f"""
|
|
|
|
| 197 |
|
| 198 |
df = load_data()
|
| 199 |
|
| 200 |
+
# ================= HEADER β FIX FINAL (LOGO PASTI MUNCUL) =================
|
| 201 |
# ================= HEADER β FIX FINAL (LOGO PASTI MUNCUL) =================
|
| 202 |
with st.container():
|
| 203 |
col1, col2, col3 = st.columns([1.2, 6, 1.2])
|
| 204 |
|
| 205 |
# LEFT β Michelin Logo
|
| 206 |
with col1:
|
| 207 |
+
if os.path.exists("logo.png"):
|
| 208 |
+
try:
|
| 209 |
+
st.image("logo.png", use_container_width=True)
|
| 210 |
+
except Exception as e:
|
| 211 |
+
st.markdown("<h4 style='color:#003A8F; text-align:center;'>Michelin</h4>", unsafe_allow_html=True)
|
| 212 |
else:
|
| 213 |
+
st.markdown("<h4 style='color:#003A8F; text-align:center;'>Michelin</h4>", unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
| 214 |
|
| 215 |
# CENTER β Title
|
| 216 |
with col2:
|
|
|
|
| 227 |
|
| 228 |
# RIGHT β BTech Logo
|
| 229 |
with col3:
|
| 230 |
+
if os.path.exists("btech.png"):
|
| 231 |
+
try:
|
| 232 |
+
st.image("btech.png", use_container_width=True)
|
| 233 |
+
except Exception as e:
|
| 234 |
+
st.markdown("<h4 style='color:#7d7d7d; text-align:center;'>BTech</h4>", unsafe_allow_html=True)
|
| 235 |
else:
|
| 236 |
+
st.markdown("<h4 style='color:#7d7d7d; text-align:center;'>BTech</h4>", unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
# # ================= HEADER =================
|
| 238 |
# st.markdown("""
|
| 239 |
# <div class="main-header" style="text-align:center;">
|
|
|
|
| 248 |
|
| 249 |
# ================= LOGO (Perbaikan: Base64 Embed - Selalu Muncul) =================
|
| 250 |
# ================= LOGO (Pakai File Lokal - Selalu Muncul di Pojok Kanan Atas) =================
|
| 251 |
+
# import os
|
| 252 |
+
# import streamlit as st
|
|
|
|
|
|
|
|
|
|
| 253 |
|
| 254 |
+
# # ================= PATH AMAN (WAJIB) =================
|
| 255 |
+
# BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 256 |
|
| 257 |
+
# LOGO_MICHELIN = os.path.join(BASE_DIR, "logo.png")
|
| 258 |
+
# LOGO_BTECH = os.path.join(BASE_DIR, "btech.png")
|
|
|
|
| 259 |
|
| 260 |
+
# # ================= HEADER =================
|
| 261 |
+
# with st.container():
|
| 262 |
+
# col1, col2, col3 = st.columns([1.5, 6, 1.5])
|
| 263 |
+
|
| 264 |
+
# # LEFT β Michelin Logo
|
| 265 |
+
# with col1:
|
| 266 |
+
# if os.path.exists(LOGO_MICHELIN):
|
| 267 |
+
# st.image(LOGO_MICHELIN, width=140)
|
| 268 |
+
# else:
|
| 269 |
+
# st.markdown("**Michelin**")
|
| 270 |
+
|
| 271 |
+
# # CENTER β Title
|
| 272 |
+
# with col2:
|
| 273 |
+
# st.markdown("""
|
| 274 |
+
# <div style="text-align:center;">
|
| 275 |
+
# <h1 style="margin:0; color:#154D9C; font-weight:800;">
|
| 276 |
+
# Tyre Pressure Monitoring System (TPMS) Analytics for Mining Equipments
|
| 277 |
+
# </h1>
|
| 278 |
+
# <p style="font-size:12px; color:#7d7d7d; margin-top:6px;">
|
| 279 |
+
# Daily trend insights derived from 13β16 December 2023 data
|
| 280 |
+
# </p>
|
| 281 |
+
# </div>
|
| 282 |
+
# """, unsafe_allow_html=True)
|
| 283 |
+
|
| 284 |
+
# # RIGHT β BTech Logo
|
| 285 |
+
# with col3:
|
| 286 |
+
# if os.path.exists(LOGO_BTECH):
|
| 287 |
+
# st.image(LOGO_BTECH, width=140)
|
| 288 |
+
# else:
|
| 289 |
+
# st.markdown("**BTech**")
|
| 290 |
|
| 291 |
# ================= SIDEBAR FILTERS =================
|
| 292 |
with st.sidebar:
|
|
|
|
| 1382 |
st.markdown('<h3 class="objective-title">OBJECTIVE 6: Insights & Mitigation β How Can Red Pressure Alarms Be Reduced?</h3>', unsafe_allow_html=True)
|
| 1383 |
|
| 1384 |
# ββββββββββββββββββββββββ DATA PREP (HARD-CODED, NO DEF) βββββοΏ½οΏ½ββββββββββββββββββ
|
| 1385 |
+
# # Cek apakah kolom 'Alarm Type' ada
|
| 1386 |
+
# has_alarm_type = 'Alarm Type' in dff.columns
|
| 1387 |
+
|
| 1388 |
+
# # Front tyre stats β fallback ke "β" jika NaN/empty/error
|
| 1389 |
+
# try:
|
| 1390 |
+
# front_pressure_avg = dff[dff['Position'].isin([1, 2])]['Pressure (psi)'].mean()
|
| 1391 |
+
# front_temp_avg = dff[dff['Position'].isin([1, 2])]['Temperature (Β°C)'].mean()
|
| 1392 |
+
# except Exception:
|
| 1393 |
+
# front_pressure_avg = np.nan
|
| 1394 |
+
# front_temp_avg = np.nan
|
| 1395 |
+
|
| 1396 |
+
# front_pressure_avg_str = f"{front_pressure_avg:.1f}" if pd.notna(front_pressure_avg) else "β"
|
| 1397 |
+
# front_temp_avg_str = f"{front_temp_avg:.1f}" if pd.notna(front_temp_avg) else "β"
|
| 1398 |
+
|
| 1399 |
+
# # Alarm filtering β hanya Red & Amber, jika 'Alarm Type' tidak ada β anggap 0 alarm
|
| 1400 |
+
# if has_alarm_type:
|
| 1401 |
+
# alarm_mask = dff['Alarm Type'].isin(['Red', 'Amber'])
|
| 1402 |
+
# alarm_df = dff[alarm_mask].copy()
|
| 1403 |
+
# else:
|
| 1404 |
+
# alarm_df = dff.iloc[0:0] # empty DataFrame
|
| 1405 |
+
|
| 1406 |
+
# hourly_counts = alarm_df['hour'].value_counts().reindex(range(24), fill_value=0) if 'hour' in alarm_df.columns else pd.Series([0]*24, index=range(24))
|
| 1407 |
+
# total_alarms = hourly_counts.sum()
|
| 1408 |
+
|
| 1409 |
+
# dominant_hour = None
|
| 1410 |
+
# dominant_percentage = 0.0
|
| 1411 |
+
# if total_alarms > 0 and not hourly_counts.empty:
|
| 1412 |
+
# dominant_hour = int(hourly_counts.idxmax())
|
| 1413 |
+
# dominant_percentage = (hourly_counts[dominant_hour] / total_alarms) * 100
|
| 1414 |
+
|
| 1415 |
+
# # Zone alarm stats
|
| 1416 |
+
# if 'Zone' in alarm_df.columns and not alarm_df.empty:
|
| 1417 |
+
# zone_counts = alarm_df['Zone'].value_counts()
|
| 1418 |
+
# if not zone_counts.empty:
|
| 1419 |
+
# top_zone = str(zone_counts.index[0])
|
| 1420 |
+
# top_zone_percentage = (zone_counts.iloc[0] / total_alarms) * 100 if total_alarms > 0 else 0.0
|
| 1421 |
+
# else:
|
| 1422 |
+
# top_zone = "β"
|
| 1423 |
+
# top_zone_percentage = 0.0
|
| 1424 |
+
# else:
|
| 1425 |
+
# top_zone = "β"
|
| 1426 |
+
# top_zone_percentage = 0.0
|
| 1427 |
+
|
| 1428 |
+
# # Korelasi β aman tanpa fungsi
|
| 1429 |
+
# corr_pressure_temp_front = 0.0
|
| 1430 |
+
# corr_speed_temp_rear = 0.0
|
| 1431 |
+
|
| 1432 |
+
# try:
|
| 1433 |
+
# front_df = dff[dff['Position'].isin([1, 2])]
|
| 1434 |
+
# rear_df = dff[dff['Position'].isin([3, 4])]
|
| 1435 |
+
|
| 1436 |
+
# # Pressureβtemp (front)
|
| 1437 |
+
# x1, y1 = front_df['Pressure (psi)'], front_df['Temperature (Β°C)']
|
| 1438 |
+
# valid1 = x1.notna() & y1.notna()
|
| 1439 |
+
# if valid1.sum() >= 2:
|
| 1440 |
+
# c1 = np.corrcoef(x1[valid1], y1[valid1])[0, 1]
|
| 1441 |
+
# corr_pressure_temp_front = c1 if np.isfinite(c1) else 0.0
|
| 1442 |
+
|
| 1443 |
+
# # Speedβtemp (rear)
|
| 1444 |
+
# x2, y2 = rear_df['Speed (km/h)'], rear_df['Temperature (Β°C)']
|
| 1445 |
+
# valid2 = x2.notna() & y2.notna()
|
| 1446 |
+
# if valid2.sum() >= 2:
|
| 1447 |
+
# c2 = np.corrcoef(x2[valid2], y2[valid2])[0, 1]
|
| 1448 |
+
# corr_speed_temp_rear = c2 if np.isfinite(c2) else 0.0
|
| 1449 |
+
# except Exception:
|
| 1450 |
+
# pass # tetap 0.0 jika error
|
| 1451 |
+
|
| 1452 |
+
# # Format Β±0.xx, hindari -0.00
|
| 1453 |
+
# corr_pressure_temp_front_str = f"{corr_pressure_temp_front:+.2f}".replace("-0.00", "0.00")
|
| 1454 |
+
# corr_speed_temp_rear_str = f"{corr_speed_temp_rear:+.2f}".replace("-0.00", "0.00")
|
| 1455 |
+
|
| 1456 |
+
# # Position 1 alarm count
|
| 1457 |
+
# pos1_alarm_count = alarm_df[alarm_df['Position'] == 1].shape[0] if 'Position' in alarm_df.columns else 0
|
| 1458 |
+
|
| 1459 |
+
# # ββββββββββββββββββββββββ INSIGHTS ββββββββββββββββββββββββ
|
| 1460 |
+
# insight_lines = []
|
| 1461 |
+
|
| 1462 |
+
# # 1. Front tyre avg
|
| 1463 |
+
# line1 = f"1. Front tyres (Pos 1 & 2): avg pressure {front_pressure_avg_str} psi, avg temperature {front_temp_avg_str}Β°C."
|
| 1464 |
+
# if pd.notna(front_pressure_avg) and front_pressure_avg > 115:
|
| 1465 |
+
# line1 += " Exceeds ideal inflation range (100β110 psi), indicating over-pressure risk."
|
| 1466 |
+
# insight_lines.append(line1)
|
| 1467 |
+
|
| 1468 |
+
# # 2. Dominant hour
|
| 1469 |
+
# if dominant_hour is not None:
|
| 1470 |
+
# insight_lines.append(
|
| 1471 |
+
# f"2. Peak Red/Amber alarm concentration at {dominant_hour:02d}:00 ({dominant_percentage:.1f}% of total)."
|
| 1472 |
+
# )
|
| 1473 |
+
# else:
|
| 1474 |
+
# insight_lines.append("2. No statistically dominant hourly alarm peak.")
|
| 1475 |
+
|
| 1476 |
+
# # 3. Correlations
|
| 1477 |
+
# insight_lines.append(
|
| 1478 |
+
# f"3. Front pressureβtemperature correlation: r = {corr_pressure_temp_front_str}; "
|
| 1479 |
+
# f"Rear speedβtemperature correlation: r = {corr_speed_temp_rear_str}."
|
| 1480 |
+
# )
|
| 1481 |
+
|
| 1482 |
+
# # 4. Top zone
|
| 1483 |
+
# if top_zone != "β" and top_zone_percentage >= 10.0:
|
| 1484 |
+
# insight_lines.append(
|
| 1485 |
+
# f"4. Zone {top_zone} accounts for {top_zone_percentage:.1f}% of alarms β highest-risk location."
|
| 1486 |
+
# )
|
| 1487 |
+
# else:
|
| 1488 |
+
# insight_lines.append("4. Alarm distribution appears relatively uniform across zones.")
|
| 1489 |
+
|
| 1490 |
+
# # 5. Position 1 alarms
|
| 1491 |
+
# if pos1_alarm_count > 0:
|
| 1492 |
+
# insight_lines.append(
|
| 1493 |
+
# f"5. Position 1 recorded {pos1_alarm_count} Red/Amber alarms β highest of any wheel position."
|
| 1494 |
+
# )
|
| 1495 |
+
|
| 1496 |
+
# insight_text = "<br>".join(insight_lines)
|
| 1497 |
|
| 1498 |
# ββββββββββββββββββββββββ SUMMARY (HARD-CODED) ββββββββββββββββββββββββ
|
| 1499 |
summary_text = """\
|
|
|
|
| 1512 |
"""
|
| 1513 |
|
| 1514 |
# ββββββββββββββββββββββββ RENDER ββββββββββββββββββββββββ
|
| 1515 |
+
# st.markdown('<h4 style="text-align:center; margin:10px 0 5px 0; font-weight:bold;">INSIGHTS</h4>', unsafe_allow_html=True)
|
| 1516 |
+
# st.markdown(f"""
|
| 1517 |
+
# <div class="insight-box">
|
| 1518 |
+
# <div class="content" style="text-align:left;">
|
| 1519 |
+
# {insight_text}
|
| 1520 |
+
# </div>
|
| 1521 |
+
# </div>
|
| 1522 |
+
# """, unsafe_allow_html=True)
|
| 1523 |
|
| 1524 |
st.markdown('<h4 style="text-align:center; margin:15px 0 5px 0; font-weight:bold;">SUMMARY</h4>', unsafe_allow_html=True)
|
| 1525 |
st.markdown(f"""
|