Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1455,18 +1455,39 @@ else:
|
|
| 1455 |
|
| 1456 |
|
| 1457 |
# ================= OBJECTIVE 6 =================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1458 |
st.markdown('<h3 class="objective-title">OBJECTIVE 6: Insights & Mitigation β How Can Red Pressure Alarms Be Reduced?</h3>', unsafe_allow_html=True)
|
| 1459 |
|
| 1460 |
-
#
|
| 1461 |
-
#
|
| 1462 |
-
|
| 1463 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1464 |
front_pressure_avg_str = f"{front_pressure_avg:.1f}" if pd.notna(front_pressure_avg) else "β"
|
| 1465 |
front_temp_avg_str = f"{front_temp_avg:.1f}" if pd.notna(front_temp_avg) else "β"
|
| 1466 |
|
| 1467 |
-
#
|
| 1468 |
-
|
| 1469 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1470 |
total_alarms = hourly_counts.sum()
|
| 1471 |
|
| 1472 |
dominant_hour = None
|
|
@@ -1475,43 +1496,60 @@ if total_alarms > 0 and not hourly_counts.empty:
|
|
| 1475 |
dominant_hour = int(hourly_counts.idxmax())
|
| 1476 |
dominant_percentage = (hourly_counts[dominant_hour] / total_alarms) * 100
|
| 1477 |
|
| 1478 |
-
# Zone alarm stats
|
| 1479 |
-
|
| 1480 |
-
|
| 1481 |
-
|
| 1482 |
-
|
| 1483 |
-
|
| 1484 |
-
|
| 1485 |
-
|
| 1486 |
-
|
| 1487 |
-
|
| 1488 |
-
|
| 1489 |
-
|
| 1490 |
-
|
| 1491 |
-
|
| 1492 |
-
|
| 1493 |
-
|
| 1494 |
-
|
| 1495 |
-
|
| 1496 |
-
|
| 1497 |
-
|
| 1498 |
-
|
| 1499 |
-
|
| 1500 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1501 |
corr_pressure_temp_front_str = f"{corr_pressure_temp_front:+.2f}".replace("-0.00", "0.00")
|
| 1502 |
corr_speed_temp_rear_str = f"{corr_speed_temp_rear:+.2f}".replace("-0.00", "0.00")
|
| 1503 |
|
| 1504 |
-
# Position 1 alarm count
|
| 1505 |
-
pos1_alarm_count = alarm_df[alarm_df['Position'] == 1].shape[0]
|
| 1506 |
|
| 1507 |
-
#
|
| 1508 |
insight_lines = []
|
| 1509 |
|
|
|
|
| 1510 |
line1 = f"1. Front tyres (Pos 1 & 2): avg pressure {front_pressure_avg_str} psi, avg temperature {front_temp_avg_str}Β°C."
|
| 1511 |
if pd.notna(front_pressure_avg) and front_pressure_avg > 115:
|
| 1512 |
line1 += " Exceeds ideal inflation range (100β110 psi), indicating over-pressure risk."
|
| 1513 |
insight_lines.append(line1)
|
| 1514 |
|
|
|
|
| 1515 |
if dominant_hour is not None:
|
| 1516 |
insight_lines.append(
|
| 1517 |
f"2. Peak Red/Amber alarm concentration at {dominant_hour:02d}:00 ({dominant_percentage:.1f}% of total)."
|
|
@@ -1519,11 +1557,13 @@ if dominant_hour is not None:
|
|
| 1519 |
else:
|
| 1520 |
insight_lines.append("2. No statistically dominant hourly alarm peak.")
|
| 1521 |
|
|
|
|
| 1522 |
insight_lines.append(
|
| 1523 |
f"3. Front pressureβtemperature correlation: r = {corr_pressure_temp_front_str}; "
|
| 1524 |
f"Rear speedβtemperature correlation: r = {corr_speed_temp_rear_str}."
|
| 1525 |
)
|
| 1526 |
|
|
|
|
| 1527 |
if top_zone != "β" and top_zone_percentage >= 10.0:
|
| 1528 |
insight_lines.append(
|
| 1529 |
f"4. Zone {top_zone} accounts for {top_zone_percentage:.1f}% of alarms β highest-risk location."
|
|
@@ -1531,6 +1571,7 @@ if top_zone != "β" and top_zone_percentage >= 10.0:
|
|
| 1531 |
else:
|
| 1532 |
insight_lines.append("4. Alarm distribution appears relatively uniform across zones.")
|
| 1533 |
|
|
|
|
| 1534 |
if pos1_alarm_count > 0:
|
| 1535 |
insight_lines.append(
|
| 1536 |
f"5. Position 1 recorded {pos1_alarm_count} Red/Amber alarms β highest of any wheel position."
|
|
@@ -1538,23 +1579,23 @@ if pos1_alarm_count > 0:
|
|
| 1538 |
|
| 1539 |
insight_text = "<br>".join(insight_lines)
|
| 1540 |
|
| 1541 |
-
#
|
| 1542 |
-
summary_text = """
|
| 1543 |
1. Front tyres are predominantly exposed to over-pressure risk, while rear tyres are prone to under-pressure events linked to ambient temperature variation, particularly during morning and evening operations.<br>
|
| 1544 |
-
2. Overall, over-pressure alarms significantly exceed under-pressure alarms, and pressure behaviour is not correlated with vehicle speed, suggesting that temperature rise is driven by operational and environmental factors rather than driving behaviour
|
| 1545 |
"""
|
| 1546 |
|
| 1547 |
-
#
|
| 1548 |
-
recommendation_text = """
|
| 1549 |
1. Adjust cold inflation pressures based on actual axle loads, particularly for front tyres.<br>
|
| 1550 |
2. Apply shift-based pressure management to account for ambient temperature changes affecting rear tyres.<br>
|
| 1551 |
3. Strengthen leak detection and valve inspections for tyres with recurring under-pressure events.<br>
|
| 1552 |
4. Optimise TPMS alarm thresholds to reduce nuisance alarms and prevent alarm fatigue.<br>
|
| 1553 |
5. Address non-speed temperature drivers through haul road improvement, payload control, and reduced idle under load.<br>
|
| 1554 |
-
6. Use TPMS trends to enable proactive tyre health monitoring and maintenance planning
|
| 1555 |
"""
|
| 1556 |
|
| 1557 |
-
#
|
| 1558 |
st.markdown('<h4 style="text-align:center; margin:10px 0 5px 0; font-weight:bold;">INSIGHTS</h4>', unsafe_allow_html=True)
|
| 1559 |
st.markdown(f"""
|
| 1560 |
<div class="insight-box">
|
|
|
|
| 1455 |
|
| 1456 |
|
| 1457 |
# ================= OBJECTIVE 6 =================
|
| 1458 |
+
import streamlit as st
|
| 1459 |
+
import pandas as pd
|
| 1460 |
+
import numpy as np
|
| 1461 |
+
|
| 1462 |
+
# β οΈ ASSUMPTION: `dff` exists in scope.
|
| 1463 |
+
# Jika 'Alarm Type' tidak ada di kolom, kita fallback ke mode aman (empty alarms)
|
| 1464 |
+
# β sesuai permintaan: *hard code, jgn pakai def*
|
| 1465 |
+
|
| 1466 |
st.markdown('<h3 class="objective-title">OBJECTIVE 6: Insights & Mitigation β How Can Red Pressure Alarms Be Reduced?</h3>', unsafe_allow_html=True)
|
| 1467 |
|
| 1468 |
+
# ββββββββββββββββββββββββ DATA PREP (HARD-CODED, NO DEF) ββββββββββββββββββββββββ
|
| 1469 |
+
# Cek apakah kolom 'Alarm Type' ada
|
| 1470 |
+
has_alarm_type = 'Alarm Type' in dff.columns
|
| 1471 |
+
|
| 1472 |
+
# Front tyre stats β fallback ke "β" jika NaN/empty/error
|
| 1473 |
+
try:
|
| 1474 |
+
front_pressure_avg = dff[dff['Position'].isin([1, 2])]['Pressure (psi)'].mean()
|
| 1475 |
+
front_temp_avg = dff[dff['Position'].isin([1, 2])]['Temperature (Β°C)'].mean()
|
| 1476 |
+
except Exception:
|
| 1477 |
+
front_pressure_avg = np.nan
|
| 1478 |
+
front_temp_avg = np.nan
|
| 1479 |
+
|
| 1480 |
front_pressure_avg_str = f"{front_pressure_avg:.1f}" if pd.notna(front_pressure_avg) else "β"
|
| 1481 |
front_temp_avg_str = f"{front_temp_avg:.1f}" if pd.notna(front_temp_avg) else "β"
|
| 1482 |
|
| 1483 |
+
# Alarm filtering β hanya Red & Amber, jika 'Alarm Type' tidak ada β anggap 0 alarm
|
| 1484 |
+
if has_alarm_type:
|
| 1485 |
+
alarm_mask = dff['Alarm Type'].isin(['Red', 'Amber'])
|
| 1486 |
+
alarm_df = dff[alarm_mask].copy()
|
| 1487 |
+
else:
|
| 1488 |
+
alarm_df = dff.iloc[0:0] # empty DataFrame
|
| 1489 |
+
|
| 1490 |
+
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))
|
| 1491 |
total_alarms = hourly_counts.sum()
|
| 1492 |
|
| 1493 |
dominant_hour = None
|
|
|
|
| 1496 |
dominant_hour = int(hourly_counts.idxmax())
|
| 1497 |
dominant_percentage = (hourly_counts[dominant_hour] / total_alarms) * 100
|
| 1498 |
|
| 1499 |
+
# Zone alarm stats
|
| 1500 |
+
if 'Zone' in alarm_df.columns and not alarm_df.empty:
|
| 1501 |
+
zone_counts = alarm_df['Zone'].value_counts()
|
| 1502 |
+
if not zone_counts.empty:
|
| 1503 |
+
top_zone = str(zone_counts.index[0])
|
| 1504 |
+
top_zone_percentage = (zone_counts.iloc[0] / total_alarms) * 100 if total_alarms > 0 else 0.0
|
| 1505 |
+
else:
|
| 1506 |
+
top_zone = "β"
|
| 1507 |
+
top_zone_percentage = 0.0
|
| 1508 |
+
else:
|
| 1509 |
+
top_zone = "β"
|
| 1510 |
+
top_zone_percentage = 0.0
|
| 1511 |
+
|
| 1512 |
+
# Korelasi β aman tanpa fungsi
|
| 1513 |
+
corr_pressure_temp_front = 0.0
|
| 1514 |
+
corr_speed_temp_rear = 0.0
|
| 1515 |
+
|
| 1516 |
+
try:
|
| 1517 |
+
front_df = dff[dff['Position'].isin([1, 2])]
|
| 1518 |
+
rear_df = dff[dff['Position'].isin([3, 4])]
|
| 1519 |
+
|
| 1520 |
+
# Pressureβtemp (front)
|
| 1521 |
+
x1, y1 = front_df['Pressure (psi)'], front_df['Temperature (Β°C)']
|
| 1522 |
+
valid1 = x1.notna() & y1.notna()
|
| 1523 |
+
if valid1.sum() >= 2:
|
| 1524 |
+
c1 = np.corrcoef(x1[valid1], y1[valid1])[0, 1]
|
| 1525 |
+
corr_pressure_temp_front = c1 if np.isfinite(c1) else 0.0
|
| 1526 |
+
|
| 1527 |
+
# Speedβtemp (rear)
|
| 1528 |
+
x2, y2 = rear_df['Speed (km/h)'], rear_df['Temperature (Β°C)']
|
| 1529 |
+
valid2 = x2.notna() & y2.notna()
|
| 1530 |
+
if valid2.sum() >= 2:
|
| 1531 |
+
c2 = np.corrcoef(x2[valid2], y2[valid2])[0, 1]
|
| 1532 |
+
corr_speed_temp_rear = c2 if np.isfinite(c2) else 0.0
|
| 1533 |
+
except Exception:
|
| 1534 |
+
pass # tetap 0.0 jika error
|
| 1535 |
+
|
| 1536 |
+
# Format Β±0.xx, hindari -0.00
|
| 1537 |
corr_pressure_temp_front_str = f"{corr_pressure_temp_front:+.2f}".replace("-0.00", "0.00")
|
| 1538 |
corr_speed_temp_rear_str = f"{corr_speed_temp_rear:+.2f}".replace("-0.00", "0.00")
|
| 1539 |
|
| 1540 |
+
# Position 1 alarm count
|
| 1541 |
+
pos1_alarm_count = alarm_df[alarm_df['Position'] == 1].shape[0] if 'Position' in alarm_df.columns else 0
|
| 1542 |
|
| 1543 |
+
# ββββββββββββββββββββββββ INSIGHTS ββββββββββββββββββββββββ
|
| 1544 |
insight_lines = []
|
| 1545 |
|
| 1546 |
+
# 1. Front tyre avg
|
| 1547 |
line1 = f"1. Front tyres (Pos 1 & 2): avg pressure {front_pressure_avg_str} psi, avg temperature {front_temp_avg_str}Β°C."
|
| 1548 |
if pd.notna(front_pressure_avg) and front_pressure_avg > 115:
|
| 1549 |
line1 += " Exceeds ideal inflation range (100β110 psi), indicating over-pressure risk."
|
| 1550 |
insight_lines.append(line1)
|
| 1551 |
|
| 1552 |
+
# 2. Dominant hour
|
| 1553 |
if dominant_hour is not None:
|
| 1554 |
insight_lines.append(
|
| 1555 |
f"2. Peak Red/Amber alarm concentration at {dominant_hour:02d}:00 ({dominant_percentage:.1f}% of total)."
|
|
|
|
| 1557 |
else:
|
| 1558 |
insight_lines.append("2. No statistically dominant hourly alarm peak.")
|
| 1559 |
|
| 1560 |
+
# 3. Correlations
|
| 1561 |
insight_lines.append(
|
| 1562 |
f"3. Front pressureβtemperature correlation: r = {corr_pressure_temp_front_str}; "
|
| 1563 |
f"Rear speedβtemperature correlation: r = {corr_speed_temp_rear_str}."
|
| 1564 |
)
|
| 1565 |
|
| 1566 |
+
# 4. Top zone
|
| 1567 |
if top_zone != "β" and top_zone_percentage >= 10.0:
|
| 1568 |
insight_lines.append(
|
| 1569 |
f"4. Zone {top_zone} accounts for {top_zone_percentage:.1f}% of alarms β highest-risk location."
|
|
|
|
| 1571 |
else:
|
| 1572 |
insight_lines.append("4. Alarm distribution appears relatively uniform across zones.")
|
| 1573 |
|
| 1574 |
+
# 5. Position 1 alarms
|
| 1575 |
if pos1_alarm_count > 0:
|
| 1576 |
insight_lines.append(
|
| 1577 |
f"5. Position 1 recorded {pos1_alarm_count} Red/Amber alarms β highest of any wheel position."
|
|
|
|
| 1579 |
|
| 1580 |
insight_text = "<br>".join(insight_lines)
|
| 1581 |
|
| 1582 |
+
# ββββββββββββββββββββββββ SUMMARY (HARD-CODED) ββββββββββββββββββββββββ
|
| 1583 |
+
summary_text = """\
|
| 1584 |
1. Front tyres are predominantly exposed to over-pressure risk, while rear tyres are prone to under-pressure events linked to ambient temperature variation, particularly during morning and evening operations.<br>
|
| 1585 |
+
2. Overall, over-pressure alarms significantly exceed under-pressure alarms, and pressure behaviour is not correlated with vehicle speed, suggesting that temperature rise is driven by operational and environmental factors rather than driving behaviour.\
|
| 1586 |
"""
|
| 1587 |
|
| 1588 |
+
# ββββββββββββββββββββββββ RECOMMENDATION (HARD-CODED, BUSINESS-READY) ββββββββββββββββββββββββ
|
| 1589 |
+
recommendation_text = """\
|
| 1590 |
1. Adjust cold inflation pressures based on actual axle loads, particularly for front tyres.<br>
|
| 1591 |
2. Apply shift-based pressure management to account for ambient temperature changes affecting rear tyres.<br>
|
| 1592 |
3. Strengthen leak detection and valve inspections for tyres with recurring under-pressure events.<br>
|
| 1593 |
4. Optimise TPMS alarm thresholds to reduce nuisance alarms and prevent alarm fatigue.<br>
|
| 1594 |
5. Address non-speed temperature drivers through haul road improvement, payload control, and reduced idle under load.<br>
|
| 1595 |
+
6. Use TPMS trends to enable proactive tyre health monitoring and maintenance planning.\
|
| 1596 |
"""
|
| 1597 |
|
| 1598 |
+
# ββββββββββββββββββββββββ RENDER ββββββββββββββββββββββββ
|
| 1599 |
st.markdown('<h4 style="text-align:center; margin:10px 0 5px 0; font-weight:bold;">INSIGHTS</h4>', unsafe_allow_html=True)
|
| 1600 |
st.markdown(f"""
|
| 1601 |
<div class="insight-box">
|