CarlyneB commited on
Commit
e5f540d
·
1 Parent(s): 426e346

[DOC] Readme updated with instructions on adding data and updating libraries

Browse files
Files changed (4) hide show
  1. .streamlit/config.toml +1 -4
  2. README.md +399 -218
  3. app.py +5 -7
  4. assets/styles.css +1 -20
.streamlit/config.toml CHANGED
@@ -4,7 +4,4 @@ primaryColor = "#298231"
4
  backgroundColor = "#ffffff"
5
  secondaryBackgroundColor = "#eae9d8"
6
  textColor = "#000000"
7
- font = "sans-serif"
8
-
9
- [server]
10
- enableStaticServing = true
 
4
  backgroundColor = "#ffffff"
5
  secondaryBackgroundColor = "#eae9d8"
6
  textColor = "#000000"
7
+ font = "sans-serif"
 
 
 
README.md CHANGED
@@ -15,9 +15,45 @@ A Streamlit app for optimizing carbon removal portfolios across different method
15
 
16
  ---
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  ## Data Maintenance Guide
19
 
20
- This guide is for Carbon Gap staff who need to update the tool's data — **no coding experience required** for most tasks.
21
 
22
  ---
23
 
@@ -29,51 +65,82 @@ All the data the tool uses (CDR methods, resources, coefficients) comes from a s
29
  data/inputs_aggregated.csv
30
  ```
31
 
32
- Every time the app starts, it computes a fingerprint (hash) of the CSV and compares it to the last known value. If they differ — meaning the CSV has been modified — it regenerates all data files automatically before loading. You do not need to run anything manually.
33
 
34
- There are two ways to update the data, depending on whether you are working directly on Hugging Face or on a local copy of the project.
35
 
36
- ---
37
-
38
- ### Option 1 — Edit directly on Hugging Face (no local setup needed)
39
 
40
  This is the simplest option for non-coders with admin access to the Hugging Face Space.
41
 
42
  **Steps:**
43
 
44
- 1. Go to the Hugging Face Space → click the **Files** tab
45
- 2. Open `data/inputs_aggregated.csv` and click **Edit** (pencil icon), or upload a new version of the file
46
- 3. Commit the change directly on Hugging Face — the Space will restart automatically
47
- 4. **Check the logs** to confirm the update ran:
48
- - In the Space, click **⋮ (three dots)** → **Logs**
 
 
49
  - You should see:
50
  ```
51
- inputs_aggregated.csv has changed — running data/update.py ...
52
  [... update details ...]
53
  Data files updated successfully.
54
  ```
55
- 5. If the logs show this message, the app is running with the new data. If not, something went wrong — contact the developer.
56
 
57
  > **Note:** with this option, only `inputs_aggregated.csv` needs to be uploaded. The app handles the rest automatically on restart.
58
 
59
- ---
60
 
61
- ### Option 2 — Work locally and push (recommended for larger changes)
62
 
63
- Use this option when making bigger changes (new methods, new resources, reordering) where you want to preview the result before publishing.
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- **Step 1 — Get the project on your machine**
66
 
67
- If you do not already have it:
68
- - Install [GitHub Desktop](https://desktop.github.com) (free, no command line needed)
69
- - Open GitHub Desktop → **File** → **Clone repository** → enter the repository URL → choose a local folder → click **Clone**
70
 
71
- **Step 2 — Edit the CSV**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
  Open `data/inputs_aggregated.csv` in Excel or any spreadsheet editor. Make your changes and save.
74
 
75
- **Step 3 — Open a terminal in the project folder**
76
 
 
 
 
77
  - Mac: right-click the project folder → **New Terminal at Folder**
78
  - Windows: open the folder, click in the address bar, type `cmd`, press Enter
79
 
@@ -83,78 +150,67 @@ source venv/bin/activate # Mac / Linux
83
  venv\Scripts\activate # Windows
84
  ```
85
 
86
- **Step 4 — Run the update script**
87
 
88
  ```
89
- python data/update.py
90
  ```
91
 
92
- This regenerates all data files and updates the internal fingerprint. Check the output — it should end with `All files updated successfully.`
93
 
94
- **Step 5 — Commit and push**
95
 
96
- In GitHub Desktop:
97
- - You will see all modified files listed on the left
98
- - Write a short description in the **Summary** field (e.g. "Update coefficients for Afforestation")
99
- - Click **Commit to main**
100
- - Click **Push origin**
 
 
 
101
 
102
  Hugging Face will detect the push and rebuild the Space automatically.
103
 
104
  ---
105
 
106
- ### Quick reference — where is each parameter?
107
 
108
  | I want to change… | File | Where exactly |
109
  |---|---|---|
110
- | A coefficient value (min / median / max) | `data/inputs_aggregated.csv` | Columns `min`, `median`, `max` — find the row by `Implementation` + `Resource` |
111
- | The name of a CDR method | `data/inputs_aggregated.csv` | Column `Implementation` — use Find & Replace |
112
  | Which group a CDR method belongs to | `data/inputs_aggregated.csv` | Column `Method group` |
113
- | The name of a resource | `data/inputs_aggregated.csv` | Column `Resource` — use Find & Replace |
114
  | Which group a resource belongs to | `data/inputs_aggregated.csv` | Column `Resource group` |
115
- | The unit of a resource group | `data/inputs_aggregated.csv` | Column `Unit` — must be consistent across all rows for that group |
116
- | Whether a resource is optional for a method | `data/inputs_aggregated.csv` | Column `Is secondary` — `TRUE` = optional, `FALSE` = always active |
117
- | The display order of methods or resources | `data/inputs_aggregated.csv` | Row order — move rows up/down |
118
- | The app's colours | `config/config.py` | `CRRA_COLORS` dictionary |
119
- | The app's font | `config/config.py` | `CRRA_FONT` variable |
120
- | The tooltip text on a method name | `data/tooltips.xlsx` | Sheet **Methods** — column `Tooltip` |
121
- | The tooltip text on a resource name | `data/tooltips.xlsx` | Sheet **Resources** — column `Tooltip` |
122
- | UI spacing, font sizes, button styles | `assets/styles.css` | Standard CSS — search for the element name |
123
- | Python library versions | `requirements.txt` | One line per library — see Library Maintenance Guide below |
124
-
125
- > After any change to `inputs_aggregated.csv`, run `python data/update.py`. After changes to `config/config.py` or `assets/styles.css`, simply restart the app.
126
-
127
- ---
128
-
129
- ### Before you start
130
-
131
- **Open a terminal** in the project folder. On Mac: right-click the folder → "New Terminal at Folder". On Windows: open the folder, then type `cmd` in the address bar.
132
-
133
- **Activate the Python environment** (only needed once per session):
134
-
135
- - Mac / Linux: `source venv/bin/activate`
136
- - Windows: `venv\Scripts\activate`
137
-
138
- You should now see `(venv)` at the start of your terminal line.
139
-
140
- ---
141
 
142
  ### File structure (what each file does)
143
 
144
  | File | What it is | Do you edit it? |
145
  |------|-----------|-----------------|
146
- | `data/inputs_aggregated.csv` | **Main data file** — all methods, resources and coefficients | ✅ Yes |
147
  | `data/update.py` | Script that regenerates everything from the CSV | ❌ No |
148
- | `data/cost_sliders.json` | Auto-generated — coefficients used by the app | ❌ No (auto) |
149
- | `data/method_groups.json` | Auto-generated — CDR method categories | ❌ No (auto) |
150
- | `data/secondary_resources.json` | Auto-generated — optional resource assignments | ❌ No (auto) |
151
- | `data/inputs_template.xlsx` | Auto-generated — Excel template for users | ❌ No (auto) |
152
- | `data/resource_template.xlsx` | Auto-generated — Excel template for resources | ❌ No (auto) |
153
- | `data/tooltips.xlsx` | Tooltip texts shown on hover in the app | ✅ Yes — edit directly |
154
 
155
- > ⚠️ **Never edit the auto-generated files directly** — your changes will be overwritten the next time `update.py` is run.
156
-
157
- ---
158
 
159
  ### Understanding `inputs_aggregated.csv`
160
 
