Skip to content

Commit d809f44

Browse files
0.31.1
Spot plot contour redesigned
1 parent 385c9cf commit d809f44

4 files changed

Lines changed: 292 additions & 331 deletions

File tree

notebooks/00_spotPython_tests.ipynb

Lines changed: 136 additions & 274 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
77

88
[project]
99
name = "spotpython"
10-
version = "0.31.0"
10+
version = "0.31.1"
1111
authors = [
1212
{ name="T. Bartz-Beielstein", email="tbb@bartzundbartz.de" }
1313
]

src/spotpython/spot/spot.py

Lines changed: 149 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def objective_function(X, fun_control=None):
187187
optimizer_control=optimizer_control)
188188
spot.run()
189189
spot.plot_progress()
190-
spot.plot_contour(i=0, j=1)
190+
spot.prepare_plot_contour(i=0, j=1)
191191
spot.plot_importance()
192192
"""
193193

@@ -2431,64 +2431,115 @@ def process_z00(self, z00, use_min=True) -> list:
24312431
result.append(max_value)
24322432
return result
24332433

2434-
def plot_contour(
2434+
2435+
def prepare_plot_contour(
24352436
self,
24362437
i=0,
24372438
j=1,
24382439
min_z=None,
24392440
max_z=None,
24402441
show=True,
2442+
title=None,
24412443
filename=None,
24422444
n_grid=50,
24432445
contour_levels=10,
24442446
dpi=200,
2445-
title="",
2446-
figsize=(12, 6),
2447+
figsize=(12, 5),
24472448
use_min=False,
24482449
use_max=True,
24492450
tkagg=False,
24502451
) -> None:
2451-
"""Plot the contour of any dimension."""
2452+
"""
2453+
Plot the contour and 3D surface for any pair of dimensions of the surrogate model.
2454+
This method visualizes the surrogate model's predictions over a grid for two selected dimensions.
2455+
It creates both a filled contour plot and a 3D surface plot, allowing users to inspect the surrogate's
2456+
response surface. The remaining dimensions are fixed to either their minimum or maximum values, depending
2457+
on the `use_min` and `use_max` flags.
2458+
2459+
Args:
2460+
i (int, optional): Index of the first dimension to plot. Default is 0.
2461+
j (int, optional): Index of the second dimension to plot. Default is 1.
2462+
min_z (float, optional): Minimum value for the color scale (z-axis). If None, determined automatically.
2463+
max_z (float, optional): Maximum value for the color scale (z-axis). If None, determined automatically.
2464+
show (bool, optional): Whether to display the plot interactively. Default is True.
2465+
filename (str, optional): If provided, saves the plot to this file. Default is None.
2466+
n_grid (int, optional): Number of grid points per dimension. Default is 50.
2467+
contour_levels (int, optional): Number of contour levels. Default is 10.
2468+
dpi (int, optional): Dots per inch for saved figure. Default is 200.
2469+
title (str, optional): Title for the plot. Default is None.
2470+
figsize (tuple, optional): Figure size in inches (width, height). Default is (12, 6).
2471+
use_min (bool, optional): If True, fix hidden dimensions to their minimum values. Default is False.
2472+
use_max (bool, optional): If True, fix hidden dimensions to their maximum values. Default is True.
2473+
tkagg (bool, optional): If True, use TkAgg backend for matplotlib. Default is False.
2474+
2475+
Returns:
2476+
None
2477+
"""
2478+
plot_data = self.prepare_plot(
2479+
i=i,
2480+
j=j,
2481+
n_grid=n_grid,
2482+
use_min=use_min,
2483+
use_max=use_max,
2484+
)
2485+
self.plot_contour(
2486+
plot_data,
2487+
i=i,
2488+
j=j,
2489+
show=show,
2490+
filename=filename,
2491+
contour_levels=contour_levels,
2492+
dpi=dpi,
2493+
title=title,
2494+
figsize=figsize,
2495+
tkagg=tkagg,
2496+
)
2497+
2498+
def prepare_plot(
2499+
self,
2500+
i=0,
2501+
j=1,
2502+
n_grid=50,
2503+
use_min=False,
2504+
use_max=True,
2505+
) -> dict:
2506+
"""
2507+
Prepare mesh grid and surrogate predictions for contour and 3D surface plotting.
2508+
2509+
Args:
2510+
i (int, optional): Index of the first dimension to plot. Default is 0.
2511+
j (int, optional): Index of the second dimension to plot. Default is 1.
2512+
n_grid (int, optional): Number of grid points per dimension. Default is 50.
2513+
use_min (bool, optional): If True, fix hidden dimensions to their minimum values. Default is False.
2514+
use_max (bool, optional): If True, fix hidden dimensions to their maximum values. Default is True.
2515+
2516+
Returns:
2517+
dict: Dictionary containing X_combined, Y_combined, Z_combined, min_z, max_z.
2518+
2519+
Examples:
2520+
>>> plot_data = S.prepare_plot(i=0, j=1)
2521+
"""
24522522

24532523
def generate_mesh_grid(lower, upper, grid_points):
2454-
"""Generate a mesh grid for the given range."""
24552524
x = np.linspace(lower[i], upper[i], num=grid_points)
24562525
y = np.linspace(lower[j], upper[j], num=grid_points)
24572526
return np.meshgrid(x, y), x, y
24582527

24592528
def validate_types(var_type, lower, upper):
2460-
"""Validate if the dimensions of var_type, lower, and upper are the same."""
24612529
if var_type is not None:
24622530
if len(var_type) != len(lower) or len(var_type) != len(upper):
24632531
raise ValueError("The dimensions of var_type, lower, and upper must be the same.")
24642532

2465-
def setup_plot():
2466-
"""Setup the plot with specified figure size."""
2467-
fig = pylab.figure(figsize=figsize)
2468-
return fig
2469-
24702533
def predict_contour_values(X, Y, z0):
2471-
"""Predict contour values based on the surrogate model."""
24722534
grid_points = np.c_[np.ravel(X), np.ravel(Y)]
24732535
predictions = []
2474-
24752536
for x, y in grid_points:
24762537
adjusted_z0 = self.chg(x, y, z0.copy(), i, j)
24772538
prediction = self.surrogate.predict(np.array([adjusted_z0]))
24782539
predictions.append(prediction[0])
2479-
24802540
Z = np.array(predictions).reshape(X.shape)
24812541
return Z
24822542

2483-
def plot_contour_subplots(X, Y, Z, ax, min_z, max_z, contour_levels):
2484-
"""Plot the contour and 3D surface subplots."""
2485-
contour = ax.contourf(X, Y, Z, contour_levels, zorder=1, cmap="jet", vmin=min_z, vmax=max_z)
2486-
pylab.colorbar(contour, ax=ax)
2487-
2488-
if tkagg:
2489-
matplotlib.use("TkAgg")
2490-
fig = setup_plot()
2491-
24922543
(X, Y), x, y = generate_mesh_grid(self.lower, self.upper, n_grid)
24932544
validate_types(self.var_type, self.lower, self.upper)
24942545

@@ -2509,27 +2560,70 @@ def plot_contour_subplots(X, Y, Z, ax, min_z, max_z, contour_levels):
25092560
X_list.append(X)
25102561
Y_list.append(Y)
25112562

2512-
if Z_list: # Ensure that there is at least one Z to stack
2563+
if Z_list:
25132564
Z_combined = np.vstack(Z_list)
25142565
X_combined = np.vstack(X_list)
25152566
Y_combined = np.vstack(Y_list)
2567+
else:
2568+
raise ValueError("No data to plot.")
2569+
2570+
min_z = np.min(Z_combined)
2571+
max_z = np.max(Z_combined)
25162572

2517-
if min_z is None:
2518-
min_z = np.min(Z_combined)
2519-
if max_z is None:
2520-
max_z = np.max(Z_combined)
2573+
return {
2574+
"X_combined": X_combined,
2575+
"Y_combined": Y_combined,
2576+
"Z_combined": Z_combined,
2577+
"min_z": min_z,
2578+
"max_z": max_z,
2579+
}
25212580

2522-
ax_contour = fig.add_subplot(221)
2523-
plot_contour_subplots(X_combined, Y_combined, Z_combined, ax_contour, min_z, max_z, contour_levels)
2581+
def plot_contour(
2582+
self,
2583+
plot_data: dict,
2584+
i=0,
2585+
j=1,
2586+
show=True,
2587+
filename=None,
2588+
contour_levels=10,
2589+
dpi=200,
2590+
title=None,
2591+
figsize=(12, 6),
2592+
tkagg=False,
2593+
) -> None:
2594+
"""
2595+
Plot the contour and 3D surface using prepared data.
25242596
2525-
if self.var_name is None:
2526-
ax_contour.set_xlabel(f"x{i}")
2527-
ax_contour.set_ylabel(f"x{j}")
2528-
else:
2529-
ax_contour.set_xlabel(f"x{i}: {self.var_name[i]}")
2530-
ax_contour.set_ylabel(f"x{j}: {self.var_name[j]}")
2597+
Args:
2598+
plot_data (dict): Output from prepare_plot().
2599+
i (int, optional): Index of the first dimension to plot. Default is 0.
2600+
j (int, optional): Index of the second dimension to plot. Default is 1.
2601+
show (bool, optional): Whether to display the plot interactively. Default is True.
2602+
filename (str, optional): If provided, saves the plot to this file. Default is None.
2603+
contour_levels (int, optional): Number of contour levels. Default is 10.
2604+
dpi (int, optional): Dots per inch for saved figure. Default is 200.
2605+
title (str, optional): Title for the plot. Default is None.
2606+
figsize (tuple, optional): Figure size in inches (width, height). Default is (12, 6).
2607+
tkagg (bool, optional): If True, use TkAgg backend for matplotlib. Default is False.
2608+
2609+
Returns:
2610+
None
2611+
2612+
Examples:
2613+
>>> plot_data = S.prepare_plot(i=0, j=1)
2614+
>>> S.plot_contour(plot_data, i=0, j=1, title="Surrogate Contour Plot")
2615+
"""
2616+
X_combined = plot_data["X_combined"]
2617+
Y_combined = plot_data["Y_combined"]
2618+
Z_combined = plot_data["Z_combined"]
2619+
min_z = plot_data["min_z"]
2620+
max_z = plot_data["max_z"]
2621+
2622+
if tkagg:
2623+
matplotlib.use("TkAgg")
2624+
fig = pylab.figure(figsize=figsize)
25312625

2532-
ax_3d = fig.add_subplot(222, projection="3d")
2626+
ax_3d = fig.add_subplot(121, projection="3d")
25332627
ax_3d.plot_surface(X_combined, Y_combined, Z_combined, rstride=3, cstride=3, alpha=0.9, cmap="jet", vmin=min_z, vmax=max_z)
25342628

25352629
if self.var_name is None:
@@ -2539,8 +2633,22 @@ def plot_contour_subplots(X, Y, Z, ax, min_z, max_z, contour_levels):
25392633
ax_3d.set_xlabel(f"x{i}: {self.var_name[i]}")
25402634
ax_3d.set_ylabel(f"x{j}: {self.var_name[j]}")
25412635

2542-
plt.title(title)
2636+
ax_contour = fig.add_subplot(122)
2637+
if title is not None:
2638+
ax_3d.set_title(title)
2639+
2640+
contour = ax_contour.contourf(X_combined, Y_combined, Z_combined, levels=contour_levels, zorder=1, cmap="jet", vmin=min_z, vmax=max_z)
2641+
pylab.colorbar(contour, ax=ax_contour)
2642+
2643+
if self.var_name is None:
2644+
ax_contour.set_xlabel(f"x{i}")
2645+
ax_contour.set_ylabel(f"x{j}")
2646+
else:
2647+
ax_contour.set_xlabel(f"x{i}: {self.var_name[i]}")
2648+
ax_contour.set_ylabel(f"x{j}: {self.var_name[j]}")
25432649

2650+
if title is not None:
2651+
ax_contour.set_title(title)
25442652
if filename:
25452653
pylab.savefig(filename, bbox_inches="tight", dpi=dpi, pad_inches=0)
25462654

@@ -2564,7 +2672,7 @@ def plot_important_hyperparameter_contour(
25642672
) -> None:
25652673
"""
25662674
Plot the contour of important hyperparameters.
2567-
Calls `plot_contour` for each pair of important hyperparameters.
2675+
Calls `prepare_plot_contour` for each pair of important hyperparameters.
25682676
Importance can be specified by the threshold.
25692677
25702678
Args:
@@ -2651,7 +2759,7 @@ def plot_important_hyperparameter_contour(
26512759
filename_full = filename + "_contour_" + str(i) + "_" + str(j) + ".png"
26522760
else:
26532761
filename_full = None
2654-
self.plot_contour(
2762+
self.prepare_plot_contour(
26552763
i=i,
26562764
j=j,
26572765
min_z=min_z,

src/spotpython/surrogate/plot.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,7 @@ def plot2d(model, X: np.ndarray, y: np.ndarray, show: Optional[bool] = True, alp
132132
plt.show()
133133

134134

135-
def plotkd(
136-
model,
137-
X: np.ndarray,
138-
y: np.ndarray,
139-
i: int,
140-
j: int,
141-
show: Optional[bool] = True,
142-
alpha=0.8,
143-
eps=1e-3,
144-
var_names: Optional[List[str]] = None,
145-
) -> None:
135+
def plotkd(model, X: np.ndarray, y: np.ndarray, i: int, j: int, show: Optional[bool] = True, alpha=0.8, eps=1e-3, var_names: Optional[List[str]] = None, cmap="jet") -> None:
146136
"""
147137
Plots the Kriging surrogate model for k-dimensional input data by varying two dimensions (i, j).
148138
@@ -158,6 +148,7 @@ def plotkd(
158148
var_names (List[str], optional): A list of three strings for axis labels.
159149
The first entry is for the x-axis, the second for the y-axis, and the third for the z-axis.
160150
If empty or None, default axis labels are used.
151+
cmap (str): Colormap for the surface plots. Defaults to "jet".
161152
162153
Returns:
163154
None
@@ -209,7 +200,7 @@ def plotkd(
209200

210201
# Plot predicted values
211202
ax1 = fig.add_subplot(221, projection="3d")
212-
ax1.plot_surface(X_i, X_j, Z_pred, cmap="viridis", alpha=alpha)
203+
ax1.plot_surface(X_i, X_j, Z_pred, cmap=cmap, alpha=alpha)
213204
ax1.set_title("Prediction Surface")
214205
ax1.set_xlabel(var_names[0] if var_names else f"Dimension {i}")
215206
ax1.set_ylabel(var_names[1] if var_names else f"Dimension {j}")
@@ -233,7 +224,7 @@ def plotkd(
233224

234225
# Plot prediction error
235226
ax2 = fig.add_subplot(222, projection="3d")
236-
ax2.plot_surface(X_i, X_j, Z_std, cmap="viridis", alpha=alpha)
227+
ax2.plot_surface(X_i, X_j, Z_std, cmap=cmap, alpha=alpha)
237228
ax2.set_title("Prediction Error Surface")
238229
ax2.set_xlabel(var_names[0] if var_names else f"Dimension {i}")
239230
ax2.set_ylabel(var_names[1] if var_names else f"Dimension {j}")
@@ -257,7 +248,7 @@ def plotkd(
257248

258249
# Contour plot of predicted values
259250
ax3 = fig.add_subplot(223)
260-
contour = ax3.contourf(X_i, X_j, Z_pred, cmap="viridis", levels=30)
251+
contour = ax3.contourf(X_i, X_j, Z_pred, cmap=cmap, levels=30)
261252
plt.colorbar(contour, ax=ax3)
262253
for idx in range(X.shape[0]):
263254
x_point = X[idx, i]
@@ -279,7 +270,7 @@ def plotkd(
279270

280271
# Contour plot of prediction error
281272
ax4 = fig.add_subplot(224)
282-
contour = ax4.contourf(X_i, X_j, Z_std, cmap="viridis", levels=30)
273+
contour = ax4.contourf(X_i, X_j, Z_std, cmap=cmap, levels=30)
283274
plt.colorbar(contour, ax=ax4)
284275
for idx in range(X.shape[0]):
285276
x_point = X[idx, i]

0 commit comments

Comments
 (0)