Skip to content

Commit 6904948

Browse files
committed
Use improved .report.plot features in .transport
1 parent 33d6299 commit 6904948

File tree

3 files changed

+65
-55
lines changed

3 files changed

+65
-55
lines changed

message_ix_models/model/transport/build.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from message_ix_models import Context, ScenarioInfo
1616
from message_ix_models.model import bare, build
1717
from message_ix_models.model.structure import get_codelist
18+
from message_ix_models.model.workflow import STAGE
1819
from message_ix_models.util import (
1920
MappingAdapter,
2021
WildcardAdapter,
@@ -42,7 +43,9 @@
4243
def add_debug(c: Computer) -> None:
4344
"""Add tasks for debugging the build."""
4445

45-
from . import plot
46+
from message_ix_models.report import plot
47+
48+
from . import plot as plots
4649
from .key import gdp_cap, ms, pdt_nyt
4750

4851
context: Context = c.graph["context"]
@@ -85,16 +88,19 @@ def add_debug(c: Computer) -> None:
8588
):
8689
c.add(k_debug[i], "write_report_debug", key, output_dir.joinpath(f"{stem}.csv"))
8790

88-
c.add("transport build debug", "summarize", *k_debug.generated)
89-
plot.prepare_computer(c, kind=plot.Kind.BUILD, target="transport build debug")
91+
k_debug = Key("transport build debug")
92+
c.add(k_debug["data"], "summarize", *k_debug.generated)
93+
plot.prepare_computer(c, plots, k_debug["plot"], stage=STAGE.BUILD, single=True)
9094

9195
# Also generate these debugging outputs when building the scenario
92-
c.graph["add transport data"].append("transport build debug")
96+
c.graph["add transport data"].extend(k_debug["data"], k_debug["plot"])
9397

9498

9599
def debug_multi(context: Context, *paths: Path) -> None:
96100
"""Generate plots comparing data from multiple build debug directories."""
97-
from . import plot
101+
from message_ix_models.report import plot
102+
103+
from . import plot as plots
98104

99105
if isinstance(paths[0], Scenario):
100106
# Workflow was called with --from="…", so paths from the previous step are not
@@ -105,10 +111,10 @@ def debug_multi(context: Context, *paths: Path) -> None:
105111
)
106112
)
107113

108-
c = Computer(config={"transport build debug dir": paths[0].parent})
114+
c = Computer(config={"build debug dir": paths[0].parent})
109115
c.require_compat("message_ix_models.report.operator")
110116

111-
plot.prepare_computer(c, kind=plot.Kind.BUILD_MULTI, target="debug multi")
117+
plot.prepare_computer(c, plots, "debug multi", stage=STAGE.BUILD, single=False)
112118

113119
c.get("debug multi")
114120

message_ix_models/model/transport/plot.py

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
"""Plots for MESSAGEix-Transport reporting."""
22

33
from pathlib import Path
4+
from typing import cast
45

56
import pandas as pd
67
import plotnine as p9
78
from iam_units import registry
89

10+
from message_ix_models.model.workflow import STAGE
11+
from message_ix_models.report.plot import COMMON, LabelFirst, Plot, PlotFromIAMC
912

1013
from .key import gdp_cap, pdt_nyt
1114

15+
#: Common, static settings
16+
STATIC = [
17+
COMMON["A4 landscape"],
18+
]
1219

1320

1421
class BaseEnergy0(Plot):
1522
"""Transport final energy intensity of GDP."""
1623