@@ -174,98 +230,143 @@ Each row represents **one resource used by one CDR method**, with the following
174
  | `Is secondary` | Whether this resource is optional for this method | `FALSE` |
175
 
176
  > **Primary resources** (`Is secondary = FALSE`) are always active in the model.
177
- > **Secondary resources** (`Is secondary = TRUE`) are optional — users can toggle them on in the app.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
  ---
180
 
181
- ## Case 1 — Modify existing coefficient values
182
 
183
  **When to use:** The literature has been updated and you want to change the min/median/max values for an existing method-resource pair.
184
 
185
- **Steps:**
 
 
 
 
 
 
 
 
186
 
187
  1. Open `data/inputs_aggregated.csv` in Excel or a text editor.
188
  2. Find the row with the correct `Implementation` and `Resource`.
189
  3. Edit the `min`, `median`, and/or `max` columns.
190
- 4. Save the file.
191
- 5. In the terminal, run:
192
  ```
193
- python data/update.py
 
 
 
 
 
 
194
  ```
195
 
196
- ---
197
 
198
- ## Case 2 — Add a new resource to an existing method
199
 
200
- **When to use:** A CDR method now uses a resource that wasn't tracked before (e.g., adding water consumption to Afforestation).
201
 
202
- **Steps:**
 
 
203
 
204
- 1. Open `data/inputs_aggregated.csv`.
205
- 2. Add a **new row** at the end (or anywhere in the file — order of rows determines display order in the app):
206
-
207
- | Column | What to enter |
208
- |--------|--------------|
209
- | `Implementation` | Exact name of the existing method (copy it from another row to avoid typos) |
210
- | `Method group` | Same group as the other rows for that method |
211
- | `Resource` | Name of the resource (must match an existing resource exactly, or see Case 4 to add a new one) |
212
- | `Resource group` | Same group as the other rows for that resource |
213
- | `Type` | `Physical` or `Energy` |
214
- | `Unit` | Must match the unit already used for that resource (e.g., `Mha/MtCO2`) |
215
- | `min` | Minimum coefficient |
216
- | `median` | Median coefficient |
217
- | `max` | Maximum coefficient |
218
- | `Is secondary` | `TRUE` if optional, `FALSE` if always required |
219
-
220
- 3. Save the file.
221
- 4. Run `python data/update.py`.
222
 
223
- ---
 
 
 
 
 
 
 
 
 
 
224
 
225
- ## Case 3 — Add a new CDR method
226
 
227
  **When to use:** A new carbon removal approach needs to be added to the tool.
228
 
229
- **Steps:**
230
 
231
- 1. Open `data/inputs_aggregated.csv`.
232
- 2. Add **one row per resource** used by the new method. For example, if your new method uses land and water, add 2 rows.
 
 
233
 
234
- For each row, fill in all columns. Use an **existing Method group** (e.g., `Forestry`) or create a new one (the name you write here becomes the category name in the app).
235
 
236
- 3. Save the file.
237
- 4. Run `python data/update.py`.
238
-
239
- > **Note on display order:** The new method will appear in the app in the same position it appears in the CSV. If you want it between two existing methods, insert the rows between those methods' rows.
 
 
 
 
 
 
 
 
240
 
241
- > ⚠️ **Special case — derived methods:** see Case 3b below.
242
 
243
  ---
244
 
245
- ## Case 3b — Add a derived CDR method (variant of an existing method)
246
 
247
  **What is a derived method?**
248
- Some methods in the tool are not standalone entries in the CSV — they are automatically generated as **variants** of a base method. For example:
249
  - `Bio-char` in the CSV → generates 3 variants in the app: `Bio-char - Forest biomass`, `Bio-char - Non-forest biomass`, `Bio-char - Unspecified biomass`
250
  - `Enhanced weathering` in the CSV → generates 4 variants: one per mineral type
251
 
252
- Each variant is identical to the base method **except** it only keeps the resource relevant to that variant (e.g. `Bio-char - Forest biomass` removes the non-forest and unspecified biomass resources).
253
 
254
  **When to use:** You want to add a new variant of an existing method (e.g. a new mineral type for Enhanced weathering, or a new biomass type for Bio-char).
255
 
256
- **Steps:**
257
 
258
- 1. Open `data/inputs_aggregated.csv` and make sure the base method has a row for the new resource (e.g. add a row for `Enhanced weathering` with the new mineral).
 
 
 
 
 
 
259
 
260
  2. Open `data/generate_model_data.py`. Find the two structures at the top of the file:
261
 
262
- **`REPLACED_BY_DERIVED`** — lists base methods that are fully replaced by their variants (the base name disappears from the app):
263
  ```
264
  REPLACED_BY_DERIVED = {"Bio-char", "Enhanced weathering"}
265
  ```
266
- If your new base method should disappear from the app once variants exist, add its name here.
267
 
268
- **`DERIVED_FROM`** — maps each base method to its list of variant names (in display order):
269
  ```
270
  DERIVED_FROM = {
271
  "Bio-char": ["Bio-char - Forest biomass", ...],
@@ -273,136 +374,208 @@ Each variant is identical to the base method **except** it only keeps the resour
273
  ...
274
  }
275
  ```
276
- Add the new variant name to the relevant list here.
277
 
278
- 3. Further down in `create_sliders_inputs()`, add the derivation logic for your new variant — copy the pattern already used for Bio-char or Enhanced weathering: copy the base method's coefficients, then remove the resources that don't apply to this variant.
279
 
280
- 4. Save `generate_model_data.py` and run:
281
  ```
282
  python data/update.py
283
  ```
284
-
285
- > ⚠️ This case requires editing Python code. If you are not comfortable with this, contact the developer — provide the name of the new variant and which resource it should keep, and they can add the 5–10 lines needed.
 
 
 
 
286
 
287
  ---
288
 
289
- ## Case 4 — Add a new resource
290
 
291
- **When to use:** A resource that doesn't exist yet needs to be tracked (e.g., a new type of mineral or energy).
292
 
293
- **Steps:**
294
-
295
- 1. Decide which **Resource group** the new resource belongs to (e.g., `Minerals`, `Energy`, `Land`). If it belongs to an existing group, use the exact same group name. If it needs its own group, invent a new name.
296
 
297
- 2. Open `data/inputs_aggregated.csv` and add one row per method that uses this resource (same as Case 2).
 
 
 
 
298
 
299
- 3. **Check the unit:** the unit for all resources in a group must be the same (e.g., all `Land` resources use `Mha/MtCO2`). If your new resource has a different unit, it needs its own Resource group.
300
 
301
- 4. Save the file and run `python data/update.py`.
 
 
 
 
 
 
 
 
 
 
 
 
302
 
303
  ---
304
 
305
- ## Case 5 — Add a new resource group (new category)
306
 
307
  **When to use:** Your new resource doesn't fit any existing category.
308
 
309
- **Steps:**
 
 
310
 
311
- Same as Case 4, but in the `Resource group` column, write a **new group name** that has never been used before. The app will automatically create a new section for it in the Resource Inputs tab.
312
 
313
- The new group will appear in the app **in the position of its first row in the CSV**. Move the rows up or down to control where it appears.
314
 
315
  ---
316
 
317
- ## Case 6 — Change whether a resource is optional (secondary) for a method
318
 
319
  **When to use:** You want to make a resource optional (user can enable/disable it) or make it always required.
320
 
321
- **Steps:**
 
 
 
 
 
 
 
322
 
323
  1. Open `data/inputs_aggregated.csv`.
324
  2. Find the row with the correct `Implementation` and `Resource`.
325
- 3. Change the `Is secondary` column to `TRUE` (optional) or `FALSE` (always active).
326
- 4. Save and run `python data/update.py`.
 
 
 
 
 
 
 
 
 
327
 
328
  ---
329
 
330
- ## Case 7 — Rename a method or resource
331
 
332
  **When to use:** Correcting a spelling mistake or updating nomenclature.
333
 
334
- **Steps:**
335
 
336
- 1. Open `data/inputs_aggregated.csv`.
337
- 2. Use **Find & Replace** (Ctrl+H / Cmd+H) to replace the old name with the new name everywhere in the file. Make sure to replace it in both the `Implementation` column (for methods) or `Resource` column (for resources), and also in the `Method group` / `Resource group` columns if the group name changed.
338
- 3. Save and run `python data/update.py`.
339
 
