Skip to content

Commit b4d437c

Browse files
authored
Docs/improve perf graphs (AntaresSimulatorTeam#1015)
Improve and change performance graph layout for more clarity. The code is also updated to be able to ealisy select the Xpansion versions we want to plot in the graph.
1 parent b2973fa commit b4d437c

3 files changed

Lines changed: 115 additions & 78 deletions

File tree

docs/user-guide/performance-history/perf-graphs.ipynb

Lines changed: 9 additions & 17 deletions
Large diffs are not rendered by default.

docs/user-guide/performance-history/perf_data.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@
9696
{
9797
"version": 1.4,
9898
"batch_size": 96,
99-
"antares": 360,
100-
"problem_generation": 345,
101-
"benders": 957
99+
"antares": 390,
100+
"problem_generation": 344,
101+
"benders": 961
102102
}
103103
]
104104
},
@@ -147,9 +147,9 @@
147147
{
148148
"version": 1.4,
149149
"batch_size": 96,
150-
"antares": 384,
151-
"problem_generation": 350,
152-
"benders": 1107
150+
"antares": 333,
151+
"problem_generation": 362,
152+
"benders": 972
153153
}
154154
]
155155
},
Lines changed: 100 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from typing import List
2-
31
import json
2+
from typing import List, Optional
3+
44
import pandas as pd
5-
from matplotlib.figure import Figure
5+
from matplotlib import pyplot as plt
6+
from matplotlib import rc, rcParams, style
67
from matplotlib.axes import Axes
7-
from matplotlib import pyplot as plt, rc, rcParams, style
8+
from matplotlib.figure import Figure
89

910
ANTARES_STEP = "antares"
1011
PROBLEM_GENERATION_STEP = "problem_generation"
@@ -56,13 +57,15 @@ def stylize_data_for_display(self):
5657
"resolution.stopping_criterion.type",
5758
"resolution.stopping_criterion.value",
5859
]
59-
stylized_data = self.processed_data.loc[(slice(None), 1.0), columns_to_display]
60+
stylized_data = self.processed_data.loc[(slice(None), 1.1), columns_to_display]
6061
stylized_data.index = stylized_data.index.droplevel(1)
6162
return stylized_data
6263

6364

6465
class PerfPlotsGenerator:
65-
def __init__(self, perf_data: pd.DataFrame) -> None:
66+
def __init__(
67+
self, perf_data: pd.DataFrame, xpansion_versions: Optional[List[int]] = None
68+
) -> None:
6669
self.perf_data = perf_data
6770

6871
self.fig: Figure
@@ -72,69 +75,111 @@ def __init__(self, perf_data: pd.DataFrame) -> None:
7275
rc("font", **{"family": "serif"})
7376
rcParams.update({"font.size": 16})
7477

75-
def _xpansion_versions(self) -> List[float]:
76-
return self.perf_data.index.unique(level="version").tolist()
78+
self.xpansion_versions = self._xpansion_versions(xpansion_versions)
7779

78-
def _create_fig(self) -> None:
80+
def _xpansion_versions(self, xpansion_versions: Optional[List[str]]) -> List[float]:
81+
valid_versions = self.perf_data.index.unique(level="version").tolist()
82+
if xpansion_versions is None:
83+
# If no version is specified by the user, return all versions present in the data
84+
return valid_versions
85+
else:
86+
return_versions = []
87+
for version in xpansion_versions:
88+
if version in valid_versions:
89+
return_versions.append(version)
90+
return return_versions
7991

80-
nb_versions = len(self._xpansion_versions())
81-
fig, ax = plt.subplots(
82-
1, nb_versions, sharey=True, figsize=(5 * nb_versions, 8)
83-
)
92+
def _create_fig(self) -> None:
93+
nb_versions = self._get_nb_versions()
94+
fig, ax = plt.subplots(1, 1, figsize=(8, 3 * nb_versions))
8495

8596
self.fig = fig
8697
self.ax = ax
98+
self.ax.invert_yaxis()
99+
100+
def _get_nb_versions(self):
101+
return len(self.xpansion_versions)
87102

88103
def _display_names(self) -> List[str]:
89104
return self.perf_data.index.unique(level="display_name").tolist()
90105

