Skip to content

Commit 9a7d575

Browse files
committed
improving on the plot Optimization function:
- having option to switch between stacked 'tall' and a grid type. Default is tall. - having ylabels instead of titles. - other improvements to make sure there is no overlays between the subplots.
1 parent 876b336 commit 9a7d575

File tree

1 file changed

+63
-32
lines changed

1 file changed

+63
-32
lines changed

famodel/design/LineDesign.py

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,8 +1313,14 @@ def getCons4PSO(self, X):
13131313
return conList
13141314

13151315

1316-
def plotOptimization(self):
1317-
1316+
def plotOptimization(self, layout="grid"):
1317+
'''Plot the optimization trajectory, including design variables, constraints and cost.
1318+
1319+
Parameters
1320+
----------
1321+
layout : str
1322+
"tall" (default) or "grid" layout for subplots. The grid will place all d.v.s in the first column, all constraints in the second column, and cost in the third column.
1323+
'''
13181324
if len(self.log['x']) == 0:
13191325
print("No optimization trajectory saved (log is empty). Nothing to plot.")
13201326
return
@@ -1325,52 +1331,77 @@ def plotOptimization(self):
13251331

13261332
n_dv = len(self.X0)
13271333
n_con = len(self.constraints)
1328-
n_rows = max(n_dv, n_con, 1)
1329-
1330-
fig, axes = plt.subplots(n_rows, 3, sharex=True, figsize=[12, 3*n_rows])
1331-
fig.subplots_adjust(left=0.1, right=0.95, hspace=0.5, wspace=0.4)
13321334

1333-
if n_rows == 1:
1334-
axes = axes[np.newaxis, :]
1335+
if layout=="tall":
1336+
n_rows = n_dv + n_con + 1
1337+
fig, axes = plt.subplots(n_rows, 1, sharex=True, figsize=[6, 1.5*n_rows])
1338+
axes = axes.reshape(-1, 1)
1339+
elif layout=="grid":
1340+
n_rows = max(n_dv, n_con, 1)
1341+
fig, axes = plt.subplots(n_rows, 3, sharex=True, figsize=[12, 1.5*n_rows])
1342+
if n_rows == 1:
1343+
axes = axes[np.newaxis, :]
13351344

13361345
# --- Column 1: Design variables ---
13371346
for i in range(n_dv):
13381347
ax = axes[i, 0]
13391348
ax.plot(Xs[:, i], color='blue')
1340-
ax.set_title(f"d.v.{i+1} [{self.X0Units[i]}]")
1341-
1342-
# turn off unused subplots
1343-
for i in range(n_dv, n_rows):
1344-
axes[i, 0].axis("off")
1349+
ax.set_ylabel(f"d.v.{i+1} ({self.X0Units[i]})", rotation=0, labelpad=20,fontsize=10, ha='right', va='center')
13451350

1346-
# --- Column 2: Constraints ---
1351+
# --- Column 2 / stacked: Constraints ---
13471352
for i, con in enumerate(self.constraints):
1348-
tol = 0.005 * (max(Gs[:, 0])-min(Gs[:, 0]))
1349-
ax = axes[i, 1]
1353+
idx = i if layout == "grid" else n_dv + i
1354+
ax = axes[idx, 1 if layout == "grid" else 0]
13501355
ax.axhline(0, color=[0.5,0.5,0.5])
1356+
tol = 0.005 * (max(Gs[:, i])-min(Gs[:, i]))
13511357
color = 'green' if Gs[-1, i] >= -tol else 'red'
13521358
ax.plot(Gs[:, i], color=color)
1353-
ax.set_title(f"{con['name']} ({con['threshold']}) [{con['unit']}]")
1354-
1355-
for i in range(n_con, n_rows):
1356-
axes[i, 1].axis("off")
1357-
1358-
# --- Column 3: Cost ---
1359-
ax_cost = axes[0, 2]
1359+
ax.set_ylabel(f"{con['name']} ({con['unit']})",
1360+
rotation=0, labelpad=20,
1361+
ha='right', va='center',
1362+
fontsize=10)
1363+
# Show threshold value inside plot
1364+
ax.text(0.98, 0.90, f"{con['threshold']}",
1365+
transform=ax.transAxes,
1366+
va='top', ha='right', fontsize=8, color='black')
1367+
1368+
# --- Column 3 / stacked: Cost ---
1369+
if layout == "grid":
1370+
ax_cost = axes[0, 2]
1371+
else:
1372+
ax_cost = axes[-1, 0]
13601373
ax_cost.plot(Fs/1e6, color='black')
1361-
ax_cost.set_title('cost [$M]')
1362-
1363-
for i in range(1, n_rows):
1364-
axes[i, 2].axis("off")
1374+
ax_cost.set_ylabel('cost (M$)', rotation=0, labelpad=20, ha='right', va='center', fontsize=10)
1375+
1376+
# remove unused axes if layout='grid'
1377+
if layout=="grid":
1378+
for i in range(n_dv, n_rows):
1379+
axes[i, 0].axis('off')
1380+
1381+
for i in range(n_con, n_rows):
1382+
axes[i, 1].axis('off')
1383+
1384+
for i in range(1, n_rows):
1385+
axes[i, 2].axis('off')
13651386

1366-
# x-label
1387+
# --- X labels only on bottom subplots ---
13671388
for i in range(n_rows):
1368-
for j in range(3):
1389+
for j in range(axes.shape[1]):
13691390
if axes[i, j].has_data():
1370-
axes[i, j].set_xlabel("function evaluations")
1371-
1391+
if layout == "tall":
1392+
if i == n_rows-1: # only bottom row
1393+
axes[i, j].set_xlabel("function evaluations")
1394+
else:
1395+
axes[i, j].set_xlabel("")
1396+
elif layout == "grid":
1397+
if (i == n_dv-1 and j == 0) or (i == n_con-1 and j == 1) or (i == 0 and j == 2):
1398+
axes[i, j].set_xlabel("function evaluations")
1399+
else:
1400+
axes[i, j].set_xlabel("")
1401+
1402+
13721403
plt.tight_layout()
1373-
plt.savefig("/Users/ralkarem/Documents/projects/FADesign/scripts/concepts2/LineDesign_optimization_ex.pdf", dpi=200)
1404+
13741405
def plotGA(self):
13751406
'''A function dedicated to plotting relevant GA outputs'''
13761407

0 commit comments

Comments
 (0)