Skip to content

Commit 2cab0c3

Browse files
v0.28.9
pareto front
1 parent 32391cf commit 2cab0c3

4 files changed

Lines changed: 134 additions & 3 deletions

File tree

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.28.8"
10+
version = "0.28.9"
1111
authors = [
1212
{ name="T. Bartz-Beielstein", email="tbb@bartzundbartz.de" }
1313
]

src/spotpython/fun/mohyperlight.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ def fun(self, X: np.ndarray, fun_control: dict = None) -> np.ndarray:
142142
epochs_val = config.get("epochs", np.nan) # Default to np.nan if "epochs" is not in config
143143
epochs_res = np.append(epochs_res, epochs_val)
144144

145-
# Stack z_res and epochs_res into a (2, n) array
146-
result = np.vstack((z_res, epochs_res))
145+
# Stack z_res and epochs_res into a (n, 2) array
146+
result = np.column_stack((z_res, epochs_res))
147+
print(f"result.shape: {result.shape}")
148+
print(f"result: {result}")
147149

148150
return result

src/spotpython/mo/plot.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import matplotlib.pyplot as plt
2+
import numpy as np
3+
import pandas as pd
4+
from spotpython.mo.pareto import is_pareto_efficient
5+
6+
7+
def plot_mo(
8+
target_names: list,
9+
combinations: list,
10+
pareto: str,
11+
y_rf: np.ndarray = None,
12+
pareto_front: bool = False,
13+
y_best: np.ndarray = None,
14+
title: str = "",
15+
y_orig: np.ndarray = None,
16+
pareto_front_orig: bool = False,
17+
pareto_label: bool = False,
18+
y_rf_color="blue",
19+
y_best_color="red",
20+
) -> None:
21+
"""
22+
Generates scatter plots for each combination of two targets from a multi-output prediction while highlighting Pareto optimal points.
23+
24+
Args:
25+
y_rf (np.ndarray): The predicted target values with shape (n_samples, n_targets).
26+
target_names (list): A list of target names corresponding to the columns of y_rf.
27+
combinations (list): A list of tuples, where each tuple contains the indices of the target combinations to plot.
28+
pareto (str): Specifies whether to compute Pareto front based on 'min' or 'max' criterion.
29+
pareto_front (bool): If True, connect Pareto optimal points with a red line for y_rf.
30+
y_best (np.ndarray, optional): A NumPy array representing the best point to highlight in red. Defaults to None.
31+
title (str): The title of the plot. Defaults to "" (empty string).
32+
y_orig (np.ndarray, optional): The original target values with shape (n_samples, n_targets). Defaults to None.
33+
pareto_front_orig (bool): If True, connect Pareto optimal points with a light blue line for y_orig. Defaults to False.
34+
pareto_label (bool): If True, label Pareto points with their index. Defaults to False.
35+
y_rf_color (str): The color of the predicted points. Defaults to "blue".
36+
y_best_color (str): The color of the best point. Defaults to "red".
37+
38+
Returns:
39+
None: Displays the plot.
40+
41+
Examples:
42+
>>> from spotpython.mo.plot import plot_mo
43+
>>> import numpy as np
44+
>>> target_names = ["Target 1", "Target 2"]
45+
>>> combinations = [(0, 1)]
46+
>>> pareto = "min"
47+
>>> y_rf = np.random.rand(100, 2)
48+
>>> y_orig = np.random.rand(100, 2)
49+
>>> plot_mo(target_names, combinations, pareto, y_rf=y_rf, y_orig=y_orig)
50+
"""
51+
# Convert y_rf to numpy array if it's a pandas DataFrame
52+
if isinstance(y_rf, pd.DataFrame):
53+
y_rf = y_rf.values
54+
55+
# Convert y_orig to numpy array if it's a pandas DataFrame
56+
if isinstance(y_orig, pd.DataFrame):
57+
y_orig = y_orig.values
58+
59+
for i, j in combinations:
60+
plt.figure()
61+
s = 50 # Base size for points
62+
pareto_size = s # Size for Pareto points
63+
if pareto_label:
64+
pareto_size = s * 4 # Increase the size for Pareto points
65+
a = 0.4
66+
67+
# Plot original data if provided
68+
if y_orig is not None:
69+
# Determine Pareto optimal points for original data
70+
minimize = pareto == "min"
71+
pareto_mask_orig = is_pareto_efficient(y_orig[:, [i, j]], minimize)
72+
73+
# Plot all original points
74+
plt.scatter(y_orig[:, i], y_orig[:, j], edgecolor="w", c="gray", s=s, marker="o", alpha=a, label="Original Points")
75+
76+
# Highlight Pareto points for original data
77+
plt.scatter(y_orig[pareto_mask_orig, i], y_orig[pareto_mask_orig, j], edgecolor="k", c="gray", s=pareto_size, marker="o", alpha=a, label="Original Pareto")
78+
79+
# Label Pareto points for original data if requested
80+
if pareto_label:
81+
for idx in np.where(pareto_mask_orig)[0]:
82+
plt.text(y_orig[idx, i], y_orig[idx, j], str(idx), color="black", fontsize=8, ha="center", va="center")
83+
84+
# Draw Pareto front for original data if requested
85+
if pareto_front_orig:
86+
sorted_indices_orig = np.argsort(y_orig[pareto_mask_orig, i])
87+
plt.plot(y_orig[pareto_mask_orig, i][sorted_indices_orig], y_orig[pareto_mask_orig, j][sorted_indices_orig], "k-", alpha=a, label="Original Pareto Front")
88+
89+
if y_rf is not None:
90+
# Determine Pareto optimal points for predicted data
91+
minimize = pareto == "min"
92+
pareto_mask = is_pareto_efficient(y_rf[:, [i, j]], minimize)
93+
94+
# Plot all predicted points
95+
plt.scatter(y_rf[:, i], y_rf[:, j], edgecolor="w", c=y_rf_color, s=s, marker="^", alpha=a, label="Predicted Points")
96+
97+
# Highlight Pareto points for predicted data
98+
plt.scatter(y_rf[pareto_mask, i], y_rf[pareto_mask, j], edgecolor="k", c=y_rf_color, s=pareto_size, marker="s", alpha=a, label="Predicted Pareto")
99+
100+
# Label Pareto points for predicted data if requested
101+
if pareto_label:
102+
for idx in np.where(pareto_mask)[0]:
103+
plt.text(y_rf[idx, i], y_rf[idx, j], str(idx), color="black", fontsize=8, ha="center", va="center")
104+
105+
# Draw Pareto front for predicted data if requested
106+
if pareto_front:
107+
sorted_indices = np.argsort(y_rf[pareto_mask, i])
108+
plt.plot(
109+
y_rf[pareto_mask, i][sorted_indices],
110+
y_rf[pareto_mask, j][sorted_indices],
111+
linestyle="-", # Specify the line style
112+
color=y_rf_color, # Use the color specified by y_rf_color
113+
alpha=a,
114+
label="Predicted Pareto Front",
115+
)
116+
117+
# Plot the best point, if provided
118+
if y_best is not None:
119+
plt.scatter(y_best[:, i], y_best[:, j], edgecolor="k", c=y_best_color, s=s, marker="D", alpha=1, label="Best")
120+
121+
plt.xlabel(target_names[i])
122+
plt.ylabel(target_names[j])
123+
plt.grid()
124+
plt.title(title)
125+
plt.legend()
126+
plt.show()

src/spotpython/utils/repair.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ def remove_nan(X: np.ndarray, y: np.ndarray, stop_on_zero_return: bool = False)
6060
>>> print(X_cleaned, y_cleaned)
6161
[[1 2]] [[1. 2.]]
6262
"""
63+
print(f"remove_nan: X.shape={X.shape}, y.shape={y.shape}")
64+
print(f"remove_nan: X={X},\n y={y}")
6365
# Get the original dimension of the y array
6466
original_dim = y.shape[0]
6567

@@ -70,6 +72,7 @@ def remove_nan(X: np.ndarray, y: np.ndarray, stop_on_zero_return: bool = False)
7072
ind = np.all(np.isfinite(y), axis=0)
7173
else:
7274
raise ValueError("y must be a 1D or 2D array.")
75+
print(f"remove_nan: ind={ind}")
7376

7477
# Update X and y by removing rows with NaN in y
7578
X_cleaned = X[ind, :]

0 commit comments

Comments
 (0)