91106
def _beautify_fig(self) -> None:
92-
self.fig.subplots_adjust(bottom=0.2)
93-
self.fig.suptitle("Xpansion performance evolution")
94-
95-
self.fig.supylabel("Execution time (s)")
96-
self.fig.supxlabel("Study id")
97-
self.ax[-1].legend()
98-
99-
for axes in self.ax:
100-
axes.set_xticks(self._display_names())
101-
axes.set_xticklabels(self._display_names(), rotation=90)
107+
self.ax.set_yticks(
108+
list(range(len(self._display_names()))),
109+
[study for study in self._display_names()],
110+
)
111+
self.ax.set_ylim(self.ax.get_ylim()[0], 1.5 * self.ax.get_ylim()[1])
112+
self.ax.legend(loc="upper center", ncol=3, fontsize=12)
113+
self.ax.set_title("Xpansion performance evolution")
102114

115+
self.ax.set_xlabel("Execution time (s)")
103116
self.fig.tight_layout()
104117

105-
def _plot_single_version(self, version_count: int, xpansion_version: float) -> None:
106-
antares_step_times = self.perf_data.loc[
107-
(slice(None), xpansion_version), ANTARES_STEP
108-
].values
109-
problem_generation_step_times = self.perf_data.loc[
110-
(slice(None), xpansion_version), PROBLEM_GENERATION_STEP
111-
].values
112-
benders_step_times = self.perf_data.loc[
113-
(slice(None), xpansion_version), BENDERS_STEP
114-
].values
115-
116-
self.ax[version_count].bar(
117-
self._display_names(), antares_step_times, label=ANTARES_STEP
118-
)
119-
self.ax[version_count].bar(
120-
self._display_names(),
121-
problem_generation_step_times,
122-
bottom=antares_step_times,
123-
label=PROBLEM_GENERATION_STEP,
124-
)
125-
self.ax[version_count].bar(
126-
self._display_names(),
127-
benders_step_times,
128-
bottom=problem_generation_step_times + antares_step_times,
129-
label=BENDERS_STEP,
130-
)
131-
self.ax[version_count].set_title(f"Version {xpansion_version}")
118+
def _plot_study_data(self) -> None:
119+
120+
nb_versions = self._get_nb_versions()
121+
height = 0.8 / nb_versions # Defines space between different study data
122+
epsilon = 0.03 # Defines space between bars of the data for the different version of the same study
123+
actual_height = (1 - epsilon) * height
124+
alpha_decrease_rate = 0.2 # Defines transparency difference between bars of the data for the different version of the same study
125+
126+
for count, study in enumerate(self._display_names()):
127+
for version_cnt, xpansion_version in enumerate(self.xpansion_versions):
128+
antares_time = self.perf_data.loc[
129+
(study, xpansion_version), ANTARES_STEP
130+
]
131+
pb_gen_time = self.perf_data.loc[
132+
(study, xpansion_version), PROBLEM_GENERATION_STEP
133+
]
134+
benders_time = self.perf_data.loc[
135+
(study, xpansion_version), BENDERS_STEP
136+
]
137+
138+
y_pos = self._bar_y_position(nb_versions, height, count, version_cnt)
139+
140+
antares_line = self.ax.barh(
141+
y_pos,
142+
antares_time,
143+
height=actual_height,
144+
color="C0",
145+
align="edge",
146+
alpha=1 - alpha_decrease_rate * version_cnt,
147+
)
148+
pb_gen_line = self.ax.barh(
149+
y_pos,
150+
pb_gen_time,
151+
height=actual_height,
152+
left=antares_time,
153+
color="C1",
154+
align="edge",
155+
alpha=1 - alpha_decrease_rate * version_cnt,
156+
)
157+
benders_line = self.ax.barh(
158+
y_pos,
159+
benders_time,
160+
left=pb_gen_time + antares_time,
161+
height=actual_height,
162+
color="C2",
163+
align="edge",
164+
alpha=1 - alpha_decrease_rate * version_cnt,
165+
)
166+
self.ax.bar_label(
167+
benders_line,
168+
[f"v{xpansion_version}: {antares_time + pb_gen_time + benders_time}s"],
169+
label_type="edge",
170+
fontsize=12,
171+
)
172+
if version_cnt == 0 and count == 0:
173+
antares_line.set_label(ANTARES_STEP)
174+
pb_gen_line.set_label(PROBLEM_GENERATION_STEP)
175+
benders_line.set_label(BENDERS_STEP)
176+
177+
def _bar_y_position(
178+
self, nb_versions: int, height: float, count: int, version_cnt: int
179+
):
180+
return count + height * (version_cnt - nb_versions / 2)
132181

133182
def run(self) -> None:
134-
135183
self._create_fig()
136-
137-
for version_count, xpansion_version in enumerate(self._xpansion_versions()):
138-
self._plot_single_version(version_count, xpansion_version)
139-
184+
self._plot_study_data()
140185
self._beautify_fig()

0 commit comments

Comments
 (0)