340
- > ⚠️ If users have saved scenario files (`.xlsx` or `.zip`) that reference the old name, those files will no longer load correctly after the rename.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
  ---
343
 
344
- ## Case 8 — Edit tooltip texts (hover descriptions)
345
 
346
  **When to use:** You want to add, update, or remove the short description that appears when a user hovers over a resource or method name in the app.
347
 
348
- **Steps:**
349
 
350
- 1. Open `data/tooltips.xlsx`.
351
- 2. Go to the relevant sheet:
352
- - **Resources** — for the hover text on resource names (Tab 1 "Resource Inputs")
353
- - **Methods** — for the hover text on method names (Tab 2 "Method Constraints")
354
- 3. Find the row with the name you want to edit. All resource and method names are already listed — you only need to fill in or change the `Tooltip` column.
355
- 4. To **add** a tooltip: type the text in the `Tooltip` cell for that row.
356
- 5. To **remove** a tooltip: leave the `Tooltip` cell empty.
357
- 6. Save the file.
358
- 7. Restart the app (no need to run `update.py`).
359
 
360
- > ⚠️ The name in column `Resource` or `Method` must match **exactly** the name used in `inputs_aggregated.csv` (same spelling, same capitalisation). If you rename a method or resource in the CSV, remember to update the name in `tooltips.xlsx` too.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
 
362
  ---
363
 
364
- ## Case 10 — Change the display order of methods or resources
365
 
366
- **When to use:** You want a method or resource group to appear earlier or later in the app.
367
 
368
- **Steps:**
 
 
 
 
 
 
 
 
369
 
370
  1. Open `data/inputs_aggregated.csv`.
371
- 2. Move the relevant rows up or down. The app displays methods and resource groups **in the same order as they appear in the CSV**.
372
- 3. Save and run `python data/update.py`.
 
 
 
 
 
 
 
 
 
373
 
374
  ---
375
 
376
- ## After any change — checklist
377
 
378
  **Option 1 (Hugging Face direct):**
379
  - [ ] Edited and committed `inputs_aggregated.csv` on Hugging Face
380
- - [ ] Checked the Space logs — confirmed `Data files updated successfully.`
381
  - [ ] Verified the change appears correctly in the app
382
 
383
  **Option 2 (local):**
384
  - [ ] Saved `inputs_aggregated.csv`
385
- - [ ] Ran `python data/update.py` with no errors
 
386
  - [ ] Committed all modified files (CSV, JSON files, templates) and pushed
387
- - [ ] Verified the change appears correctly in the app after the Space rebuilt
388
-
389
- ---
390
-
391
- ## Common mistakes
392
-
393
- | Mistake | What happens | Fix |
394
- |---------|-------------|-----|
395
- | Typo in `Method group` or `Resource group` | A new accidental group is created in the app | Fix the typo and re-run `update.py` |
396
- | Wrong unit (e.g., `MWh/MtCO2` instead of `Mha/MtCO2`) | The resource appears in the wrong group or breaks the unit display | Correct the `Unit` column |
397
- | Edited a JSON file directly | Changes are overwritten next time `update.py` runs | Always edit the CSV, never the JSON |
398
- | Forgot to run `update.py` | The app still shows the old data | Run `python data/update.py` |
399
- | `min` value equals `max` value | The model automatically halves the `min` to create a range | Intentional for fixed-value resources like Geologic storage — leave as is |
400
 
401
  ---
402
 
403
  ## Library Maintenance Guide
404
 
405
- This section explains how to keep the tool's software dependencies up to date — safely and without breaking anything.
406
 
407
  ---
408
 
@@ -410,7 +583,7 @@ This section explains how to keep the tool's software dependencies up to date
410
 
411
  The tool is built on top of external software packages ("libraries") that handle things like displaying the interface, reading Excel files, or running the optimization. These libraries are listed in `requirements.txt` with their exact version numbers (e.g., `streamlit==1.45.1`).
412
 
413
- Libraries sometimes release updates — fixing bugs, patching security holes, or adding new features. The risk is that an update can also change how a library behaves and break the tool.
414
 
415
  ---
416
 
@@ -420,15 +593,15 @@ These are the libraries that matter most for this tool:
420
 
421
  | Library | Role | Risk if updated |
422
  |---------|------|----------------|
423
- | **streamlit** | Powers the entire web interface (tabs, sliders, buttons, charts) — currently 1.58.0 | 🔴 High — UI layout and widget behavior can change |
424
- | **streamlit-option-menu** | The navigation sidebar menu | 🟡 Medium — must stay compatible with streamlit version |
425
- | **pandas** | Reads and processes CSV and Excel files | 🟡 Medium — occasional API changes |
426
- | **numpy** | Numerical operations (arrays, math) | 🟡 Medium — used by scipy and pandas |
427
- | **scipy** | Runs the LP optimization (`linprog`) | 🟡 Medium — optimization results could change |
428
- | **plotly** | All charts and interactive graphs | 🟡 Medium — chart API evolves |
429
- | **openpyxl** | Reads and writes Excel files (.xlsx) | 🟢 Low — stable API |
430
  | **pillow** | Image handling (indirect use) | 🟢 Low |
431
- | **requests / urllib3 / certifi** | Network and security | 🟢 Low — update freely for security patches |
432
 
433
  ---
434
 
@@ -462,13 +635,14 @@ openpyxl ──────────────► pillow
462
  ### When to update
463
 
464
  #### ✅ Update immediately
465
- - **Security vulnerabilities** in `requests`, `urllib3`, `certifi`, or `pillow` — these are reported publicly and should be patched fast.
 
466
  - Check https://pypi.org/project/[library-name] or subscribe to GitHub security alerts.
467
 
468
  #### ✅ Update when needed
469
- - **Streamlit** — when a new feature in the app requires it, or when a critical bug in the current version is causing problems.
470
- - **pandas / numpy / scipy** — when a bug in the current version is causing incorrect data processing or optimization results.
471
- - **openpyxl** — when Excel import/export breaks with newer `.xlsx` files.
472
 
473
  #### ❌ Do NOT update just because a newer version exists
474
  - "Latest is always better" is not true for production tools. An update that works fine in isolation can break interactions between libraries.
@@ -476,17 +650,29 @@ openpyxl ──────────────► pillow
476
 
477
  ---
478
 
 
 
 
 
 
 
 
 
 
 
 
 
479
  ### How to safely update a library
480
 
481
  **Never update all libraries at once.** Update one at a time, test the tool after each one.
482
 
483
- **Step 1 — Back up the current working state**
484
 
485
  ```
486
  cp requirements.txt requirements.txt.backup
487
  ```
488
 
489
- **Step 2 — Simulate first (dry run)**
490
 
491
  Before applying anything, check whether the update would cause conflicts:
492
  ```
@@ -494,7 +680,7 @@ pip install --upgrade streamlit --dry-run
494
  ```
495
  If pip reports conflicts, investigate before proceeding.
496
 
497
- **Step 3 — Update the library**
498
 
499
  ```
500
  pip install --upgrade streamlit
@@ -505,20 +691,21 @@ Or to a specific version:
505
  pip install streamlit==1.58.0
506
  ```
507
 
508
- **Step 4 — Verify no dependencies are broken**
509
 
510
  ```
511
  pip check
512
  ```
513
- This confirms that all installed packages are mutually compatible. If it reports any conflict, do not proceed to the next step — restore the backup instead (see Step 6).
514
 
515
- **Step 5 — Freeze the new versions to requirements.txt**
516
 
517
  ```
518
  pip freeze > requirements.txt
519
  ```
 
520
 
521
- **Step 6 — Test the tool**
522
 
523
  - Start the app: `streamlit run app.py`
524
  - Go through every tab
@@ -526,7 +713,7 @@ pip freeze > requirements.txt
526
  - Run an optimization
527
  - Check that charts display correctly
528
 
529
- **Step 7 — If something breaks**
530
 
531
  Restore the backup:
532
  ```
@@ -534,6 +721,14 @@ pip install -r requirements.txt.backup
534
  cp requirements.txt.backup requirements.txt
535
  ```
