Skip to content

Commit 5bf11e5

Browse files
authored
Implementation of backend plotting for profile_plot (#645)
1 parent 0ac82d0 commit 5bf11e5

File tree

4 files changed

+307
-125
lines changed

4 files changed

+307
-125
lines changed

docs/source/how_to/how_to_benchmarking.ipynb

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,18 @@
135135
"cell_type": "markdown",
136136
"id": "10",
137137
"metadata": {},
138+
"source": [
139+
":::{note}\n",
140+
"\n",
141+
"For details on using other plotting backends, see [How to change the plotting backend](how_to_change_plotting_backend.ipynb).\n",
142+
"\n",
143+
":::"
144+
]
145+
},
146+
{
147+
"cell_type": "markdown",
148+
"id": "11",
149+
"metadata": {},
138150
"source": [
139151
"The x axis shows runtime per problem. The y axis shows the share of problems each algorithm solved within that runtime. Thus, higher and further to the left values are desirable. Higher means more problems were solved and further to the left means, the algorithm found the solutions earlier. \n",
140152
"\n",
@@ -150,7 +162,7 @@
150162
{
151163
"cell_type": "code",
152164
"execution_count": null,
153-
"id": "11",
165+
"id": "12",
154166
"metadata": {},
155167
"outputs": [],
156168
"source": [
@@ -167,7 +179,7 @@
167179
},
168180
{
169181
"cell_type": "markdown",
170-
"id": "12",
182+
"id": "13",
171183
"metadata": {},
172184
"source": [
173185
"## 4b. Convergence plots\n",
@@ -178,7 +190,7 @@
178190
{
179191
"cell_type": "code",
180192
"execution_count": null,
181-
"id": "13",
193+
"id": "14",
182194
"metadata": {},
183195
"outputs": [],
184196
"source": [
@@ -194,7 +206,7 @@
194206
},
195207
{
196208
"cell_type": "markdown",
197-
"id": "14",
209+
"id": "15",
198210
"metadata": {},
199211
"source": [
200212
"The further to the left and the lower the curve of an algorithm, the better that algorithm performed.\n",
@@ -205,7 +217,7 @@
205217
{
206218
"cell_type": "code",
207219
"execution_count": null,
208-
"id": "15",
220+
"id": "16",
209221
"metadata": {},
210222
"outputs": [],
211223
"source": [
@@ -223,7 +235,7 @@
223235
},
224236
{
225237
"cell_type": "markdown",
226-
"id": "16",
238+
"id": "17",
227239
"metadata": {},
228240
"source": [
229241
"## 5a. Convergence report\n",
@@ -235,7 +247,7 @@
235247
{
236248
"cell_type": "code",
237249
"execution_count": null,
238-
"id": "17",
250+
"id": "18",
239251
"metadata": {},
240252
"outputs": [],
241253
"source": [
@@ -251,7 +263,7 @@
251263
{
252264
"cell_type": "code",
253265
"execution_count": null,
254-
"id": "18",
266+
"id": "19",
255267
"metadata": {},
256268
"outputs": [],
257269
"source": [
@@ -260,18 +272,18 @@
260272
},
261273
{
262274
"cell_type": "markdown",
263-
"id": "19",
275+
"id": "20",
264276
"metadata": {},
265277
"source": [
266-
"## 5b. Rank report\n",
278+
"## 5b. Rank report\n",
267279
"\n",
268280
"The **Rank Report** shows the ranks of the algorithms for each problem; where 0 means the algorithm was the fastest on a given benchmark problem, 1 means it was the second fastest and so on. If an algorithm did not converge on a problem, the value is \"failed\". If an algorithm did encounter an error during optimization, the value is \"error\"."
269281
]
270282
},
271283
{
272284
"cell_type": "code",
273285
"execution_count": null,
274-
"id": "20",
286+
"id": "21",
275287
"metadata": {},
276288
"outputs": [],
277289
"source": [
@@ -288,7 +300,7 @@
288300
{
289301
"cell_type": "code",
290302
"execution_count": null,
291-
"id": "21",
303+
"id": "22",
292304
"metadata": {},
293305
"outputs": [],
294306
"source": [
@@ -297,18 +309,18 @@
297309
},
298310
{
299311
"cell_type": "markdown",
300-
"id": "22",
312+
"id": "23",
301313
"metadata": {},
302314
"source": [
303-
"## 5b. Traceback report\n",
315+
"## 5b. Traceback report\n",
304316
"\n",
305317
"The **Traceback Report** shows the tracebacks returned by the optimizers if they encountered an error during optimization. The resulting ```pd.DataFrame``` is empty if none of the optimizers terminated with an error, as in the example below."
306318
]
307319
},
308320
{
309321
"cell_type": "code",
310322
"execution_count": null,
311-
"id": "23",
323+
"id": "24",
312324
"metadata": {},
313325
"outputs": [],
314326
"source": [
@@ -318,7 +330,7 @@
318330
{
319331
"cell_type": "code",
320332
"execution_count": null,
321-
"id": "24",
333+
"id": "25",
322334
"metadata": {},
323335
"outputs": [],
324336
"source": [

src/optimagic/visualization/backends.py

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ def __call__(
2323
height: int | None,
2424
width: int | None,
2525
legend_properties: dict[str, Any] | None,
26+
margin_properties: dict[str, Any] | None,
27+
horizontal_line: float | None,
2628
) -> Any: ...
2729

2830

@@ -36,12 +38,32 @@ def _line_plot_plotly(
3638
height: int | None,
3739
width: int | None,
3840
legend_properties: dict[str, Any] | None,
41+
margin_properties: dict[str, Any] | None,
42+
horizontal_line: float | None,
3943
) -> go.Figure:
4044
if template is None:
4145
template = "simple_white"
4246

4347
fig = go.Figure()
4448

49+
fig.update_layout(
50+
title=title,
51+
xaxis_title=xlabel.format(linebreak="<br>") if xlabel else None,
52+
yaxis_title=ylabel,
53+
template=template,
54+
height=height,
55+
width=width,
56+
legend=legend_properties,
57+
margin=margin_properties,
58+
)
59+
60+
if horizontal_line is not None:
61+
fig.add_hline(
62+
y=horizontal_line,
63+
line_width=fig.layout.yaxis.linewidth or 1,
64+
opacity=1.0,
65+
)
66+
4567
for line in lines:
4668
trace = go.Scatter(
4769
x=line.x,
@@ -53,18 +75,6 @@ def _line_plot_plotly(
5375
)
5476
fig.add_trace(trace)
5577

56-
fig.update_layout(
57-
title=title,
58-
xaxis_title=xlabel,
59-
yaxis_title=ylabel,
60-
template=template,
61-
height=height,
62-
width=width,
63-
)
64-
65-
if legend_properties:
66-
fig.update_layout(legend=legend_properties)
67-
6878
return fig
6979

7080

@@ -78,6 +88,8 @@ def _line_plot_matplotlib(
7888
height: int | None,
7989
width: int | None,
8090
legend_properties: dict[str, Any] | None,
91+
margin_properties: dict[str, Any] | None,
92+
horizontal_line: float | None,
8193
) -> "plt.Axes":
8294
import matplotlib.pyplot as plt
8395

@@ -93,7 +105,17 @@ def _line_plot_matplotlib(
93105
template = "default"
94106

95107
with plt.style.context(template):
96-
fig, ax = plt.subplots(figsize=(width, height) if width and height else None)
108+
px = 1 / plt.rcParams["figure.dpi"] # pixel in inches
109+
fig, ax = plt.subplots(
110+
figsize=(width * px, height * px) if width and height else None
111+
)
112+
113+
if horizontal_line is not None:
114+
ax.axhline(
115+
y=horizontal_line,
116+
color=ax.spines["left"].get_edgecolor() or "gray",
117+
linewidth=ax.spines["left"].get_linewidth() or 1.0,
118+
)
97119

98120
for line in lines:
99121
ax.plot(
@@ -103,9 +125,17 @@ def _line_plot_matplotlib(
103125
color=line.color,
104126
)
105127

106-
ax.set(title=title, xlabel=xlabel, ylabel=ylabel)
107-
if legend_properties:
108-
ax.legend(**legend_properties)
128+
ax.set(
129+
title=title,
130+
xlabel=xlabel.format(linebreak="\n") if xlabel else None,
131+
ylabel=ylabel,
132+
)
133+
134+
if legend_properties is None:
135+
legend_properties = {}
136+
ax.legend(**legend_properties)
137+
138+
fig.tight_layout()
109139

110140
return ax
111141

@@ -129,6 +159,8 @@ def line_plot(
129159
height: int | None = None,
130160
width: int | None = None,
131161
legend_properties: dict[str, Any] | None = None,
162+
margin_properties: dict[str, Any] | None = None,
163+
horizontal_line: float | None = None,
132164
) -> Any:
133165
"""Create a line plot corresponding to the specified backend.
134166
@@ -144,6 +176,9 @@ def line_plot(
144176
height: Height of the plot (in pixels).
145177
width: Width of the plot (in pixels).
146178
legend_properties: Backend-specific properties for the legend.
179+
margin_properties: Backend-specific properties for the plot margins.
180+
horizontal_line: If provided, a horizontal line is drawn at the specified
181+
y-value.
147182
148183
Returns:
149184
A figure object corresponding to the specified backend.
@@ -178,6 +213,8 @@ def line_plot(
178213
height=height,
179214
width=width,
180215
legend_properties=legend_properties,
216+
margin_properties=margin_properties,
217+
horizontal_line=horizontal_line,
181218
)
182219

183220
return fig

0 commit comments

Comments
 (0)