CarlyneB commited on
Commit
fbd166f
·
1 Parent(s): 323fe98

[FEAT] Possibility to choose between running the optimization with manually entered values or by adding a pre-existing scenario (JSON) -> in this case, the values are automatically populated in all other input tabs

Browse files
data/cost_sliders.json CHANGED
@@ -67,7 +67,7 @@
67
  "max": 1296342.17
68
  }
69
  },
70
- "Coastal revegetation (mangrove, seaweeds\u2026)": {
71
  "Non-arable land (ha/tCO2)": {
72
  "min": 0.0078,
73
  "median": 0.12056618,
 
67
  "max": 1296342.17
68
  }
69
  },
70
+ "Coastal revegetation (mangrove, seaweeds)": {
71
  "Non-arable land (ha/tCO2)": {
72
  "min": 0.0078,
73
  "median": 0.12056618,
requirements.txt CHANGED
Binary files a/requirements.txt and b/requirements.txt differ
 
tabs/tab1_inputs.py CHANGED
@@ -14,7 +14,6 @@ def render_tab():
14
  for r in resource_order:
15
  if r not in st.session_state.resource_caps:
16
  st.session_state.resource_caps[r] = 0.0
17
-
18
  st.header("Resource inputs")
19
 
20
  st.info("""
@@ -28,6 +27,7 @@ def render_tab():
28
  # Reset button
29
  st.markdown("### Controls")
30
  col_reset, _ = st.columns([1, 5])
 
31
  with col_reset:
32
  if st.button("🔄 Reset All", type="secondary"):
33
  for r in st.session_state.resource_caps:
@@ -35,6 +35,51 @@ def render_tab():
35
  st.success("All resource values reset to 0.")
36
  st.rerun()
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  # Inputs by resource group
39
  st.markdown("### Set available resources for one year")
40
  for group, rlist in resource_groups.items():
 
14
  for r in resource_order:
15
  if r not in st.session_state.resource_caps:
16
  st.session_state.resource_caps[r] = 0.0
 
17
  st.header("Resource inputs")
18
 
19
  st.info("""
 
27
  # Reset button
28
  st.markdown("### Controls")
29
  col_reset, _ = st.columns([1, 5])
30
+
31
  with col_reset:
32
  if st.button("🔄 Reset All", type="secondary"):
33
  for r in st.session_state.resource_caps:
 
35
  st.success("All resource values reset to 0.")
36
  st.rerun()
37
 
38
+ # Dowload template
39
+ st.markdown("**Import resource values**")
40
+ col_template, col_upload = st.columns([1, 1])
41
+ with col_template:
42
+ st.markdown("Use the template below to fill in your resource availability values and import them directly into the tool.")
43
+ with open("data/resource_template.xlsx", "rb") as f:
44
+ st.download_button(
45
+ label="📥 Download Excel Template",
46
+ data=f,
47
+ file_name="resource_template.xlsx",
48
+ use_container_width= True,
49
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
50
+ )
51
+ with col_upload:
52
+ uploaded_file = st.file_uploader("Upload your Excel file", type="xlsx")
53
+ if uploaded_file is not None:
54
+ try:
55
+ df = pd.read_excel(uploaded_file)
56
+ required_cols = {"Resource", "Available Amount"}
57
+ if not required_cols.issubset(df.columns):
58
+ raise ValueError(f"Missing columns: {required_cols - set(df.columns)}")
59
+ for _, row in df.iterrows():
60
+ r = row["Resource"]
61
+ val = row["Available Amount"]
62
+ if r not in st.session_state.resource_caps:
63
+ continue
64
+ if pd.isna(val):
65
+ continue
66
+ try:
67
+ val = float(val)
68
+ except (ValueError, TypeError):
69
+ continue
70
+ if val == 0:
71
+ continue
72
+ st.session_state.resource_caps[r] = val
73
+ st.success(f"Resource values imported successfully.", icon="✅")
74
+
75
+ for r, v in st.session_state.resource_caps.items():
76
+ st.session_state[f"cap_{r}"] = v
77
+
78
+ except Exception as e:
79
+ st.error(f"Error importing resource values: {e}")
80
+
81
+ col_reset, _ = st.columns([1, 5])
82
+
83
  # Inputs by resource group
84
  st.markdown("### Set available resources for one year")
85
  for group, rlist in resource_groups.items():
tabs/tab3_coefficients.py CHANGED
@@ -10,7 +10,7 @@ def render_tab(cost_sliders):
10
  st.header("Resource efficiency coefficients")
11
 
12
  # === Initialization ===
13
- if "costs" not in st.session_state:
14
  st.session_state.costs = {
15
  m: {
16
  r: (0.0 if (m, r) in secondary_resources else cost_sliders[m][r]["median"])
 
10
  st.header("Resource efficiency coefficients")
11
 
12
  # === Initialization ===
13
+ if "costs" not in st.session_state or st.session_state.costs == {}:
14
  st.session_state.costs = {
15
  m: {
16
  r: (0.0 if (m, r) in secondary_resources else cost_sliders[m][r]["median"])
tabs/tab4_optimization.py CHANGED
@@ -11,6 +11,7 @@ import streamlit as st
11
  from config.config import method_order, resource_order, resource_units
12
  from optimization.optimization import run_optimization
13
  from utils.ui_helpers import format_results_summary
 
14
 
15
 
16
  def render_tab():
@@ -22,59 +23,83 @@ def render_tab():
22
  Run the optimization tool, explore results, and save scenarios for comparison or export.
23
  """)
24
 
25
- # Validate necessary inputs
26
- if "constraints" not in st.session_state or "costs" not in st.session_state or "resource_caps" not in st.session_state:
27
- st.error("Missing inputs. Please complete previous steps.")
28
- return
29
-
 
 
30
  if "scenarios" not in st.session_state:
31
  st.session_state.scenarios = {}
32
-
33
- if sum(st.session_state.resource_caps.values()) <= 0:
34
- st.warning("\u26a0\ufe0f All resources are currently set to 0. Please increase availability.")
35
- return
36
-
37
  # Run optimization
38
- if st.button("Run Optimization"):
39
- success, result = run_optimization(
40
- resource_caps=st.session_state.resource_caps,
41
- method_constraints=st.session_state.constraints,
42
- method_costs=st.session_state.costs,
43
- )
44
-
45
- if success:
46
- allocations = result["method_usage"]
47
- total_removed = result["total_removed"]
48
-
49
- if total_removed <= 0:
50
- st.warning("\u274c Optimization removed 0 tCO₂. Relax constraints or increase resources.")
51
- return
52
-
53
- total_cost = sum(
54
- allocations[m] * sum(st.session_state.costs[m].values())
55
- for m in allocations
56
- )
57
-
58
- st.session_state.latest_result = {
59
- "summary": {
60
- "total_co2_removed": total_removed,
61
- "total_cost": total_cost
62
- },
63
- "allocations": allocations,
64
- "resource_caps": st.session_state.resource_caps.copy(),
65
- "method_constraints": st.session_state.constraints,
66
- "method_costs": st.session_state.costs,
67
- }
68
-
69
- st.success(f"\u2705 Optimization successful: {total_removed:,.0f} tCO₂ removed")
 
 
 
70
  else:
71
- st.error("\u274c Optimization failed")
72
- if "message" in result:
73
- st.error(result["message"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
  if "latest_result" not in st.session_state:
76
  return
77
-
78
  latest = st.session_state.latest_result
79
  allocations = latest["allocations"]
80
  resource_caps = latest["resource_caps"]
 
11
  from config.config import method_order, resource_order, resource_units
12
  from optimization.optimization import run_optimization
13
  from utils.ui_helpers import format_results_summary
14
+ from utils.data_utils import is_valid_scenario
15
 
16
 
17
  def render_tab():
 
23
  Run the optimization tool, explore results, and save scenarios for comparison or export.
24
  """)
25
 
26
+ # Initialize necessary session state variables if they don't exist
27
+ if "resource_caps" not in st.session_state:
28
+ st.session_state.resource_caps = {}
29
+ if "constraints" not in st.session_state:
30
+ st.session_state.constraints = {}
31
+ if "costs" not in st.session_state:
32
+ st.session_state.costs = {}
33
  if "scenarios" not in st.session_state:
34
  st.session_state.scenarios = {}
35
+
 
 
 
 
36
  # Run optimization
37
+ st.markdown("### Run optimization")
38
+ col_run, col_load = st.columns(2)
39
+
40
+ with col_run:
41
+ st.markdown("**From current input values**")
42
+ run_clicked = st.button("▶️ Run Optimization", use_container_width=False)
43
+
44
+ with col_load:
45
+ st.markdown("**From a saved JSON scenario**")
46
+ uploaded_scenario = st.file_uploader("Upload a saved JSON scenario", type="json", key="scenario_loader")
47
+ if uploaded_scenario is not None:
48
+ try:
49
+ data = json.load(uploaded_scenario)
50
+ if is_valid_scenario(data):
51
+ if st.button("↩️ Reload this scenario into all tabs", use_container_width=True):
52
+ st.session_state.resource_caps = data["resource_caps"].copy()
53
+ st.session_state.constraints = data["method_constraints"].copy()
54
+ st.session_state.costs = data["method_costs"].copy()
55
+ keys_to_delete = [k for k in st.session_state if any(
56
+ k.startswith(prefix) for prefix in ["slider_", "manual_", "toggle_"]
57
+ )]
58
+ for k in keys_to_delete:
59
+ del st.session_state[k]
60
+ st.session_state.latest_result = data
61
+ st.success("Scenario loaded. All tabs have been updated.")
62
+ st.rerun()
63
+ else:
64
+ st.error("Invalid scenario format.")
65
+ except Exception as e:
66
+ st.error(f"Error loading scenario: {e}")
67
+
68
+ # Vérifications et exécution — uniquement si Run Optimization cliqué
69
+ if run_clicked:
70
+ if sum(st.session_state.resource_caps.values()) <= 0:
71
+ st.warning("⚠️ All resources are currently set to 0. Please increase availability or load a saved scenario.")
72
  else:
73
+ success, result = run_optimization(
74
+ resource_caps=st.session_state.resource_caps,
75
+ method_constraints=st.session_state.constraints,
76
+ method_costs=st.session_state.costs,
77
+ )
78
+ if success:
79
+ allocations = result["method_usage"]
80
+ total_removed = result["total_removed"]
81
+ if total_removed <= 0:
82
+ st.warning("❌ Optimization removed 0 tCO₂. Relax constraints or increase resources.")
83
+ else:
84
+ total_cost = sum(
85
+ allocations[m] * sum(st.session_state.costs[m].values())
86
+ for m in allocations
87
+ )
88
+ st.session_state.latest_result = {
89
+ "summary": {"total_co2_removed": total_removed, "total_cost": total_cost},
90
+ "allocations": allocations,
91
+ "resource_caps": st.session_state.resource_caps.copy(),
92
+ "method_constraints": st.session_state.constraints,
93
+ "method_costs": st.session_state.costs,
94
+ }
95
+ st.success(f"✅ Optimization successful: {total_removed:,.0f} tCO₂ removed")
96
+ else:
97
+ st.error("❌ Optimization failed")
98
+ if "message" in result:
99
+ st.error(result["message"])
100
 
101
  if "latest_result" not in st.session_state:
102
  return
 
103
  latest = st.session_state.latest_result
104
  allocations = latest["allocations"]
105
  resource_caps = latest["resource_caps"]
tabs/tab6_scenarios.py CHANGED
@@ -4,17 +4,7 @@ import matplotlib.pyplot as plt
4
  import pandas as pd
5
  import seaborn as sns
6
  import streamlit as st
7
-
8
-
9
- def is_valid_scenario(scenario):
10
- return (
11
- isinstance(scenario, dict)
12
- and "allocations" in scenario
13
- and "resource_caps" in scenario
14
- and "method_costs" in scenario
15
- and "method_constraints" in scenario
16
- and "summary" in scenario
17
- )
18
 
19
  def render_tab():
20
  st.header("Scenario Comparison")
 
4
  import pandas as pd
5
  import seaborn as sns
6
  import streamlit as st
7
+ from utils.data_utils import is_valid_scenario
 
 
 
 
 
 
 
 
 
 
8
 
9
  def render_tab():
10
  st.header("Scenario Comparison")
utils/data_utils.py CHANGED
@@ -1,5 +1,5 @@
1
  import json
2
-
3
  import streamlit as st
4
 
5
 
@@ -19,14 +19,27 @@ def render_resource_input(name_clean, r, tooltip=None):
19
  else:
20
  st.markdown(f"**{name_clean}**")
21
 
22
- if r not in st.session_state.resource_caps:
23
- st.session_state.resource_caps[r] = 0.0
 
 
24
 
25
  cap = st.number_input(
26
  label="label",
27
  label_visibility="collapsed",
28
  min_value=0.0,
29
  format="%.2f",
30
- key=f"cap_{r}"
31
  )
 
32
  st.session_state.resource_caps[r] = cap
 
 
 
 
 
 
 
 
 
 
 
1
  import json
2
+ import pandas as pd
3
  import streamlit as st
4
 
5
 
 
19
  else:
20
  st.markdown(f"**{name_clean}**")
21
 
22
+ widget_key = f"cap_{r}"
23
+
24
+ if widget_key not in st.session_state:
25
+ st.session_state[widget_key] = st.session_state.resource_caps.get(r, 0.0)
26
 
27
  cap = st.number_input(
28
  label="label",
29
  label_visibility="collapsed",
30
  min_value=0.0,
31
  format="%.2f",
32
+ key=widget_key,
33
  )
34
+
35
  st.session_state.resource_caps[r] = cap
36
+
37
+ def is_valid_scenario(scenario):
38
+ return (
39
+ isinstance(scenario, dict)
40
+ and "allocations" in scenario
41
+ and "resource_caps" in scenario
42
+ and "method_costs" in scenario
43
+ and "method_constraints" in scenario
44
+ and "summary" in scenario
45
+ )