1724
basename = "base-fe-intensity-gdp"
1825
inputs = ["fe intensity:nl-ya:units"]
19-
static = Plot.static + [
26+
static = STATIC + [
2027
p9.aes(x="ya", y="value", color="nl"),
2128
p9.geom_line(),
2229
p9.geom_point(),
@@ -35,7 +42,7 @@ class CapNewLDV(Plot):
3542

3643
basename = "cap-new-t-ldv"
3744
inputs = ["historical_new_capacity:nl-t-yv:ldv", "CAP_NEW:nl-t-yv:ldv"]
38-
static = Plot.static + [
45+
static = STATIC + [
3946
p9.aes(x="yv", y="value", color="t"),
4047
p9.geom_vline(xintercept=2020, size=4, color="white"),
4148
p9.geom_line(),
@@ -96,11 +103,10 @@ class ComparePDT(Plot):
96103
- One line with points per scenario, coloured by scenario.
97104
"""
98105

99-
kind = Kind.BUILD_MULTI
100-
101106
basename = "compare-pdt"
102-
103-
static = Plot.static + [
107+
stage = STAGE.BUILD
108+
single = False
109+
static = STATIC + [
104110
p9.aes(x="y", y="value", color="scenario"),
105111
p9.facet_wrap("t", ncol=5),
106112
p9.geom_line(),
@@ -118,7 +124,10 @@ class ComparePDT(Plot):
118124
factor = 1e6
119125

120126
def generate(self, *paths: Path):
121-
data = read_csvs(self.measure, *paths).eval("value = value / @self.factor")
127+
data = cast(
128+
pd.DataFrame,
129+
read_csvs(self.measure, *paths).eval("value = value / @self.factor"),
130+
)
122131

123132
# Add factor to the unit expression
124133
if self.factor != 1.0:
@@ -140,7 +149,7 @@ class ComparePDTCap0(ComparePDT):
140149

141150

142151
#: Common layers for :class:`ComparePDTCap1` and :class:`DemandExoCap1`.
143-
PDT_CAP_GDP_STATIC = Plot.static + [
152+
PDT_CAP_GDP_STATIC = STATIC + [
144153
p9.aes(x="gdp", y="value", color="t"),
145154
p9.geom_line(),
146155
p9.geom_point(),
@@ -160,8 +169,9 @@ class ComparePDTCap1(Plot):
160169
- One line with points per |t| (=transport mode), coloured by mode.
161170
"""
162171

163-
kind = Kind.BUILD_MULTI
164172
basename = "compare-pdt-capita-gdp"
173+
stage = STAGE.BUILD
174+
single = False
165175
static = PDT_CAP_GDP_STATIC + [
166176
p9.facet_wrap("scenario", ncol=5),
167177
]
@@ -192,7 +202,7 @@ class InvCost0(Plot):
192202

193203
basename = "inv-cost-transport"
194204
inputs = ["inv_cost:nl-t-yv:transport all"]
195-
static = Plot.static + [
205+
static = STATIC + [
196206
p9.aes(x="yv", y="inv_cost", color="t"),
197207
p9.geom_line(),
198208
p9.geom_point(),
@@ -231,7 +241,7 @@ class FixCost(Plot):
231241

232242
basename = "fix-cost"
233243
inputs = ["fix_cost:nl-t-yv-ya:transport all"]
234-
static = Plot.static + [
244+
static = STATIC + [
235245
p9.aes(x="ya", y="fix_cost", color="t", group="t * yv"),
236246
p9.geom_line(),
237247
p9.geom_point(),
@@ -250,7 +260,7 @@ class VarCost(Plot):
250260

251261
basename = "var-cost"
252262
inputs = ["var_cost:nl-t-yv-ya:transport all"]
253-
static = Plot.static + [
263+
static = STATIC + [
254264
p9.aes(x="ya", y="var_cost", color="t", group="t * yv"),
255265
p9.geom_line(),
256266
p9.geom_point(),
@@ -269,7 +279,7 @@ class LDV_IO(Plot):
269279

270280
basename = "ldv-efficiency"
271281
inputs = ["input:nl-t-yv-ya:transport all"]
272-
static = Plot.static + [
282+
static = STATIC + [
273283
p9.aes(x="ya", y="input", color="t"),
274284
# TODO remove typing exclusion once plotnine >0.12.4 is released
275285
p9.facet_wrap(
@@ -291,7 +301,7 @@ class OutShareLDV0(Plot):
291301

292302
basename = "out-share-t-ldv"
293303
inputs = ["out:nl-t-ya:ldv+units"]
294-
static = Plot.static + [
304+
static = STATIC + [
295305
p9.aes(x="ya", y="value", fill="t"),
296306
p9.geom_bar(stat="identity", width=4),
297307
# # Select a palette with up to 12 colors
@@ -314,7 +324,7 @@ class OutShareLDV1(Plot):
314324

315325
basename = "out-share-t-cg-ldv"
316326
inputs = ["out:nl-t-ya-c", "cg"]
317-
static = Plot.static + [
327+
static = STATIC + [
318328
p9.aes(x="ya", y="value", fill="t"),
319329
p9.facet_wrap(["c"], ncol=5),
320330
p9.geom_bar(stat="identity", width=4),
@@ -352,7 +362,7 @@ class Demand0(Plot):
352362

353363
basename = "demand"
354364
inputs = ["demand:n-c-y", "c::transport", "cg"]
355-
static = Plot.static + [
365+
static = STATIC + [
356366
p9.aes(x="y", y="demand", fill="c_group"),
357367
p9.geom_bar(stat="identity", width=4),
358368
p9.labs(x="Period", y="", fill="Transport mode"),
@@ -394,7 +404,7 @@ class DemandCap(Plot):
394404

395405
basename = "demand-capita"
396406
inputs = ["demand:n-c-y:capita", "c::transport", "cg"]
397-
static = Plot.static + [
407+
static = STATIC + [
398408
p9.aes(x="y", y="value", fill="c"),
399409
p9.geom_bar(stat="identity", width=4),
400410
p9.labs(x="Period", y="", fill="Transport mode group"),
@@ -412,18 +422,20 @@ def _reduce_units(df: pd.DataFrame, target_units) -> tuple[pd.DataFrame, str]:
412422
assert 1 == len(df_units)
413423
tmp = registry.Quantity(1.0, df_units[0]).to(target_units)
414424
return (
415-
df.eval("value = value * @tmp.magnitude").assign(unit=f"{tmp.units:~}"),
425+
cast(pd.DataFrame, df.eval("value = value * @tmp.magnitude")).assign(
426+
unit=f"{tmp.units:~}"
427+
),
416428
f"{tmp.units:~}",
417429
)
418430

419431

420432
class DemandExo(Plot):
421433
"""Passenger transport activity."""
422434

423-
kind = Kind.BUILD
424435
basename = "demand-exo"
436+
stage = STAGE.BUILD
425437
inputs = [pdt_nyt]
426-
static = Plot.static + [
438+
static = STATIC + [
427439
p9.aes(x="y", y="value", fill="t"),
428440
p9.geom_bar(stat="identity", width=4),
429441
p9.labs(x="Period", y="", fill="Mode (tech group)"),
@@ -442,10 +454,10 @@ def generate(self, data):
442454
class DemandExoCap0(Plot):
443455
"""Passenger transport activity per person."""
444456

445-
kind = Kind.BUILD
446457
basename = "demand-exo-capita"
458+
stage = STAGE.BUILD
447459
inputs = [pdt_nyt + "capita+post"]
448-
static = Plot.static + [
460+
static = STATIC + [
449461
p9.aes(x="y", y="value", fill="t"),
450462
p9.geom_bar(stat="identity", width=4),
451463
p9.labs(x="Period", y="", fill="Transport mode"),
@@ -467,8 +479,8 @@ class DemandExoCap1(DemandExoCap0):
467479
Unlike :class:`DemandExoCap0`, this uses GDP per capita as the abscissa/x-aesthetic.
468480
"""
469481

470-
kind = Kind.BUILD
471482
basename = "demand-exo-capita-gdp"
483+
stage = STAGE.BUILD
472484
inputs = [pdt_nyt + "capita+post", gdp_cap]
473485
static = PDT_CAP_GDP_STATIC
474486

@@ -494,7 +506,7 @@ class EnergyCmdty0(Plot):
494506

495507
basename = "energy-c"
496508
inputs = ["y0", "in:nl-ya-c:transport all"]
497-
static = Plot.static + [
509+
static = STATIC + [
498510
p9.aes(x="ya", y="value", fill="c"),
499511
p9.geom_bar(stat="identity", width=5, color="black"),
500512
p9.labs(x="Period", y="Energy", fill="Commodity"),
@@ -538,20 +550,22 @@ def generate(self, y0: int, data):
538550
yield ggplot
539551

540552

541-
class MultiStock(Plot):
553+
class MultiStock(PlotFromIAMC):
542554
"""LDV technology stock."""
543555

544-
kind = Kind.REPORT_MULTI
545556
basename = "multi-stock"
557+
single = False
558+
inputs = ["all:n-s-UNIT-v-y"]
559+
iamc_variable_pattern = r"Transport\|Stock\|Road\|Passenger\|LDV\|(.*)"
546560

547-
static = Plot.static + [
561+
static = STATIC + [
548562
p9.aes(x="y", y="value", color="v"),
549563
p9.facet_wrap("s", ncol=3, nrow=5),
550564
p9.geom_point(),
551565
p9.geom_line(),
552566
p9.scale_color_brewer(type="qualitative", palette="Paired"),
553567
p9.labs(x="Period", y="", color="Technology"),
554-
p9.theme(figure_size=(11.7, 16.6)),
568+
COMMON["A3 portrait"],
555569
]
556570

557571
def generate(self, data):
@@ -567,12 +581,11 @@ class Scale1Diff(Plot):
567581
"""scale-1 factor in y=2020; changes between 2 scenarios."""
568582

569583
basename = "scale-1-diff"
570-
571-
kind = Kind.BUILD
584+
stage = STAGE.BUILD
572585
inputs = ["scale-1:nl-t-c-l-h:a", "scale-1:nl-t-c-l-h:b"]
573586

574587
_s, _v, _y = "scenario", "value", "t + ' ' + c"
575-
static = Plot.static + [
588+
static = STATIC + [
576589
p9.aes(x=_v, y=_y, yend=_y, group=_s, color=_s, shape=_s),
577590
p9.facet_wrap("nl", scales="free_x"),
578591
p9.geom_vline(p9.aes(xintercept=_v), pd.DataFrame([[1.0]], columns=[_v])),
@@ -611,7 +624,7 @@ class Stock0(Plot):
611624
basename = "stock-ldv"
612625
# Partial sum over driver_type dimension
613626
inputs = ["CAP:nl-t-ya:ldv+units"]
614-
static = Plot.static + [
627+
static = STATIC + [
615628
p9.aes(x="ya", y="CAP", color="t"),
616629
p9.geom_line(),
617630
p9.geom_point(),
@@ -634,7 +647,7 @@ class Stock1(Plot):
634647

635648
basename = "stock-non-ldv"
636649
inputs = ["CAP:nl-t-ya:non-ldv+units"]
637-
static = Plot.static + [
650+
static = STATIC + [
638651
p9.aes(x="ya", y="CAP", color="t"),
639652
p9.geom_line(),
640653
p9.geom_point(),

message_ix_models/model/transport/report.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import logging
44
import re
55
from copy import deepcopy
6-
from types import SimpleNamespace
76
from typing import TYPE_CHECKING
87

98
import pandas as pd
@@ -12,6 +11,7 @@
1211
from message_ix import Reporter
1312

1413
from message_ix_models import Context, ScenarioInfo
14+
from message_ix_models.model.workflow import STAGE
1515
from message_ix_models.report.util import add_replacements
1616

1717
from . import Config
@@ -418,9 +418,10 @@ def misc(c: "Computer") -> None:
418418
def multi(context: Context, targets: list[str], *, use_platform: bool = False) -> None:
419419
"""Report outputs from multiple scenarios."""
420420

421+
from message_ix_models.report import plot
421422
from message_ix_models.tools.iamc import to_quantity
422423

423-
from . import plot
424+
from . import plot as plots
424425

425426
k = Keys(
426427
in_="in::pd",
@@ -430,16 +431,14 @@ def multi(context: Context, targets: list[str], *, use_platform: bool = False) -
430431
plot_data="plot data:n-s-y",
431432
)
432433

433-
c = Computer()
434+
# Computer, with configuration expected by Plot.add_tasks
435+
c = Computer(config=dict(output_dir=context.get_local_path("report")))
434436
# Order is important: use genno.compat.pyam.operator.quantity_from_iamc over local
435437
c.require_compat("message_ix_models.report.operator")
436438
c.require_compat("pyam")
437439

438440
c.add("context", context)
439441

440-
# Expected by .transport.plot.Plot.add_tasks
441-
c.graph["config"]["transport build debug dir"] = context.get_local_path("report")
442-
443442
# Retrieve all data for each of the `targets` as pd.DataFrame
444443
kw0 = dict(filename="transport.csv", use={"file"})
445444
for i, info in enumerate(map(ScenarioInfo.from_url, targets)):
@@ -459,16 +458,8 @@ def multi(context: Context, targets: list[str], *, use_platform: bool = False) -
459458
# Rename dimensions
460459
c.add(k.all1, "rename_dims", k.all0, name_dict={"SCENARIO": "s", "VARIABLE": "v"})
461460

462-
# Select a subset of data and reduce dimensionality
463-
expr = r"Transport\|Stock\|Road\|Passenger\|LDV\|(.*)"
464-
c.add(k.plot_data[0], "quantity_from_iamc", k.all1, variable=expr)
465-
466-
# Key used by .plot.Plot for formatting titles
467-
c.add("scenario", SimpleNamespace(url="Multiple scenarios"))
468-
469461
# Collect all plots
470-
c.add("multi", "summarize")
471-
plot.prepare_computer(c, kind=plot.Kind.REPORT_MULTI, target="multi")
462+
plot.prepare_computer(c, plots, "multi", stage=STAGE.REPORT, single=False)
472463

473464
return c.get("multi")
474465

0 commit comments

Comments
 (0)