Spaces:
Sleeping
Sleeping
[FEAT] Tab4: add Run tab + fix heatmap size + fix export tab reset
Browse files- tabs/tab4_optimization.py +57 -36
tabs/tab4_optimization.py
CHANGED
|
@@ -588,7 +588,13 @@ def show_heatmap(df_result, resource_caps, method_costs, custom_resources=None,
|
|
| 588 |
customdata=matrix_exact_fmt,
|
| 589 |
hovertemplate="<b>%{y}</b><br>%{x}<br>% of cap: %{z:.1f}%<br>Exact: %{customdata}<extra></extra>",
|
| 590 |
)
|
| 591 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 592 |
st.plotly_chart(fig, width='stretch')
|
| 593 |
|
| 594 |
resource_to_group = get_resource_to_group()
|
|
@@ -1181,7 +1187,7 @@ def confirm_clear_all():
|
|
| 1181 |
clear_all_data()
|
| 1182 |
st.rerun()
|
| 1183 |
with col2:
|
| 1184 |
-
if st.button("Cancel",width='stretch'):
|
| 1185 |
st.rerun()
|
| 1186 |
|
| 1187 |
def reset_scenario():
|
|
@@ -1198,6 +1204,16 @@ def reset_scenario():
|
|
| 1198 |
confirm_clear_all()
|
| 1199 |
|
| 1200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1201 |
def render_tab():
|
| 1202 |
"""Render the Portfolio Generation tab.
|
| 1203 |
|
|
@@ -1237,44 +1253,59 @@ def render_tab():
|
|
| 1237 |
if "enabled_methods" not in st.session_state:
|
| 1238 |
st.session_state.enabled_methods = {}
|
| 1239 |
|
| 1240 |
-
st.
|
| 1241 |
-
|
| 1242 |
-
|
| 1243 |
-
|
| 1244 |
-
|
|
|
|
|
|
|
| 1245 |
|
| 1246 |
-
with
|
| 1247 |
st.markdown("""
|
| 1248 |
-
<p class="crra-sub-
|
| 1249 |
unsafe_allow_html=True,
|
| 1250 |
)
|
| 1251 |
-
|
| 1252 |
-
panel_run_from_tabs()
|
| 1253 |
-
panel_load_from_excel()
|
| 1254 |
|
| 1255 |
-
|
| 1256 |
-
|
| 1257 |
-
|
| 1258 |
-
|
| 1259 |
-
|
| 1260 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1261 |
|
| 1262 |
-
|
| 1263 |
-
|
| 1264 |
|
| 1265 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1266 |
return
|
| 1267 |
|
| 1268 |
-
latest = st.session_state.latest_result
|
| 1269 |
allocations = latest["allocations"]
|
| 1270 |
resource_caps = latest["resource_caps"]
|
| 1271 |
method_costs = latest["method_costs"]
|
| 1272 |
|
| 1273 |
if not allocations or sum(allocations.values()) == 0:
|
|
|
|
|
|
|
|
|
|
| 1274 |
return
|
| 1275 |
|
| 1276 |
-
show_metrics(latest)
|
| 1277 |
-
|
| 1278 |
df_result = build_results_df(
|
| 1279 |
allocations,
|
| 1280 |
method_constraints=latest.get("method_constraints")
|
|
@@ -1284,14 +1315,8 @@ def render_tab():
|
|
| 1284 |
lambda x: f"{x:,.4f}" if pd.notna(x) else x
|
| 1285 |
)
|
| 1286 |
|
| 1287 |
-
tab_results, tab_resources, tab_bottleneck, tab_export = st.tabs([
|
| 1288 |
-
"📊 Method allocation",
|
| 1289 |
-
"🌿 Resource usage",
|
| 1290 |
-
"🔍 Bottleneck analysis",
|
| 1291 |
-
"💾 Export & Save",
|
| 1292 |
-
])
|
| 1293 |
-
|
| 1294 |
with tab_results:
|
|
|
|
| 1295 |
st.markdown('<p class="crra-sub-heading">Optimization Summary</p>', unsafe_allow_html=True)
|
| 1296 |
st.dataframe(df_display, width='stretch')
|
| 1297 |
st.markdown('<p class="crra-sub-heading">Method allocation breakdown</p>', unsafe_allow_html=True)
|
|
@@ -1312,8 +1337,4 @@ def render_tab():
|
|
| 1312 |
show_bottleneck_analysis(latest)
|
| 1313 |
|
| 1314 |
with tab_export:
|
| 1315 |
-
|
| 1316 |
-
export_scenario()
|
| 1317 |
-
export_inputs_only()
|
| 1318 |
-
export_all_charts()
|
| 1319 |
-
reset_scenario()
|
|
|
|
| 588 |
customdata=matrix_exact_fmt,
|
| 589 |
hovertemplate="<b>%{y}</b><br>%{x}<br>% of cap: %{z:.1f}%<br>Exact: %{customdata}<extra></extra>",
|
| 590 |
)
|
| 591 |
+
n_rows = len(df_heat.index)
|
| 592 |
+
n_cols = len(df_heat.columns)
|
| 593 |
+
height = max(500, 80 + 50 * n_rows)
|
| 594 |
+
# For wide heatmaps, force a minimum width so each column stays readable
|
| 595 |
+
if n_cols > 8:
|
| 596 |
+
fig.update_layout(width=max(900, 90 * n_cols))
|
| 597 |
+
apply_chart_style(fig, height=height)
|
| 598 |
st.plotly_chart(fig, width='stretch')
|
| 599 |
|
| 600 |
resource_to_group = get_resource_to_group()
|
|
|
|
| 1187 |
clear_all_data()
|
| 1188 |
st.rerun()
|
| 1189 |
with col2:
|
| 1190 |
+
if st.button("Cancel", width='stretch', type="secondary", key="btn-cancel"):
|
| 1191 |
st.rerun()
|
| 1192 |
|
| 1193 |
def reset_scenario():
|
|
|
|
| 1204 |
confirm_clear_all()
|
| 1205 |
|
| 1206 |
|
| 1207 |
+
@st.fragment
|
| 1208 |
+
def render_export_tab(latest):
|
| 1209 |
+
"""Render the full export/save section as a fragment so Save reruns only this area."""
|
| 1210 |
+
save_scenario(latest)
|
| 1211 |
+
export_scenario()
|
| 1212 |
+
export_inputs_only()
|
| 1213 |
+
export_all_charts()
|
| 1214 |
+
reset_scenario()
|
| 1215 |
+
|
| 1216 |
+
|
| 1217 |
def render_tab():
|
| 1218 |
"""Render the Portfolio Generation tab.
|
| 1219 |
|
|
|
|
| 1253 |
if "enabled_methods" not in st.session_state:
|
| 1254 |
st.session_state.enabled_methods = {}
|
| 1255 |
|
| 1256 |
+
tab_run, tab_results, tab_resources, tab_bottleneck, tab_export = st.tabs([
|
| 1257 |
+
"▶️ Run",
|
| 1258 |
+
"📊 Method allocation",
|
| 1259 |
+
"🌿 Resource usage",
|
| 1260 |
+
"🔍 Bottleneck analysis",
|
| 1261 |
+
"💾 Export & Save",
|
| 1262 |
+
])
|
| 1263 |
|
| 1264 |
+
with tab_run:
|
| 1265 |
st.markdown("""
|
| 1266 |
+
<p class="crra-sub-heading">Run optimization</p>""",
|
| 1267 |
unsafe_allow_html=True,
|
| 1268 |
)
|
| 1269 |
+
col_inputs, col_scenario = st.columns(2, gap="large")
|
|
|
|
|
|
|
| 1270 |
|
| 1271 |
+
with col_inputs:
|
| 1272 |
+
st.markdown("""
|
| 1273 |
+
<p class="crra-sub-sub-heading">From inputs</p>""",
|
| 1274 |
+
unsafe_allow_html=True,
|
| 1275 |
+
)
|
| 1276 |
+
run_clicked = st.button("Run Optimization", icon=":material/play_arrow:", key="btn-run-optimization", type="primary")
|
| 1277 |
+
panel_run_from_tabs()
|
| 1278 |
+
panel_load_from_excel()
|
| 1279 |
+
|
| 1280 |
+
with col_scenario:
|
| 1281 |
+
st.markdown("""
|
| 1282 |
+
<p class="crra-sub-sub-heading">From a saved scenario</p>""",
|
| 1283 |
+
unsafe_allow_html=True,
|
| 1284 |
+
)
|
| 1285 |
+
panel_load_from_json_or_csv()
|
| 1286 |
|
| 1287 |
+
if run_clicked:
|
| 1288 |
+
run_and_store_result()
|
| 1289 |
|
| 1290 |
+
_no_results = '<p class="caption">Run the optimization first to see results here.</p>'
|
| 1291 |
+
|
| 1292 |
+
latest = st.session_state.get("latest_result")
|
| 1293 |
+
if not latest:
|
| 1294 |
+
for _tab in [tab_results, tab_resources, tab_bottleneck, tab_export]:
|
| 1295 |
+
with _tab:
|
| 1296 |
+
st.markdown(_no_results, unsafe_allow_html=True)
|
| 1297 |
return
|
| 1298 |
|
|
|
|
| 1299 |
allocations = latest["allocations"]
|
| 1300 |
resource_caps = latest["resource_caps"]
|
| 1301 |
method_costs = latest["method_costs"]
|
| 1302 |
|
| 1303 |
if not allocations or sum(allocations.values()) == 0:
|
| 1304 |
+
for _tab in [tab_results, tab_resources, tab_bottleneck, tab_export]:
|
| 1305 |
+
with _tab:
|
| 1306 |
+
st.markdown(_no_results, unsafe_allow_html=True)
|
| 1307 |
return
|
| 1308 |
|
|
|
|
|
|
|
| 1309 |
df_result = build_results_df(
|
| 1310 |
allocations,
|
| 1311 |
method_constraints=latest.get("method_constraints")
|
|
|
|
| 1315 |
lambda x: f"{x:,.4f}" if pd.notna(x) else x
|
| 1316 |
)
|
| 1317 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1318 |
with tab_results:
|
| 1319 |
+
show_metrics(latest)
|
| 1320 |
st.markdown('<p class="crra-sub-heading">Optimization Summary</p>', unsafe_allow_html=True)
|
| 1321 |
st.dataframe(df_display, width='stretch')
|
| 1322 |
st.markdown('<p class="crra-sub-heading">Method allocation breakdown</p>', unsafe_allow_html=True)
|
|
|
|
| 1337 |
show_bottleneck_analysis(latest)
|
| 1338 |
|
| 1339 |
with tab_export:
|
| 1340 |
+
render_export_tab(latest)
|
|
|
|
|
|
|
|
|
|
|
|