Skip to content

75 notebooks#84

Open
dalonsoa wants to merge 6 commits into
mainfrom
75_notebooks
Open

75 notebooks#84
dalonsoa wants to merge 6 commits into
mainfrom
75_notebooks

Conversation

@dalonsoa

@dalonsoa dalonsoa commented Jul 16, 2026

Copy link
Copy Markdown

Description

Update the capacity notebook to account for the new output file structure - which is far from ideal from the processing perspective. Performance-wise, there are vectorised options that are faster than apply, but this one was more readable.

The output plot is:

Screenshot from 2026-07-16 08-50-09

Close #75

Type of change

  • Documentation (non-breaking change that adds or improves the documentation)
  • New feature (non-breaking change which adds functionality)
  • Optimization (non-breaking, back-end change that speeds up the code)
  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (whatever its nature)

Key checklist

  • All tests pass (eg. python -m pytest)
  • Pre-commit hooks run successfully (eg. pre-commit run --all-files)

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added or an issue has been opened to tackle that in the future.
    (Indicate issue here: # (issue))

Copilot AI review requested due to automatic review settings July 16, 2026 06:48
@dalonsoa
dalonsoa requested review from AdrianDAlessandro, dc2917 and tsmbland and removed request for Copilot July 16, 2026 06:50
@dalonsoa

Copy link
Copy Markdown
Author

The latest MUSE2 release uses the old file structure, so those tests are failing - but it is for a known reason.

@dc2917 dc2917 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable to me!

is far from ideal from the processing perspective. Performance-wise, there are vectorised options that are faster than apply, but this one was more readable.

I think for a notebook this sounds like a good approach.

@dalonsoa

Copy link
Copy Markdown
Author

This is the vectorised version, by the way:

# Try merging on asset_id first, then fall back to group_id for unmatched rows
merged = asset_capacities.merge(
    assets[["asset_id", "agent_id", "process_id", "commission_year"]],
    on="asset_id",
    how="left"
)

# Fill in rows where asset_id was None using group_id
mask = merged["agent_id"].isna()
fallback = asset_capacities[mask].merge(
    assets[["group_id", "agent_id", "process_id", "commission_year"]],
    on="group_id",
    how="left"
)

merged.loc[mask, ["agent_id", "process_id", "commission_year"]] = fallback[["agent_id", "process_id", "commission_year"]].values
asset_capacities = merged

@dc2917

dc2917 commented Jul 16, 2026

Copy link
Copy Markdown

This is the vectorised version, by the way:

Yeah, it's not that it's unclear, but it does make the process look more cumbersome, even if it's less work for the computer to do. I guess it depends on the purpose of the notebook?

@tsmbland tsmbland left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't quite right I'm afraid. asset_capacities.csv has a row for each asset in each year that it has capacity, so it's just a matter of merging this table with assets.csv to add metadata, then grouping by (milestone_year, agent_id, process_id) and summing. With some pandas trickery this can be relatively concise:

assets = pd.read_csv(OUTPUT_DIR / "assets.csv")
asset_capacities = pd.read_csv(OUTPUT_DIR / "asset_capacities.csv")

merged = asset_capacities.merge(assets, on=["asset_id", "group_id"])
agg_capacities = merged.groupby(["milestone_year", "agent_id", "process_id"])[
    "capacity"
].sum()
agg_capacities_wide = agg_capacities.unstack(["agent_id", "process_id"], fill_value=0)

agents = agg_capacities_wide.columns.get_level_values("agent_id").unique()
fig, axes = plt.subplots(1, len(agents), figsize=(4 * len(agents), 4))
for ax, agent in zip(axes, agents):
    agg_capacities_wide[agent].plot(
        kind="bar", stacked=True, ax=ax, title=agent, xlabel="Year", ylabel="Capacity"
    )

plt.tight_layout()

I think stacked bars look better as well

If we wanted to use something like seaborn I think this could be even more concise (e.g. no need to loop over agents)

Comment thread notebooks/capacity.ipynb Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now copy the input data to the output folder (EnergySystemsModellingLab/MUSE2#1282), so we can drop this.

I don't think we need to read model.toml anyway

Comment thread notebooks/capacity.ipynb Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is apparently no longer true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should remove this comment as it isn't true

Comment thread notebooks/capacity.ipynb Outdated
Comment on lines 50 to 58

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block needs updating

Comment thread notebooks/prices.ipynb Outdated
@dalonsoa

Copy link
Copy Markdown
Author

New plot:

image

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the example analysis notebooks to align with the new MUSE2 output file structure (splitting time-varying capacities into asset_capacities.csv and keeping metadata in assets.csv), and improves plot layout/legibility.

Changes:

  • Refactors the capacity notebook to compute invested capacity from asset_capacities.csv merged with metadata from assets.csv.
  • Adjusts plot layouts (legend placement in prices.ipynb, stacked bar plots in capacity.ipynb).
  • Updates notebook metadata (kernel display name / Python version).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
notebooks/prices.ipynb Improves legend placement for the price bar plot and updates notebook metadata.
notebooks/capacity.ipynb Reworks capacity aggregation to use asset_capacities.csv + assets.csv, and updates plotting logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread notebooks/capacity.ipynb
Comment on lines +57 to +61
"merged = asset_capacities.merge(assets, on=[\"asset_id\", \"group_id\"])\n",
"agg_capacities = merged.groupby([\"milestone_year\", \"agent_id\", \"process_id\"])[\n",
" \"capacity\"\n",
"].sum()\n",
"agg_capacities_wide = agg_capacities.unstack([\"agent_id\", \"process_id\"], fill_value=0)\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does work though 🤷

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might work in this case because there's no group_id in any of the rows. Maybe if there were, things would fail.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried it with the simple_divisible model (which has rows with group_id populated) and it worked, so I think it's fine

Comment thread notebooks/capacity.ipynb
Comment on lines +87 to +92
"agents = agg_capacities_wide.columns.get_level_values(\"agent_id\").unique()\n",
"fig, axes = plt.subplots(1, len(agents), figsize=(4 * len(agents), 4))\n",
"for ax, agent in zip(axes, agents):\n",
" capacity[capacity[\"agent_id\"] == agent].pivot(\n",
" index=\"year\", columns=\"process_id\", values=\"capacity\"\n",
" ).plot(kind=\"bar\", ax=ax)\n",
" ax.set_title(agent)\n",
" ax.set_xlabel(\"Year\")\n",
" ax.set_ylabel(\"Capacity\")\n",
" ax.legend(title=\"Process\")"
" agg_capacities_wide[agent].plot(\n",
" kind=\"bar\", stacked=True, ax=ax, title=agent, xlabel=\"Year\", ylabel=\"Capacity\"\n",
" )\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not too concerned about this. If there was only one agent then you'd plot in a different way anyway

@tsmbland tsmbland left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there!

Comment thread notebooks/capacity.ipynb Outdated
"We begin by loading the `model.toml` input file to get the list of milestone years.\n",
"\n",
"[output-format]: https://energysystemsmodellinglab.github.io/MUSE2/file_formats/output_files.html"
"Output files are mostly in CSV format. The format of output files is documented [here][output-format]."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to add the link back

Comment thread notebooks/capacity.ipynb Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should remove this comment as it isn't true

Comment thread notebooks/capacity.ipynb
Comment on lines +57 to +61
"merged = asset_capacities.merge(assets, on=[\"asset_id\", \"group_id\"])\n",
"agg_capacities = merged.groupby([\"milestone_year\", \"agent_id\", \"process_id\"])[\n",
" \"capacity\"\n",
"].sum()\n",
"agg_capacities_wide = agg_capacities.unstack([\"agent_id\", \"process_id\"], fill_value=0)\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does work though 🤷

Comment thread notebooks/capacity.ipynb
Comment on lines +87 to +92
"agents = agg_capacities_wide.columns.get_level_values(\"agent_id\").unique()\n",
"fig, axes = plt.subplots(1, len(agents), figsize=(4 * len(agents), 4))\n",
"for ax, agent in zip(axes, agents):\n",
" capacity[capacity[\"agent_id\"] == agent].pivot(\n",
" index=\"year\", columns=\"process_id\", values=\"capacity\"\n",
" ).plot(kind=\"bar\", ax=ax)\n",
" ax.set_title(agent)\n",
" ax.set_xlabel(\"Year\")\n",
" ax.set_ylabel(\"Capacity\")\n",
" ax.legend(title=\"Process\")"
" agg_capacities_wide[agent].plot(\n",
" kind=\"bar\", stacked=True, ax=ax, title=agent, xlabel=\"Year\", ylabel=\"Capacity\"\n",
" )\n",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not too concerned about this. If there was only one agent then you'd plot in a different way anyway

Copilot AI review requested due to automatic review settings July 17, 2026 11:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread notebooks/capacity.ipynb
Comment on lines +89 to +91
" agg_capacities_wide[agent].plot(\n",
" kind=\"bar\", stacked=True, ax=ax, title=agent, xlabel=\"Year\", ylabel=\"Capacity\"\n",
" )\n",
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Notebooks failing due to changes in the output format

4 participants