Skip to content

Commit e9659e0

Browse files
Merge branch 'main' into gradient_free_optimizers
2 parents b0b70aa + d9f31d1 commit e9659e0

File tree

7 files changed

+1681
-3
lines changed

7 files changed

+1681
-3
lines changed

docs/source/conf.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@
152152
# List of patterns, relative to source directory, that match files and
153153
# directories to ignore when looking for source files.
154154
# This patterns also effect to html_static_path and html_extra_path
155-
exclude_patterns = ["_build", "**.ipynb_checkpoints"]
155+
exclude_patterns = [
156+
"_build",
157+
"**.ipynb_checkpoints",
158+
"how_to/how_to_slice_plot_3d.ipynb",
159+
]
156160

157161
# The name of the Pygments (syntax highlighting) style to use.
158162
pygments_style = "sphinx"
@@ -179,6 +183,7 @@
179183
"estimation_tables_overview.ipynb",
180184
# too long runtime
181185
"bootstrap_montecarlo_comparison.ipynb",
186+
"how_to_slice_plot_3d.ipynb",
182187
]
183188

184189
# -- Options for HTML output ----------------------------------------------

docs/source/how_to/how_to_constraints.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ The unconstrained optimum of a six-dimensional version of this problem is:
5252
... params=np.array([2.5, 1, 1, 1, 1, -2.5]),
5353
... algorithm="scipy_lbfgsb",
5454
... )
55-
>>> res.params.round(3)
55+
>>> res.params.round(3) # doctest: +SKIP
5656
array([1. , 0.8, 0.6, 0.4, 0.2, 0. ])
5757
5858
```
Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "0",
6+
"metadata": {},
7+
"source": [
8+
"# Visualizing Objective Functions with `slice_plot_3d`\n",
9+
"\n",
10+
"In optimization, understanding the shape of your objective function is a key step toward choosing the right algorithm.\n",
11+
"\n",
12+
"This notebook introduces the `slice_plot_3d` tool, which provides flexible ways to visualize:\n",
13+
"- Single-parameter sensitivity through **univariate slice plots**,\n",
14+
"- Pairwise interactions through **contour** or **surface plots**,\n",
15+
"- Full parameter relationships through **subplot grids**.\n",
16+
"\n",
17+
"We will progress from basic to advanced usage, learning how to create clean and insightful plots easily.\n"
18+
]
19+
},
20+
{
21+
"cell_type": "markdown",
22+
"id": "1",
23+
"metadata": {},
24+
"source": [
25+
"## Univariate slice Plot\n",
26+
"\n",
27+
"We start with a **univariate slice plot**.\n",
28+
"This plots the function along each parameter individually to the function value,\n",
29+
"while fixing others at their current values. This provides a clean view of how sensitive the function is to each parameter separately. We use the **Sphere function**, which sums the squares of each input.\n"
30+
]
31+
},
32+
{
33+
"cell_type": "code",
34+
"execution_count": null,
35+
"id": "2",
36+
"metadata": {},
37+
"outputs": [],
38+
"source": [
39+
"import numpy as np\n",
40+
"\n",
41+
"import optimagic as om"
42+
]
43+
},
44+
{
45+
"cell_type": "code",
46+
"execution_count": null,
47+
"id": "3",
48+
"metadata": {},
49+
"outputs": [],
50+
"source": [
51+
"# Define the Sphere function\n",
52+
"def sphere(params):\n",
53+
" x = np.array(list(params.values()))\n",
54+
" return np.sum(x**2)"
55+
]
56+
},
57+
{
58+
"cell_type": "code",
59+
"execution_count": null,
60+
"id": "4",
61+
"metadata": {},
62+
"outputs": [],
63+
"source": [
64+
"params = {\"alpha\": 0, \"beta\": 0, \"gamma\": 0, \"delta\": 0}\n",
65+
"bounds = om.Bounds(\n",
66+
" lower={name: -5 for name in params},\n",
67+
" upper={name: i + 2 for i, name in enumerate(params)},\n",
68+
")"
69+
]
70+
},
71+
{
72+
"cell_type": "code",
73+
"execution_count": null,
74+
"id": "5",
75+
"metadata": {},
76+
"outputs": [],
77+
"source": [
78+
"fig = om.sandbox.slice_plot_3d(\n",
79+
" func=sphere,\n",
80+
" params=params,\n",
81+
" bounds=bounds,\n",
82+
")\n",
83+
"fig.show()"
84+
]
85+
},
86+
{
87+
"cell_type": "markdown",
88+
"id": "6",
89+
"metadata": {},
90+
"source": [
91+
"## Univariate slice plot with selected parameters\n",
92+
"\n",
93+
"In many situations, we are interested in exploring only specific parameters.\n",
94+
"Using the `selector` argument, we can restrict the univariate plots to\n",
95+
"chosen parameters — here, we select `\"alpha\"` and `\"beta\"`.\n",
96+
"\n",
97+
"This focuses our visualization on dimensions of interest."
98+
]
99+
},
100+
{
101+
"cell_type": "code",
102+
"execution_count": null,
103+
"id": "7",
104+
"metadata": {},
105+
"outputs": [],
106+
"source": [
107+
"fig = om.sandbox.slice_plot_3d(\n",
108+
" func=sphere,\n",
109+
" params=params,\n",
110+
" bounds=bounds,\n",
111+
" selector=lambda p: [p[\"alpha\"], p[\"beta\"]],\n",
112+
" projection=\"univariate\",\n",
113+
")\n",
114+
"fig.show()"
115+
]
116+
},
117+
{
118+
"cell_type": "markdown",
119+
"id": "8",
120+
"metadata": {},
121+
"source": [
122+
"## 3D Surface Plot for Two Parameters\n",
123+
"\n",
124+
"To better understand interaction between parameters,\n",
125+
"we can switch to a **3D surface plot**.\n",
126+
"\n",
127+
"Surface plots reveal valleys, ridges, and general landscape shapes clearly.\n",
128+
"Here, we vary `\"alpha\"` and `\"beta\"` simultaneously and plot the resulting surface."
129+
]
130+
},
131+
{
132+
"cell_type": "code",
133+
"execution_count": null,
134+
"id": "9",
135+
"metadata": {},
136+
"outputs": [],
137+
"source": [
138+
"fig = om.sandbox.slice_plot_3d(\n",
139+
" func=sphere,\n",
140+
" params=params,\n",
141+
" bounds=bounds,\n",
142+
" selector=lambda p: [p[\"alpha\"], p[\"beta\"]],\n",
143+
" projection=\"surface\",\n",
144+
" n_gridpoints=30,\n",
145+
")\n",
146+
"fig.show()"
147+
]
148+
},
149+
{
150+
"cell_type": "markdown",
151+
"id": "10",
152+
"metadata": {},
153+
"source": [
154+
"## 2D Contour Plot for Two Parameters\n",
155+
"\n",
156+
"Contour plots offer a 2D view with iso-function-value curves.\n",
157+
"\n",
158+
"They are especially useful for:\n",
159+
"- Finding basins or valleys.\n",
160+
"- Visualizing optimization paths.\n",
161+
"- Detecting steep or flat regions easily.\n",
162+
"\n",
163+
"Again, we use `\"alpha\"` and `\"beta\"` to generate the plot."
164+
]
165+
},
166+
{
167+
"cell_type": "code",
168+
"execution_count": null,
169+
"id": "11",
170+
"metadata": {},
171+
"outputs": [],
172+
"source": [
173+
"fig = om.sandbox.slice_plot_3d(\n",
174+
" func=sphere,\n",
175+
" params=params,\n",
176+
" bounds=bounds,\n",
177+
" selector=lambda p: [p[\"alpha\"], p[\"beta\"]],\n",
178+
" projection=\"contour\",\n",
179+
" n_gridpoints=30,\n",
180+
")\n",
181+
"fig.show()"
182+
]
183+
},
184+
{
185+
"cell_type": "markdown",
186+
"id": "12",
187+
"metadata": {},
188+
"source": [
189+
"## Grid View for Multiple Parameters\n",
190+
"When selecting more than two parameters, the slice_plot_3d function automatically constructs a grid-based visualization to analyze both individual and pairwise parameter effects.\n",
191+
"\n",
192+
"- **Diagonal** cells display 1D univariate slice plots, representing the isolated\n",
193+
"effect of each parameter on the function output.\n",
194+
"- **Off-diagonal** cells visualize pairwise interactions between parameters using\n",
195+
"either 3D surface or contour plots.\n",
196+
"\n",
197+
"\n",
198+
"### Single projection type\n",
199+
"##### (eg: `projection: \"surface\"`)\n",
200+
"\n",
201+
"By default, when a single projection type is specified (e.g., \"surface\" or \"contour\"), the following behavior is applied:\n",
202+
"\n",
203+
"- The **lower triangle** of the grid (i.e., plots below the diagonal) displays the\n",
204+
"specified projection type.\n",
205+
"- The **upper triangle** remains empty to avoid redundancy.\n",
206+
"\n",
207+
"This allows for a quick and uncluttered visualization of pairwise parameter interactions."
208+
]
209+
},
210+
{
211+
"cell_type": "code",
212+
"execution_count": null,
213+
"id": "13",
214+
"metadata": {},
215+
"outputs": [],
216+
"source": [
217+
"fig = om.sandbox.slice_plot_3d(\n",
218+
" func=sphere,\n",
219+
" params=params,\n",
220+
" bounds=bounds,\n",
221+
" projection=\"surface\",\n",
222+
" n_gridpoints=20,\n",
223+
")\n",
224+
"fig.show()"
225+
]
226+
},
227+
{
228+
"cell_type": "markdown",
229+
"id": "14",
230+
"metadata": {},
231+
"source": [
232+
"### Multiple projection types\n",
233+
"##### (eg: `projection: {\"lower\": \"surface\", \"upper\": \"contour\"}`)\n",
234+
"\n",
235+
"For enhanced flexibility, slice_plot_3d also supports customizing projection types independently for the upper and lower halves of the grid. This is done by passing a dictionary to the projection argument:\n",
236+
"\n",
237+
"- The **\"lower\"** key controls the projection type for plots below the diagonal.\n",
238+
"- The **\"upper\"** key controls the projection type for plots above the diagonal.\n",
239+
"\n",
240+
"For example, setting \"lower\" to \"surface\" and \"upper\" to \"contour\" enables simultaneous display of both 3D and 2D representations, maximizing interpretability."
241+
]
242+
},
243+
{
244+
"cell_type": "code",
245+
"execution_count": null,
246+
"id": "15",
247+
"metadata": {},
248+
"outputs": [],
249+
"source": [
250+
"fig = om.sandbox.slice_plot_3d(\n",
251+
" func=sphere,\n",
252+
" params=params,\n",
253+
" bounds=bounds,\n",
254+
" projection={\"lower\": \"surface\", \"upper\": \"contour\"},\n",
255+
" n_gridpoints=20,\n",
256+
")\n",
257+
"fig.show()"
258+
]
259+
},
260+
{
261+
"cell_type": "markdown",
262+
"id": "16",
263+
"metadata": {},
264+
"source": [
265+
"This **dual-projection** layout is particularly useful when analyzing high-dimensional\n",
266+
"functions, as it provides both detailed surface representations and compact contour visualizations in a single coherent grid."
267+
]
268+
},
269+
{
270+
"cell_type": "markdown",
271+
"id": "17",
272+
"metadata": {},
273+
"source": [
274+
"## Full Customization of the Visualization\n",
275+
"\n",
276+
"`s‍lice_plot_3d` allows fine control over plot styling:\n",
277+
"\n",
278+
"- `layout_kwargs` adjusts figure size, titles, background themes.\n",
279+
"- `plot_kwargs` controls color maps, marker options, and plot styles.\n",
280+
"- `make_subplot_kwargs` configures grid spacing, axis sharing, and more.\n",
281+
"\n",
282+
"Here, we demonstrate a fully customized plot combining all these features."
283+
]
284+
},
285+
{
286+
"cell_type": "code",
287+
"execution_count": null,
288+
"id": "18",
289+
"metadata": {},
290+
"outputs": [],
291+
"source": [
292+
"fig = om.sandbox.slice_plot_3d(\n",
293+
" func=sphere,\n",
294+
" params=params,\n",
295+
" bounds=bounds,\n",
296+
" selector=lambda p: [p[\"alpha\"], p[\"beta\"], p[\"gamma\"]],\n",
297+
" projection=\"surface\",\n",
298+
" n_gridpoints=40,\n",
299+
" layout_kwargs={\n",
300+
" \"width\": 800,\n",
301+
" \"height\": 800,\n",
302+
" \"title\": {\"text\": \"Customized Sphere Function Visualization\"},\n",
303+
" \"template\": \"plotly_dark\",\n",
304+
" },\n",
305+
" make_subplot_kwargs={\n",
306+
" \"horizontal_spacing\": 0.1,\n",
307+
" \"vertical_spacing\": 0.1,\n",
308+
" },\n",
309+
" plot_kwargs={\n",
310+
" \"surface_plot\": {\"colorscale\": \"Viridis\", \"opacity\": 0.7},\n",
311+
" },\n",
312+
")\n",
313+
"fig.show()"
314+
]
315+
}
316+
],
317+
"metadata": {
318+
"kernelspec": {
319+
"display_name": "Python 3 (ipykernel)",
320+
"language": "python",
321+
"name": "python3"
322+
},
323+
"language_info": {
324+
"codemirror_mode": {
325+
"name": "ipython",
326+
"version": 3
327+
},
328+
"file_extension": ".py",
329+
"mimetype": "text/x-python",
330+
"name": "python",
331+
"nbconvert_exporter": "python",
332+
"pygments_lexer": "ipython3",
333+
"version": "3.10.17"
334+
}
335+
},
336+
"nbformat": 4,
337+
"nbformat_minor": 5
338+
}

src/optimagic/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from optimagic import constraints, mark, timing, utilities
3+
from optimagic import constraints, mark, sandbox, timing, utilities
44
from optimagic.algorithms import algos
55
from optimagic.benchmarking.benchmark_reports import (
66
convergence_report,
@@ -105,4 +105,5 @@
105105
"algos",
106106
"pygad",
107107
"timing",
108+
"sandbox",
108109
]

src/optimagic/sandbox.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from optimagic.visualization.slice_plot_3d import slice_plot_3d
2+
3+
__all__ = ["slice_plot_3d"]

0 commit comments

Comments
 (0)