Update app.py
Browse files
app.py
CHANGED
|
@@ -257,8 +257,7 @@ def load_champion_models():
|
|
| 257 |
"Ensure the 5 .pkl files are in the 'models/' directory.")
|
| 258 |
return []
|
| 259 |
|
| 260 |
-
@st.
|
| 261 |
-
def load_performance_data(file_path="data/final_5_day_results_df.csv"):
|
| 262 |
"""Loads pre-calculated performance data for Tab 3."""
|
| 263 |
try:
|
| 264 |
df = pd.read_csv(file_path)
|
|
@@ -808,43 +807,94 @@ with tab4:
|
|
| 808 |
avg_temp = np.nanmean(predictions_24h)
|
| 809 |
max_temp = np.nanmax(predictions_24h)
|
| 810 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 811 |
|
| 812 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
col_t2, col_t3, col_t24, col_avg, col_max = st.columns(5)
|
| 814 |
-
# Tính Timestamp cho các dự báo điểm (T+2h và T+3h)
|
| 815 |
-
forecast_t2_ts = forecast_start_ts + pd.Timedelta(hours=1)
|
| 816 |
-
forecast_t3_ts = forecast_start_ts + pd.Timedelta(hours=2)
|
| 817 |
-
forecast_t24_ts = forecast_start_ts + pd.Timedelta(hours=23)
|
| 818 |
|
| 819 |
# --- 1. Metric T+2h ---
|
| 820 |
with col_t2:
|
| 821 |
st.metric(
|
| 822 |
label=f"Forecast @ {forecast_t2_ts.strftime('%H:%M')} (T+2H)",
|
| 823 |
-
value=f"{t_plus_2h_value:.1f}°C"
|
|
|
|
|
|
|
| 824 |
)
|
| 825 |
|
| 826 |
# --- 2. Metric T+3h ---
|
| 827 |
with col_t3:
|
| 828 |
st.metric(
|
| 829 |
label=f"Forecast @ {forecast_t3_ts.strftime('%H:%M')} (T+3H)",
|
| 830 |
-
value=f"{t_plus_3h_value:.1f}°C"
|
|
|
|
|
|
|
| 831 |
)
|
| 832 |
|
| 833 |
# --- 3. Metric T+24h (Giữ lại để đối chiếu) ---
|
| 834 |
with col_t24:
|
| 835 |
st.metric(
|
| 836 |
label=f"Forecast @ {forecast_t24_ts.strftime('%H:%M')} (T+24H)",
|
| 837 |
-
value=f"{t_plus_24h_metric_value:.1f}°C"
|
|
|
|
|
|
|
| 838 |
)
|
| 839 |
|
| 840 |
# --- 4. Metric Average ---
|
| 841 |
with col_avg:
|
| 842 |
-
st.metric(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 843 |
|
| 844 |
# --- 5. Metric Max (Sử dụng bố cục ngang) ---
|
| 845 |
with col_max:
|
| 846 |
-
st.metric(
|
| 847 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 848 |
|
| 849 |
|
| 850 |
# --- BẮT ĐẦU THAY THẾ BIỂU ĐỒ TAB 4 ---
|
|
@@ -887,17 +937,10 @@ with tab4:
|
|
| 887 |
|
| 888 |
# 5.2 Graph: So sánh Dự báo vs Thực tế
|
| 889 |
st.subheader("24-Hour Forecast vs. Actual Comparison")
|
| 890 |
-
|
| 891 |
-
#
|
| 892 |
-
|
| 893 |
-
|
| 894 |
-
actual_values_24h = future_actuals_df.values
|
| 895 |
-
except KeyError:
|
| 896 |
-
# Xảy ra nếu forecast_hourly_index vượt ra ngoài dữ liệu
|
| 897 |
-
actual_values_24h = [float('nan')] * len(predictions_24h)
|
| 898 |
-
|
| 899 |
-
# Kiểm tra xem có bất kỳ giá trị NaN nào không
|
| 900 |
-
is_partial_hourly_forecast = any(pd.isna(v) for v in actual_values_24h) or (len(actual_values_24h) < len(predictions_24h))
|
| 901 |
|
| 902 |
fig_comp_hourly = go.Figure()
|
| 903 |
|
|
@@ -907,7 +950,6 @@ with tab4:
|
|
| 907 |
mode='lines+markers', name='24-Hour Forecast',
|
| 908 |
line=dict(color='red', dash='dot')
|
| 909 |
))
|
| 910 |
-
|
| 911 |
# 2. Chỉ thêm đường Thực tế (màu xanh) nếu có đủ dữ liệu
|
| 912 |
if not is_partial_hourly_forecast:
|
| 913 |
fig_comp_hourly.add_trace(go.Scatter(
|
|
|
|
| 257 |
"Ensure the 5 .pkl files are in the 'models/' directory.")
|
| 258 |
return []
|
| 259 |
|
| 260 |
+
@st.cache_datadef load_performance_data(file_path="data/final_5_day_results_df.csv"):
|
|
|
|
| 261 |
"""Loads pre-calculated performance data for Tab 3."""
|
| 262 |
try:
|
| 263 |
df = pd.read_csv(file_path)
|
|
|
|
| 807 |
avg_temp = np.nanmean(predictions_24h)
|
| 808 |
max_temp = np.nanmax(predictions_24h)
|
| 809 |
|
| 810 |
+
|
| 811 |
+
# --- BẮT ĐẦU NÂNG CẤP: Lấy 24h ACTUAL values (Giống logic Tab 2) ---
|
| 812 |
+
# 1. Lấy 24h index
|
| 813 |
+
actual_hourly_index = pd.date_range(start=forecast_start_ts, periods=24, freq='H')
|
| 814 |
+
|
| 815 |
+
# 2. Thử lấy 24h actual temps từ dataframe GỐC (hourly_data_df)
|
| 816 |
+
try:
|
| 817 |
+
# Dùng .reindex() để đảm bảo chúng ta có 24 dòng, ngay cả khi thiếu dữ liệu
|
| 818 |
+
actual_temps_24h_series = hourly_data_df['temp'].reindex(actual_hourly_index)
|
| 819 |
+
except Exception:
|
| 820 |
+
# Trường hợp dự phòng
|
| 821 |
+
actual_temps_24h_series = pd.Series([float('nan')] * 24, index=actual_hourly_index)
|
| 822 |
+
|
| 823 |
+
# 3. Lấy các giá trị điểm (T+2, T+3, T+24)
|
| 824 |
+
forecast_t2_ts = forecast_start_ts + pd.Timedelta(hours=1) # T+2
|
| 825 |
+
forecast_t3_ts = forecast_start_ts + pd.Timedelta(hours=2) # T+3
|
| 826 |
+
forecast_t24_ts = forecast_start_ts + pd.Timedelta(hours=23) # T+24
|
| 827 |
+
|
| 828 |
+
actual_t2_val = actual_temps_24h_series.get(forecast_t2_ts)
|
| 829 |
+
actual_t3_val = actual_temps_24h_series.get(forecast_t3_ts)
|
| 830 |
+
actual_t24_val = actual_temps_24h_series.get(forecast_t24_ts)
|
| 831 |
+
|
| 832 |
+
# 4. Tính toán giá trị tổng hợp (chỉ khi KHÔNG có NaN)
|
| 833 |
+
is_partial_hourly = actual_temps_24h_series.isna().any()
|
| 834 |
|
| 835 |
+
if is_partial_hourly:
|
| 836 |
+
actual_avg_val = float('nan')
|
| 837 |
+
actual_max_val = float('nan')
|
| 838 |
+
else:
|
| 839 |
+
actual_avg_val = np.nanmean(actual_temps_24h_series)
|
| 840 |
+
actual_max_val = np.nanmax(actual_temps_24h_series)
|
| 841 |
+
|
| 842 |
+
# 5. Tạo các chuỗi delta_text
|
| 843 |
+
delta_t2 = f"Actual: {actual_t2_val:.1f}°C" if pd.notna(actual_t2_val) else "Actual: --"
|
| 844 |
+
delta_t3 = f"Actual: {actual_t3_val:.1f}°C" if pd.notna(actual_t3_val) else "Actual: --"
|
| 845 |
+
delta_t24 = f"Actual: {actual_t24_val:.1f}°C" if pd.notna(actual_t24_val) else "Actual: --"
|
| 846 |
+
delta_avg = f"Actual: {actual_avg_val:.1f}°C" if pd.notna(actual_avg_val) else "Actual: --"
|
| 847 |
+
delta_max = f"Actual: {actual_max_val:.1f}°C" if pd.notna(actual_max_val) else "Actual: --"
|
| 848 |
+
# --- KẾT THÚC NÂNG CẤP ---
|
| 849 |
+
|
| 850 |
+
|
| 851 |
+
# Tạo 5 cột mới để hiển thị các metric
|
| 852 |
col_t2, col_t3, col_t24, col_avg, col_max = st.columns(5)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 853 |
|
| 854 |
# --- 1. Metric T+2h ---
|
| 855 |
with col_t2:
|
| 856 |
st.metric(
|
| 857 |
label=f"Forecast @ {forecast_t2_ts.strftime('%H:%M')} (T+2H)",
|
| 858 |
+
value=f"{t_plus_2h_value:.1f}°C",
|
| 859 |
+
delta=delta_t2, # <-- THÊM MỚI
|
| 860 |
+
delta_color="off" # <-- THÊM MỚI
|
| 861 |
)
|
| 862 |
|
| 863 |
# --- 2. Metric T+3h ---
|
| 864 |
with col_t3:
|
| 865 |
st.metric(
|
| 866 |
label=f"Forecast @ {forecast_t3_ts.strftime('%H:%M')} (T+3H)",
|
| 867 |
+
value=f"{t_plus_3h_value:.1f}°C",
|
| 868 |
+
delta=delta_t3, # <-- THÊM MỚI
|
| 869 |
+
delta_color="off" # <-- THÊM MỚI
|
| 870 |
)
|
| 871 |
|
| 872 |
# --- 3. Metric T+24h (Giữ lại để đối chiếu) ---
|
| 873 |
with col_t24:
|
| 874 |
st.metric(
|
| 875 |
label=f"Forecast @ {forecast_t24_ts.strftime('%H:%M')} (T+24H)",
|
| 876 |
+
value=f"{t_plus_24h_metric_value:.1f}°C",
|
| 877 |
+
delta=delta_t24, # <-- THÊM MỚI
|
| 878 |
+
delta_color="off" # <-- THÊM MỚI
|
| 879 |
)
|
| 880 |
|
| 881 |
# --- 4. Metric Average ---
|
| 882 |
with col_avg:
|
| 883 |
+
st.metric(
|
| 884 |
+
label="Next 24h Average Temp",
|
| 885 |
+
value=f"{avg_temp:.1f}°C",
|
| 886 |
+
delta=delta_avg, # <-- THÊM MỚI
|
| 887 |
+
delta_color="off" # <-- THÊM MỚI
|
| 888 |
+
)
|
| 889 |
|
| 890 |
# --- 5. Metric Max (Sử dụng bố cục ngang) ---
|
| 891 |
with col_max:
|
| 892 |
+
st.metric(
|
| 893 |
+
label="Next 24h Max Temp",
|
| 894 |
+
value=f"{max_temp:.1f}°C", # max_temp là dự đoán
|
| 895 |
+
delta=delta_max, # delta_max là thực tế
|
| 896 |
+
delta_color="off" # <-- THAY THẾ "Peak Heat"
|
| 897 |
+
)
|
| 898 |
|
| 899 |
|
| 900 |
# --- BẮT ĐẦU THAY THẾ BIỂU ĐỒ TAB 4 ---
|
|
|
|
| 937 |
|
| 938 |
# 5.2 Graph: So sánh Dự báo vs Thực tế
|
| 939 |
st.subheader("24-Hour Forecast vs. Actual Comparison")
|
| 940 |
+
|
| 941 |
+
# (Sử dụng lại actual_temps_24h_series và is_partial_hourly đã tính toán ở trên)
|
| 942 |
+
actual_values_24h = actual_temps_24h_series.values
|
| 943 |
+
is_partial_hourly_forecast = is_partial_hourly # Đổi tên biến cho nhất quán
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 944 |
|
| 945 |
fig_comp_hourly = go.Figure()
|
| 946 |
|
|
|
|
| 950 |
mode='lines+markers', name='24-Hour Forecast',
|
| 951 |
line=dict(color='red', dash='dot')
|
| 952 |
))
|
|
|
|
| 953 |
# 2. Chỉ thêm đường Thực tế (màu xanh) nếu có đủ dữ liệu
|
| 954 |
if not is_partial_hourly_forecast:
|
| 955 |
fig_comp_hourly.add_trace(go.Scatter(
|