Skip to content

Commit ca94cf6

Browse files
committed
Add CLI to plot CSV and align 3D axes
1 parent 82f4b8a commit ca94cf6

1 file changed

Lines changed: 80 additions & 5 deletions

File tree

src/jmetal/util/plotting.py

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import argparse
12
import os
3+
import sys
24
from typing import Iterable
35

46
import numpy as np
@@ -70,12 +72,13 @@ def save_plt_to_file(solutions: Iterable, filename: str, out_dir: str = "results
7072
pass
7173

7274
elif n_obj == 3:
75+
axis_labels = [f"f{i+1}" for i in range(n_obj)]
7376
fig = plt.figure(figsize=(6, 6))
7477
ax = fig.add_subplot(111, projection="3d")
7578
ax.scatter(arr[:, 0], arr[:, 1], arr[:, 2], s=8, c="C0", alpha=0.8)
76-
ax.set_xlabel("f1")
77-
ax.set_ylabel("f2")
78-
ax.set_zlabel("f3")
79+
ax.set_xlabel(axis_labels[0])
80+
ax.set_ylabel(axis_labels[1])
81+
ax.set_zlabel(axis_labels[2])
7982
ax.set_title(f"{filename} approximation front (3D)")
8083
plt.tight_layout()
8184
fig.savefig(png_path, dpi=200)
@@ -86,8 +89,9 @@ def save_plt_to_file(solutions: Iterable, filename: str, out_dir: str = "results
8689
try:
8790
import pandas as pd
8891

89-
df = pd.DataFrame(arr, columns=[f"f{i+1}" for i in range(n_obj)])
90-
figly = px.scatter_3d(df, x=df.columns[0], y=df.columns[1], z=df.columns[2], title=f"{filename} approximation front (3D)")
92+
df = pd.DataFrame(arr, columns=axis_labels)
93+
figly = px.scatter_3d(df, x=axis_labels[0], y=axis_labels[1], z=axis_labels[2], title=f"{filename} approximation front (3D)")
94+
figly.update_layout(scene=dict(xaxis_title=axis_labels[0], yaxis_title=axis_labels[1], zaxis_title=axis_labels[2]))
9195
html_path = os.path.join(out_dir, f"{filename}_front.html")
9296
pyoff.plot(figly, filename=html_path, auto_open=False)
9397
except Exception:
@@ -122,3 +126,74 @@ def save_plt_to_file(solutions: Iterable, filename: str, out_dir: str = "results
122126
pass
123127

124128
return png_path
129+
130+
131+
def _read_numeric_csv(csv_path: str) -> np.ndarray:
132+
"""Load numeric columns from a CSV file into a NumPy array."""
133+
try:
134+
import pandas as pd # type: ignore
135+
136+
df = pd.read_csv(csv_path)
137+
numeric_df = df.select_dtypes(include=[np.number])
138+
if numeric_df.empty:
139+
raise ValueError("No numeric columns found in CSV")
140+
arr = numeric_df.to_numpy()
141+
if arr.ndim == 1:
142+
arr = arr.reshape(-1, 1)
143+
return arr
144+
except Exception:
145+
pass
146+
147+
for skip_header in (0, 1):
148+
data = np.genfromtxt(csv_path, delimiter=",", skip_header=skip_header)
149+
if data.size == 0 or (isinstance(data, float) and np.isnan(data)):
150+
continue
151+
if data.ndim == 0:
152+
continue
153+
if data.ndim == 1:
154+
data = data.reshape(-1, 1)
155+
data = np.asarray(data, dtype=float)
156+
if data.ndim > 1:
157+
data = data[~np.isnan(data).all(axis=1)]
158+
if data.size == 0 or np.isnan(data).all():
159+
continue
160+
return data
161+
162+
raise ValueError(f"Could not read numeric data from {csv_path}")
163+
164+
165+
def _cli() -> None:
166+
"""Entry point for plotting approximation fronts from CSV files."""
167+
parser = argparse.ArgumentParser(description="Generate approximation front plots from a numeric CSV file.")
168+
parser.add_argument("csv_file", help="Path to a CSV file containing numeric columns to plot.")
169+
parser.add_argument("--out-dir", default="results", help="Directory where output files will be written (default: results).")
170+
parser.add_argument("--base-name", help="Base name for generated files (defaults to CSV filename without extension).")
171+
parser.add_argument("--html", action="store_true", help="Also generate an interactive Plotly HTML if available.")
172+
args = parser.parse_args()
173+
174+
base_name = args.base_name or os.path.splitext(os.path.basename(args.csv_file))[0]
175+
176+
try:
177+
front = _read_numeric_csv(args.csv_file)
178+
except Exception as ex:
179+
print(f"Error reading CSV '{args.csv_file}': {ex}", file=sys.stderr)
180+
sys.exit(1)
181+
182+
try:
183+
png_path = save_plt_to_file(front, base_name, out_dir=args.out_dir, html_plotly=args.html)
184+
except Exception as ex:
185+
print(f"Error generating plot: {ex}", file=sys.stderr)
186+
sys.exit(1)
187+
188+
print(f"PNG saved to: {png_path}")
189+
if args.html:
190+
if not _PLOTLY_AVAILABLE:
191+
print("Plotly not available; HTML file not generated.", file=sys.stderr)
192+
else:
193+
html_path = os.path.join(args.out_dir, f"{base_name}_front.html")
194+
if os.path.isfile(html_path):
195+
print(f"HTML saved to: {html_path}")
196+
197+
198+
if __name__ == "__main__":
199+
_cli()

0 commit comments

Comments
 (0)