536
 
 
 
 
 
 
 
 
 
537
  ---
538
 
539
  ### How to install all libraries on a new machine
@@ -547,18 +742,6 @@ pip install -r requirements.txt
547
 
548
  ---
549
 
550
- ### Checking for outdated libraries
551
-
552
- To see which installed libraries have newer versions available:
553
-
554
- ```
555
- pip list --outdated
556
- ```
557
-
558
- This shows a list with current and latest versions. Use this to **identify** what could be updated — but don't update everything at once.
559
-
560
- ---
561
-
562
  ### Checking for known security vulnerabilities
563
 
564
  Install the security scanner:
@@ -573,15 +756,15 @@ pip-audit
573
 
574
  This will flag any library with a known security issue and suggest a fix. These should be addressed promptly.
575
 
576
- > **Recommended frequency:** run `pip-audit` at least once a year, even if the tool appears stable. Security vulnerabilities are discovered independently of whether the library has changed — a version that was safe last year may be flagged today.
577
 
578
  ---
579
 
580
  ### Using an AI assistant to handle updates
581
 
582
- Library updates sometimes require code changes alongside the pip update — for example, a deprecated function that was renamed, or a new argument that became required. Doing this manually requires reading changelogs, finding every affected line, and testing the result.
583
 
584
- An AI coding assistant such as **Claude Code** (available at [claude.ai/code](https://claude.ai/code)) can handle this end-to-end:
585
 
586
  - Run `pip-audit` or `pip list --outdated` and paste the output into Claude Code
587
  - Describe the update you want to make (e.g., "update pandas and fix any deprecation warnings")
@@ -602,6 +785,4 @@ This is especially useful when:
602
  Security fix needed? ──► Update immediately (requests, urllib3, certifi, pillow)
603
  Something is broken? ──► Update only the relevant library, test thoroughly
604
  Nothing is broken? ──► Do not update
605
- ```
606
-
607
- ---
 
15
 
16
  ---
17
 
18
+ ## Table of contents
19
+
20
+ - [Data Maintenance Guide](#data-maintenance-guide)
21
+ - [How it works](#how-it-works-overview)
22
+ - [Option 1: Hugging Face](#option-1-edit-directly-on-hugging-face-no-local-setup-needed)
23
+ - [Option 2: Local](#option-2-work-locally)
24
+ - [Quick reference](#quick-reference-where-is-each-parameter)
25
+ - [File structure](#file-structure-what-each-file-does)
26
+ - [Understanding inputs_aggregated.csv](#understanding-inputs_aggregatedcsv)
27
+ - [Maintenance cases](#maintenance-cases)
28
+ - [Before you start](#before-you-start)
29
+ - [Case 1 - Modify existing coefficient values](#case-1--modify-existing-coefficient-values)
30
+ - [Case 2 - Add an existing resource to an existing method](#case-2--add-an-existing-resource-to-an-existing-method)
31
+ - [Case 3 - Add a new CDR method](#case-3--add-a-new-cdr-method)
32
+ - [(OPTIONAL) Case 3b - Add a derived CDR method](#optional-case-3b--add-a-derived-cdr-method-variant-of-an-existing-method)
33
+ - [Case 4 - Add a new resource](#case-4--add-a-new-resource)
34
+ - [Case 5 - Add a new resource group](#case-5--add-a-new-resource-group-new-category)
35
+ - [Case 6 - Change whether a resource is optional](#case-6--change-whether-a-resource-is-optional-secondary-for-a-method)
36
+ - [Case 7 - Rename a method or resource](#case-7--rename-a-method-or-resource)
37
+ - [Case 8 - Edit tooltip texts](#case-8--edit-tooltip-texts-hover-descriptions)
38
+ - [Case 10 - Change the display order](#case-10--change-the-display-order-of-methods-or-resources)
39
+ - [After any change - checklist](#after-any-change--checklist)
40
+ - [Library Maintenance Guide](#library-maintenance-guide)
41
+ - [What is a library?](#what-is-a-library-dependency)
42
+ - [The key libraries](#the-key-libraries-and-what-they-do)
43
+ - [Dependency chain](#dependency-chain-what-depends-on-what)
44
+ - [When to update](#when-to-update)
45
+ - [How to safely update](#how-to-safely-update-a-library)
46
+ - [Install on a new machine](#how-to-install-all-libraries-on-a-new-machine)
47
+ - [Check for outdated libraries](#checking-for-outdated-libraries)
48
+ - [Check for vulnerabilities](#checking-for-known-security-vulnerabilities)
49
+ - [Using AI to handle updates](#using-an-ai-assistant-to-handle-updates)
50
+ - [Summary: update strategy](#summary-update-strategy)
51
+
52
+ ---
53
+
54
  ## Data Maintenance Guide
55
 
56
+ This guide is for Carbon Gap staff who need to update the tool's data: **no coding experience required** for most tasks.
57
 
58
  ---
59
 
 
65
  data/inputs_aggregated.csv
66
  ```
67
 
68
+ Every time the app starts, it computes a fingerprint (hash) of the CSV and compares it to the last known value. If they differ, meaning the CSV has been modified, it automatically regenerates all the data files used by the application before loading. You do not need to run anything manually.
69
 
70
+ There are two ways to update the data, depending on whether you are working directly on Hugging Face or on a local copy of the project:
71
 
72
+ ### Option 1: Edit directly on Hugging Face (no local setup needed)
 
 
73
 
74
  This is the simplest option for non-coders with admin access to the Hugging Face Space.
75
 
76
  **Steps:**
77
 
78
+ 1. Go to the Hugging Face **Space** (Carbon Dioxide Removal Toolkit) → click the **Files** tab
79
+ 2. Open `data/inputs_aggregated.csv` and click **Edit** (pencil icon)
80
+ *OR*
81
+ Upload a new version of the file: click **Delete** `data/inputs_aggregated.csv`, then go to **data** folder → click **+ Contribute** → Upload Files
82
+ 4. Commit the change directly on Hugging Face (checkbox *Commit directly to the main branch*): the Space will restart automatically
83
+ 5. **Check the logs** to confirm the update ran:
84
+ - In the Space, click **⋮ **Logs** (The button at the very top, next to *Running*)
85
  - You should see:
86
  ```
87
+ inputs_aggregated.csv has changed - running data/update.py ...
88
  [... update details ...]
89
  Data files updated successfully.
90
  ```
91
+ 6. If the logs show this message, the app is running with the new data. If not, something went wrong: try option 2 or contact a developer. You may also not have waited long enough or, conversely, you may have waited too long before checking the logs: check whether the app has successfully applied your changes.
92
 
93
  > **Note:** with this option, only `inputs_aggregated.csv` needs to be uploaded. The app handles the rest automatically on restart.
94
 
95
+ ### Option 2: Work locally
96
 
97
+ Use this option when making bigger changes where you want to preview the result before publishing.
98
 
99
+ **Step 1: Get the project on your machine**
100
+
101
+ If you do not already have git installed:
102
+ - Mac: install it via https://git-scm.com/download/mac
103
+ - Windows: install it via https://git-scm.com/download/win
104
+ -
105
+ Then in a terminal, navigate to the folder where you want to put the project and run:
106
+ ```
107
+ git clone <repository URL>
108
+ ```
109
+ Example:
110
+ ```
111
+ git clone https://huggingface.co/spaces/CarbonGap/CRRA_Optimization_Tool
112
+ ```
113
 
114
+ **Step 1b: Set up the Python environment (first time only)**
115
 
116
+ If you just cloned the repo, the venv/ folder doesn't exist yet. Create it by running in the terminal:
 
 
117
 
118
+ ```
119
+ python -m venv venv
120
+ ```
121
+
122
+ Then activate it and install the dependencies:
123
+ ```
124
+ source venv/bin/activate # Mac / Linux
125
+ venv\Scripts\activate # Windows
126
+ ```
127
+
128
+ You should now see `(venv)` at the start of your terminal line.
129
+
130
+ ```
131
+ pip install -r requirements.txt
132
+ ```
133
+ You only need to do this once per machine. After that, just activate the environment (Step 3) each time.
134
+
135
+ **Step 2: Edit the CSV**
136
 
137
  Open `data/inputs_aggregated.csv` in Excel or any spreadsheet editor. Make your changes and save.
138
 
139
+ **Step 3: Open a terminal in the project folder**
140
 
141
+ You can use any of the following:
142
+
143
+ - In your code editor (VS Code, PyCharm, etc.): open the integrated terminal, it's usually already pointing to the project folder
144
  - Mac: right-click the project folder → **New Terminal at Folder**
145
  - Windows: open the folder, click in the address bar, type `cmd`, press Enter
146
 
 
150
  venv\Scripts\activate # Windows
151
  ```
152
 
153
+ **Step 4: Start the app to verify**
154
 
155
  ```
156
+ streamlit run app.py
157
  ```
158
 
159
+ The app detects that the CSV has changed and automatically runs the update script before loading. Check the terminal output: it should say `Data files updated successfully.` Then browse the app to confirm the change looks correct.
160
 
161
+ > If the auto-update doesn't seem to work (no message in the terminal), you can trigger it manually as a fallback: `python data/update.py`
162
 
163
+ **Step 5: Commit and push**
164
+
165
+ In the terminal:
166
+ ```
167
+ git add -A -- ':!venv/'
168
+ git commit -m "Your description here (e.g. Update coefficients for Afforestation)"
169
+ git push
170
+ ```
171
 
172
  Hugging Face will detect the push and rebuild the Space automatically.
173
 
174
  ---
175
 
176
+ ### Quick reference: where is each parameter?
177
 
178
  | I want to change… | File | Where exactly |
179
  |---|---|---|
180
+ | A coefficient value (min / median / max) | `data/inputs_aggregated.csv` | Columns `min`, `median`, `max`: find the row by `Implementation` + `Resource` |
181
+ | The name of a CDR method | `data/inputs_aggregated.csv` | Column `Implementation |
182
  | Which group a CDR method belongs to | `data/inputs_aggregated.csv` | Column `Method group` |
183
+ | The name of a resource | `data/inputs_aggregated.csv` | Column `Resource` |
184
  | Which group a resource belongs to | `data/inputs_aggregated.csv` | Column `Resource group` |
185
+ | The unit of a resource group | `data/inputs_aggregated.csv` | Column `Unit`: must be consistent across all rows for that group |
186
+ | Whether a resource is optional for a method | `data/inputs_aggregated.csv` | Column `Is secondary`: `TRUE` = optional, `FALSE` = always active |
187
+ | The display order of methods or resources | `data/inputs_aggregated.csv` | Row order: in the app, groups are displayed in the order their first row is encountered in the CSV; within a group, methods or resources are displayed in the order their rows appear. Move rows up/down to reorder |
188
+ | The app's UI colours (background, buttons, links) | `.streamlit/config.toml` | `primaryColor`, `backgroundColor`, `secondaryBackgroundColor`, `textColor` |
189
+ | The chart colours (Plotly graphs) | `config/config.py` | `CRRA_COLORS` dictionary |
190
+ | The app's UI font | `.streamlit/config.toml` | `font` - accepted values: `"sans-serif"`, `"serif"`, `"monospace"` |
191
+ | The chart font (Plotly graphs) | `config/config.py` | `CRRA_FONT` variable |
192
+ | The app's UI colours and font (fine-tuned overrides) | `assets/styles.css` | `:root` block at the top of the file - change the hex values next to each variable name |
193
+ | The tooltip text on a method name | `data/tooltips.xlsx` | Sheet **Methods**: column `Tooltip` |
194
+ | The tooltip text on a resource name | `data/tooltips.xlsx` | Sheet **Resources**: column `Tooltip` |
195
+ | UI spacing, font sizes, button styles | `assets/styles.css` | Standard CSS: search for the element name |
196
+ | Python library versions | `requirements.txt` | One line per library: see Library Maintenance Guide below |
197
+
198
+ > After any change to `inputs_aggregated.csv`, start the app - it detects the change and updates automatically. After changes to `config/config.py`, `assets/styles.css`, or `data/tooltips.xlsx`, simply restart the app.
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
  ### File structure (what each file does)
201
 
202
  | File | What it is | Do you edit it? |
203
  |------|-----------|-----------------|
204
+ | `data/inputs_aggregated.csv` | **Main data file**: all methods, resources and coefficients | ✅ Yes |
205
  | `data/update.py` | Script that regenerates everything from the CSV | ❌ No |
206
+ | `data/cost_sliders.json` | Auto-generated. Coefficients used by the app | ❌ No (auto) |
207
+ | `data/method_groups.json` | Auto-generated. CDR method categories | ❌ No (auto) |
208
+ | `data/secondary_resources.json` | Auto-generated. optional resource assignments | ❌ No (auto) |
209
+ | `data/inputs_template.xlsx` | Auto-generated. Excel template for users | ❌ No (auto) |
210
+ | `data/resource_template.xlsx` | Auto-generated. Excel template for users | ❌ No (auto) |
211
+ | `data/tooltips.xlsx` | Tooltip texts shown on hover in the app | ✅ Yes |
212
 
213
+ > ⚠️ **Never edit the auto-generated files directly**: your changes will be overwritten the next time `update.py` is run.
 
 
214
 
215
  ### Understanding `inputs_aggregated.csv`
216
 
 
230
  | `Is secondary` | Whether this resource is optional for this method | `FALSE` |
231
 
232
  > **Primary resources** (`Is secondary = FALSE`) are always active in the model.
233
+ > **Secondary resources** (`Is secondary = TRUE`) are optional: users can toggle them on in the app.
234
+
235
+ ---
236
+
237
+ ## Maintenance cases
238
+
239
+ ### Before you start
240
+
241
+ Each case below covers two workflows:
242
+ - **Option 1 - Hugging Face:** edit directly in the browser, no local setup needed.
243
+ - **Option 2 - Local:** make changes on your machine, then push to Hugging Face.
244
+
245
+ For Option 2, make sure the project is cloned and the Python environment is set up (see [Option 2](#option-2-work-locally) at the top of this guide). Before running any command in the terminal, activate the environment:
246
+
247
+ ```
248
+ source venv/bin/activate # Mac / Linux
249
+ venv\Scripts\activate # Windows
250
+ ```
251
+
252
+ You should see `(venv)` at the start of your terminal line.
253
+
254
+ > **For all Option 2 cases below:** after editing the CSV, start the app (`streamlit run app.py`) to verify - it detects the change and runs the update automatically. If the auto-update doesn't trigger (no message in the terminal), run `python data/update.py` manually as a fallback.
255
 
256
  ---
257
 
258
+ ### Case 1 - Modify existing coefficient values
259
 
260
  **When to use:** The literature has been updated and you want to change the min/median/max values for an existing method-resource pair.
261
 
262
+ **Option 1 - On Hugging Face**
263
+
264
+ 1. In the Space, click the **Files** tab.
265
+ 2. Open `data/inputs_aggregated.csv` → click the **pencil icon** to edit inline.
266
+ 3. Find the row with the correct `Implementation` and `Resource`. Edit the `min`, `median`, and/or `max` columns.
267
+ 4. Scroll down → **Commit directly to main branch** → **Commit changes to main**.
268
+ 5. The Space restarts. Click **Logs** to confirm: `Data files updated successfully.`
269
+
270
+ **Option 2 - Locally**
271
 
272
  1. Open `data/inputs_aggregated.csv` in Excel or a text editor.
273
  2. Find the row with the correct `Implementation` and `Resource`.
274
  3. Edit the `min`, `median`, and/or `max` columns.
275
+ 4. Save the file, then start the app to verify:
 
276
  ```
277
+ streamlit run app.py
278
+ ```
279
+ 5. Commit and push:
280
+ ```
281
+ git add -A -- ':!venv/'
282
+ git commit -m "Update coefficients for [method name] and [resource name]"
283
+ git push
284
  ```
285
 
286
+ ### Case 2 - Add an existing resource to an existing method
287
 
288
+ **When to use:** A CDR method should now also use a resource that is already tracked for other methods (e.g., water is already listed for other methods, and you want to add it to Afforestation too). If the resource doesn't exist at all yet, use Case 4 first.
289
 
290
+ **Option 1 - On Hugging Face**
291
 
292
+ 1. In the Space, click **Files** → open `data/inputs_aggregated.csv` → click the pencil icon.
293
+ 2. Add a new row, making sure to include all the expected columns (see [Understanding inputs_aggregated.csv](#understanding-inputs_aggregatedcsv)).
294
+ 3. Commit directly to main → Space restarts. Check Logs for `Data files updated successfully.`
295
 
296
+ **Option 2 - Locally**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
 
298
+ 1. Open `data/inputs_aggregated.csv` and add a new row (see [Understanding inputs_aggregated.csv](#understanding-inputs_aggregatedcsv)).
299
+ 2. Save the file, then start the app to verify:
300
+ ```
301
+ streamlit run app.py
302
+ ```
303
+ 3. Commit and push:
304
+ ```
305
+ git add -A -- ':!venv/'
306
+ git commit -m "Add [resource name] to [method name]"
307
+ git push
308
+ ```
309
 
310
+ ### Case 3 - Add a new CDR method
311
 
312
  **When to use:** A new carbon removal approach needs to be added to the tool.
313
 
314
+ **Option 1 - On Hugging Face**
315
 
316
+ 1. In the Space, click **Files** → open `data/inputs_aggregated.csv` → click the pencil icon.
317
+ 2. Add **one row per resource** the new method uses (see [Understanding inputs_aggregated.csv](#understanding-inputs_aggregatedcsv)). Use an existing `Method group` or create a new one.
318
+ 3. Place the rows where you want the method to appear: display order follows row order in the CSV.
319
+ 4. Commit directly to main → Space restarts. Check Logs for `Data files updated successfully.`
320
 
321
+ **Option 2 - Locally**
322
 
323
+ 1. Open `data/inputs_aggregated.csv`.
324
+ 2. Add one row per resource used by the new method. Fill in all columns (see [Understanding inputs_aggregated.csv](#understanding-inputs_aggregatedcsv)).
325
+ 3. Save the file, then start the app to verify:
326
+ ```
327
+ streamlit run app.py
328
+ ```
329
+ 4. Commit and push:
330
+ ```
331
+ git add -A -- ':!venv/'
332
+ git commit -m "Add new CDR method: [method name]"
333
+ git push
334
+ ```
335
 
336
+ > ⚠️ **Special case - derived methods:** see Case 3b below.
337
 
338
  ---
339
 
340
+ ### (OPTIONAL) Case 3b - Add a derived CDR method (variant of an existing method)
341
 
342
  **What is a derived method?**
343
+ Some methods in the tool are not standalone entries in the CSV: they are automatically generated as **variants** of a base method. For example:
344
  - `Bio-char` in the CSV → generates 3 variants in the app: `Bio-char - Forest biomass`, `Bio-char - Non-forest biomass`, `Bio-char - Unspecified biomass`
345
  - `Enhanced weathering` in the CSV → generates 4 variants: one per mineral type
346
 
347
+ Each variant is identical to the base method **except** it only keeps the resource relevant to that variant.
348
 
349
  **When to use:** You want to add a new variant of an existing method (e.g. a new mineral type for Enhanced weathering, or a new biomass type for Bio-char).
350
 
351
+ > ⚠️ This case requires editing Python code. If you are not comfortable with this, contact the developer - provide the name of the new variant and which resource it should keep, and they can add the 5–10 lines needed.
352
 
353
+ **Option 1 - On Hugging Face (developers only)**
354
+
355
+ Hugging Face allows editing Python files inline via the pencil icon. Follow the same steps as Option 2 but make all edits directly in the browser. Not recommended for non-coders.
356
+
357
+ **Option 2 - Locally**
358
+
359
+ 1. Open `data/inputs_aggregated.csv` and make sure the base method has a row for the new resource.
360
 
361
  2. Open `data/generate_model_data.py`. Find the two structures at the top of the file:
362
 
363
+ **`REPLACED_BY_DERIVED`**: lists base methods fully replaced by their variants (the base name disappears from the app):
364
  ```
365
  REPLACED_BY_DERIVED = {"Bio-char", "Enhanced weathering"}
366
  ```
367
+ If your new base method should disappear once variants exist, add its name here.
368
 
369
+ **`DERIVED_FROM`**: maps each base method to its list of variant names (in display order):
370
  ```
371
  DERIVED_FROM = {
372
  "Bio-char": ["Bio-char - Forest biomass", ...],
 
374
  ...
375
  }
376
  ```
377
+ Add the new variant name to the relevant list.
378
 
379
+ 3. Further down in `create_sliders_inputs()`, add the derivation logic for the new variant: copy the pattern used for Bio-char or Enhanced weathering: copy the base method's coefficients, then remove the resources that don't apply to this variant.
380
 
381
+ 4. Save both files and run:
382
  ```
383
  python data/update.py
384
  ```
385
+ 5. Commit and push:
386
+ ```
387
+ git add -A -- ':!venv/'
388
+ git commit -m "Add derived method: [variant name]"
389
+ git push
390
+ ```
391
 
392
  ---
393
 
394
+ ### Case 4 - Add a new resource
395
 
396
+ **When to use:** A resource that doesn't exist yet needs to be used (e.g., a new type of mineral or energy).
397
 
398
+ **Option 1 - On Hugging Face**
 
 
399
 
400
+ 1. Decide which **Resource group** the new resource belongs to. If it belongs to an existing group, use the exact same name. If it needs its own group, see Case 5.
401
+ 2. In the Space, click **Files** → open `data/inputs_aggregated.csv` → pencil icon.
402
+ 3. Add one row per method that uses this resource (see column descriptions in Case 2).
403
+ 4. **Check the unit:** all resources in a group must share the same unit (e.g., all `Land` resources use `Mha/MtCO2`). If the unit differs, create a new group (Case 5).
404
+ 5. Commit directly to main → Space restarts. Check Logs.
405
 
406
+ **Option 2 - Locally**
407
 
408
+ 1. Decide which Resource group the new resource belongs to.
409
+ 2. Open `data/inputs_aggregated.csv` and add one row per method that uses this resource.
410
+ 3. Verify the unit is consistent with the rest of the group.
411
+ 4. Save, then start the app to verify:
412
+ ```
413
+ streamlit run app.py
414
+ ```
415
+ 5. Commit and push:
416
+ ```
417
+ git add -A -- ':!venv/'
418
+ git commit -m "Add new resource: [resource name]"
419
+ git push
420
+ ```
421
 
422
  ---
423
 
424
+ ### Case 5 - Add a new resource group (new category)
425
 
426
  **When to use:** Your new resource doesn't fit any existing category.
427
 
428
+ **Option 1 - On Hugging Face**
429
+
430
+ Same steps as Case 4, but write a **new group name** (never used before) in the `Resource group` column. The app will create a new section for it automatically. Place the rows where you want the group to appear: it appears at the position of its first row in the CSV.
431
 
432
+ **Option 2 - Locally**
433
 
434
+ Same steps as Case 4, but write a **new group name** in the `Resource group` column. The new group appears in the app at the position of its first row in the CSV.
435
 
436
  ---
437
 
438
+ ### Case 6 - Change whether a resource is optional (secondary) for a method
439
 
440
  **When to use:** You want to make a resource optional (user can enable/disable it) or make it always required.
441
 
442
+ **Option 1 - On Hugging Face**
443
+
444
+ 1. In the Space, click **Files** → open `data/inputs_aggregated.csv` → pencil icon.
445
+ 2. Find the row with the correct `Implementation` and `Resource`.
446
+ 3. Change `Is secondary` to `TRUE` (optional) or `FALSE` (always active).
447
+ 4. Commit directly to main → Space restarts. Check Logs.
448
+
449
+ **Option 2 - Locally**
450
 
451
  1. Open `data/inputs_aggregated.csv`.
452
  2. Find the row with the correct `Implementation` and `Resource`.
453
+ 3. Change `Is secondary` to `TRUE` (optional) or `FALSE` (always active).
454
+ 4. Save, then start the app to verify:
455
+ ```
456
+ streamlit run app.py
457
+ ```
458
+ 5. Commit and push:
459
+ ```
460
+ git add -A -- ':!venv/'
461
+ git commit -m "Update secondary status for [resource] in [method]"
462
+ git push
463
+ ```
464
 
465
  ---
466
 
467
+ ### Case 7 - Rename a method or resource
468
 
469
  **When to use:** Correcting a spelling mistake or updating nomenclature.
470
 
471
+ > ⚠️ If users have saved scenario files (`.xlsx` or `.zip`) that reference the old name, those files will no longer load correctly after the rename.
472
 
473
+ **Option 1 - On Hugging Face**
 
 
474
 
475
+ Editing inline is not recommended for a rename because Find & Replace is not available in the browser editor. Instead:
476
+ 1. Download `data/inputs_aggregated.csv` from the Files tab.
477
+ 2. Open it in Excel. Use **Find & Replace** (Ctrl+H / Cmd+H) to replace the old name with the new name in the `Implementation` / `Resource` columns and, if the group name changed, in `Method group` / `Resource group`.
478
+ 3. Also download `data/tooltips.xlsx`, update the name in the `Method` or `Resource` column of the relevant sheet, and save.
479
+ 4. Upload both files via **Files** → `data/` folder → **+ Contribute** → **Upload Files** → Commit.
480
+ 5. Space restarts → check Logs.
481
+
482
+ **Option 2 - Locally**
483
+
484
+ 1. Open `data/inputs_aggregated.csv`. Use **Find & Replace** (Ctrl+H / Cmd+H) to replace the old name everywhere in the file.
485
+ 2. Open `data/tooltips.xlsx` and update the name in the `Method` or `Resource` column of the relevant sheet. Save.
486
+ 3. Start the app to verify:
487
+ ```
488
+ streamlit run app.py
489
+ ```
490
+ 4. Commit and push:
491
+ ```
492
+ git add -A -- ':!venv/'
493
+ git commit -m "Rename [old name] to [new name]"
494
+ git push
495
+ ```
496
 
497
  ---
498
 
499
+ ### Case 8 - Edit tooltip texts (hover descriptions)
500
 
501
  **When to use:** You want to add, update, or remove the short description that appears when a user hovers over a resource or method name in the app.
502
 
503
+ > ⚠️ The name in column `Resource` or `Method` must match **exactly** the name used in `inputs_aggregated.csv` (same spelling, same capitalisation). If you rename a method or resource in the CSV, remember to update the name in `tooltips.xlsx` too.
504
 
505
+ **Option 1 - On Hugging Face**
 
 
 
 
 
 
 
 
506
 
507
+ The `.xlsx` file cannot be edited inline on Hugging Face. Instead:
508
+ 1. In the Files tab, open the `data/` folder → download `tooltips.xlsx`.
509
+ 2. Open it in Excel. Go to the relevant sheet (**Resources** or **Methods**).
510
+ 3. Find the row with the name you want to edit. Fill in or change the `Tooltip` column. Leave it empty to remove a tooltip.
511
+ 4. Save the file.
512
+ 5. Back in the Files tab, go to `data/` → **+ Contribute** → **Upload Files**.
513
+ 6. Upload your edited `tooltips.xlsx` → Commit directly to main.
514
+ 7. The Space restarts. **No update script runs for tooltips** - the file is read directly by the app on each restart.
515
+
516
+ **Option 2 - Locally**
517
+
518
+ 1. Open `data/tooltips.xlsx` in Excel.
519
+ 2. Go to the relevant sheet (**Resources** or **Methods**).
520
+ 3. Find the row with the name you want to edit. Fill in or change the `Tooltip` column. Leave it empty to remove a tooltip.
521
+ 4. Save the file.
522
+ 5. Restart the app (`Ctrl+C` then `streamlit run app.py`). **No need to run `update.py`.**
523
+ 6. Commit and push:
524
+ ```
525
+ git add data/tooltips.xlsx
526
+ git commit -m "Update tooltip texts"
527
+ git push
528
+ ```
529
 
530
  ---
531
 
532
+ ### Case 10 - Change the display order of methods or resources
533
 
534
+ **When to use:** You want a method or resource group to appear earlier or later in the app (Resource inputs, Method constraints tabs...).
535
 
536
+ **Option 1 - On Hugging Face**
537
+
538
+ Moving rows is easier in Excel than in a browser editor:
539
+ 1. Download `data/inputs_aggregated.csv` from the Files tab.
540
+ 2. Open it in Excel. Move the relevant rows up or down - the app reads the CSV from top to bottom.
541
+ 3. Upload the updated file via **Files** → `data/` → **+ Contribute** → **Upload Files** → Commit.
542
+ 4. Space restarts → check Logs for `Data files updated successfully.`
543
+
544
+ **Option 2 - Locally**
545
 
546
  1. Open `data/inputs_aggregated.csv`.
547
+ 2. Move the relevant rows up or down.
548
+ 3. Save, then start the app to verify:
549
+ ```
550
+ streamlit run app.py
551
+ ```
552
+ 4. Commit and push:
553
+ ```
554
+ git add -A -- ':!venv/'
555
+ git commit -m "Reorder [methods/resources]"
556
+ git push
557
+ ```
558
 
559
  ---
560
 
561
+ ### After any change - checklist
562
 
563
  **Option 1 (Hugging Face direct):**
564
  - [ ] Edited and committed `inputs_aggregated.csv` on Hugging Face
565
+ - [ ] Checked the Space logs: confirmed `Data files updated successfully.`
566
  - [ ] Verified the change appears correctly in the app
567
 
568
  **Option 2 (local):**
569
  - [ ] Saved `inputs_aggregated.csv`
570
+ - [ ] Started the app locally (`streamlit run app.py`): confirmed `Data files updated successfully.` in the terminal
571
+ - [ ] Verified the change appears correctly in the app
572
  - [ ] Committed all modified files (CSV, JSON files, templates) and pushed
 
 
 
 
 
 
 
 
 
 
 
 
 
573
 
574
  ---
575
 
576
  ## Library Maintenance Guide
577
 
578
+ This section explains how to keep the tool's software dependencies up to date, safely and without breaking anything.
579
 
580
  ---
581
 
 
583
 
584
  The tool is built on top of external software packages ("libraries") that handle things like displaying the interface, reading Excel files, or running the optimization. These libraries are listed in `requirements.txt` with their exact version numbers (e.g., `streamlit==1.45.1`).
585
 
586
+ Libraries sometimes release updates - fixing bugs, patching security holes, or adding new features. The risk is that an update can also change how a library behaves and break the tool.
587
 
588
  ---
589
 
 
593
 
594
  | Library | Role | Risk if updated |
595
  |---------|------|----------------|
596
+ | **streamlit** | Powers the entire web interface (tabs, sliders, buttons, charts) - currently 1.58.0 | 🔴 High - UI layout and widget behavior can change |
597
+ | **streamlit-option-menu** | The navigation sidebar menu | 🟡 Medium - must stay compatible with streamlit version |
598
+ | **pandas** | Reads and processes CSV and Excel files | 🟡 Medium - occasional API changes |
599
+ | **numpy** | Numerical operations (arrays, math) | 🟡 Medium - used by scipy and pandas |
600
+ | **scipy** | Runs the LP optimization (`linprog`) | 🟡 Medium - optimization results could change |
601
+ | **plotly** | All charts and interactive graphs | 🟡 Medium - chart API evolves |
602
+ | **openpyxl** | Reads and writes Excel files (.xlsx) | 🟢 Low - stable API |
603
  | **pillow** | Image handling (indirect use) | 🟢 Low |
604
+ | **requests / urllib3 / certifi** | Network and security | 🟢 Low - update freely for security patches |
605
 
606
  ---
607
 
 
635
  ### When to update
636
 
637
  #### ✅ Update immediately
638
+ - **`pip-audit` flags a vulnerability** - run `pip-audit` regularly (see [Check for vulnerabilities](#checking-for-known-security-vulnerabilities)); any flagged library should be patched without delay.
639
+ - **Security vulnerabilities** in `requests`, `urllib3`, `certifi`, or `pillow` - these are reported publicly and should be patched fast even before `pip-audit` catches them.
640
  - Check https://pypi.org/project/[library-name] or subscribe to GitHub security alerts.
641
 
642
  #### ✅ Update when needed
643
+ - **Streamlit** - when a new feature in the app requires it, or when a critical bug in the current version is causing problems.
644
+ - **pandas / numpy / scipy** - when a bug in the current version is causing incorrect data processing or optimization results.
645
+ - **openpyxl** - when Excel import/export breaks with newer `.xlsx` files.
646
 
647
  #### ❌ Do NOT update just because a newer version exists
648
  - "Latest is always better" is not true for production tools. An update that works fine in isolation can break interactions between libraries.
 
650
 
651
  ---
652
 
653
+ ### Checking for outdated libraries
654
+
655
+ To see which installed libraries have newer versions available:
656
+
657
+ ```
658
+ pip list --outdated
659
+ ```
660
+
661
+ This shows a list with current and latest versions. Use this to **identify** what could be updated but don't update everything at once.
662
+
663
+ ---
664
+
665
  ### How to safely update a library
666
 
667
  **Never update all libraries at once.** Update one at a time, test the tool after each one.
668
 
669
+ **Step 1 - Back up the current working state**
670
 
671
  ```
672
  cp requirements.txt requirements.txt.backup
673
  ```
674
 
675
+ **Step 2 - Simulate first (dry run)**
676
 
677
  Before applying anything, check whether the update would cause conflicts:
678
  ```
 
680
  ```
681
  If pip reports conflicts, investigate before proceeding.
682
 
683
+ **Step 3 - Update the library**
684
 
685
  ```
686
  pip install --upgrade streamlit
 
691
  pip install streamlit==1.58.0
692
  ```
693
 
694
+ **Step 4 - Verify no dependencies are broken**
695
 
696
  ```
697
  pip check
698
  ```
699
+ This confirms that all installed packages are mutually compatible. If it reports any conflict, do not proceed to the next step - restore the backup instead (see Step 6).
700
 
701
+ **Step 5 - Freeze the new versions to requirements.txt**
702
 
703
  ```
704
  pip freeze > requirements.txt
705
  ```
706
+ `pip freeze` lists every library currently installed in the environment with its exact version number, and `> requirements.txt` writes that list into the file. This ensures that anyone who installs from `requirements.txt` later, including Hugging Face when the Space rebuilds, gets exactly the same versions you just tested.
707
 
708
+ **Step 6 - Test the tool**
709
 
710
  - Start the app: `streamlit run app.py`
711
  - Go through every tab
 
713
  - Run an optimization
714
  - Check that charts display correctly
715
 
716
+ **Step 7 - If something breaks**
717
 
718
  Restore the backup:
719
  ```
 
721
  cp requirements.txt.backup requirements.txt
722
  ```
723
 
724
+ **Step 8 - If everything works**
725
+
726
+ Delete the backup file, it's no longer needed:
727
+ ```
728
+ rm requirements.txt.backup
729
+ ```
730
+ Then commit the updated `requirements.txt` and push.
731
+
732
  ---
733
 
734
  ### How to install all libraries on a new machine
 
742
 
743
  ---
744
 
 
 
 
 
 
 
 
 
 
 
 
 
745
  ### Checking for known security vulnerabilities
746
 
747
  Install the security scanner:
 
756
 
757
  This will flag any library with a known security issue and suggest a fix. These should be addressed promptly.
758
 
759
+ > **Recommended frequency:** run `pip-audit` at least once a year, even if the tool appears stable. Security vulnerabilities are discovered independently of whether the library has changed - a version that was safe last year may be flagged today.
760
 
761
  ---
762
 
763
  ### Using an AI assistant to handle updates
764
 
765
+ Library updates sometimes require code changes alongside the pip update - for example, a deprecated function that was renamed, or a new argument that became required. Doing this manually requires reading changelogs, finding every affected line, and testing the result.
766
 
767
+ An AI coding assistant such as **Claude Code** can handle this end-to-end:
768
 
769
  - Run `pip-audit` or `pip list --outdated` and paste the output into Claude Code
770
  - Describe the update you want to make (e.g., "update pandas and fix any deprecation warnings")
 
785
  Security fix needed? ──► Update immediately (requests, urllib3, certifi, pillow)
786
  Something is broken? ──► Update only the relevant library, test thoroughly
787
  Nothing is broken? ──► Do not update
788
+ ```
 
 
app.py CHANGED
@@ -3,9 +3,13 @@ import os
3
  import sys
4
  import subprocess
5
  import pathlib
6
-
7
  import streamlit as st
8
  from streamlit_option_menu import option_menu
 
 
 
 
 
9
 
10
  # ── Auto-update: regenerate JSON files if inputs_aggregated.csv has changed ───
11
  # Uses a hash file to detect changes — works both locally and on Hugging Face.
@@ -36,12 +40,6 @@ if os.path.exists(csv):
36
  file.write(current_hash)
37
  print("Data files updated successfully.")
38
 
39
- from tabs import (tab0_welcome, tab1_inputs, tab2_constraints,
40
- tab3_coefficients, tab4_optimization, tab5_sensitivity,
41
- tab6_scenarios)
42
- from utils.data_utils import load_slider_data, strip_unit_suffix
43
- from config.config import method_order, secondary_resources
44
-
45
  st.set_page_config("Carbon Portfolio Optimizer", layout="wide")
46
 
47
  def load_css(file_path):
 
3
  import sys
4
  import subprocess
5
  import pathlib
 
6
  import streamlit as st
7
  from streamlit_option_menu import option_menu
8
+ from tabs import (tab0_welcome, tab1_inputs, tab2_constraints,
9
+ tab3_coefficients, tab4_optimization, tab5_sensitivity,
10
+ tab6_scenarios)
11
+ from utils.data_utils import load_slider_data, strip_unit_suffix
12
+ from config.config import method_order, secondary_resources
13
 
14
  # ── Auto-update: regenerate JSON files if inputs_aggregated.csv has changed ───
15
  # Uses a hash file to detect changes — works both locally and on Hugging Face.
 
40
  file.write(current_hash)
41
  print("Data files updated successfully.")
42
 
 
 
 
 
 
 
43
  st.set_page_config("Carbon Portfolio Optimizer", layout="wide")
44
 
45
  def load_css(file_path):
assets/styles.css CHANGED
@@ -6,16 +6,6 @@
6
  Font : Segoe UI, sans-serif
7
  ═══════════════════════════════════════════════════════════ */
8
 
9
- /* ── 0. Font face ──────────────────────────────────────────── */
10
- /* @font-face {
11
- font-family: 'Segoe UI';
12
- src: url(/app/static/fonts/segoe-ui-400.woff2) format('woff2'),
13
- url(/app/static/fonts/segoe-ui-400.woff) format('woff');
14
- font-weight: 400;
15
- font-style: normal;
16
- font-display: swap;
17
- } */
18
-
19
  /* ── 1. Variables ──────────────────────────────────────────── */
20
  :root {
21
  --off-white: #eae9d8;
@@ -53,20 +43,11 @@ input, textarea, select,
53
  background: var(--off-white) !important;
54
  }
55
 
 
56
  section[data-testid="stSidebar"] {
57
  width: 350px;
58
  }
59
 
60
- div[data-testid="stSidebarContent"] {
61
- position: fixed;
62
- top: 0;
63
- left: 0;
64
- width: inherit;
65
- height: 100vh;
66
- overflow-y: auto;
67
- z-index: 100;
68
- }
69
-
70
  /* ── 4. Markdown headings (st.markdown "### …") ────────────── */
71
  .stMarkdown h1 {
72
  font-weight: 700;
 
6
  Font : Segoe UI, sans-serif
7
  ═══════════════════════════════════════════════════════════ */
8
 
 
 
 
 
 
 
 
 
 
 
9
  /* ── 1. Variables ──────────────────────────────────────────── */
10
  :root {
11
  --off-white: #eae9d8;
 
43
  background: var(--off-white) !important;
44
  }
45
 
46
+ /* Default width — no !important so Streamlit's drag-to-resize JS can override it */
47
  section[data-testid="stSidebar"] {
48
  width: 350px;
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
51
  /* ── 4. Markdown headings (st.markdown "### …") ────────────── */
52
  .stMarkdown h1 {
53
  font-weight: 700;