Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 83 additions & 64 deletions pymoo/util/running_metric.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import matplotlib.pyplot as plt
import numpy as np

from pymoo.core.callback import Callback
Expand All @@ -7,7 +6,7 @@
from pymoo.termination.ftol import calc_delta_norm
from pymoo.util.normalization import normalize
from pymoo.util.sliding_window import SlidingWindow
from pymoo.visualization.video.callback_video import AnimationCallback
from pymoo.visualization.matplotlib import is_matplotlib_available


class RunningMetric(Callback):
Expand Down Expand Up @@ -64,65 +63,85 @@ def update(self, algorithm):

self.delta_ideal, self.delta_nadir, self.delta_f = delta_ideal, delta_nadir, delta_f


class RunningMetricAnimation(AnimationCallback):

def __init__(self,
delta_gen,
n_plots=4,
key_press=True,
**kwargs) -> None:

super().__init__(**kwargs)
self.running = RunningMetric()
self.delta_gen = delta_gen
self.key_press = key_press
self.data = SlidingWindow(n_plots)

def draw(self, data, ax):

for tau, x, f, v in data[:-1]:
ax.plot(x, f, label="t=%s" % tau, alpha=0.6, linewidth=3)

tau, x, f, v = data[-1]
ax.plot(x, f, label="t=%s (*)" % tau, alpha=0.9, linewidth=3)

for k in range(len(v)):
if v[k]:
ax.plot([k + 1, k + 1], [0, f[k]], color="black", linewidth=0.5, alpha=0.5)
ax.plot([k + 1], [f[k]], "o", color="black", alpha=0.5, markersize=2)

ax.set_yscale("symlog")
ax.legend()

ax.set_xlabel("Generation")
ax.set_ylabel("$\Delta \, f$", rotation=0)

def do(self, _, algorithm, force_plot=False, **kwargs):
running = self.running

# update the running metric to have the most recent information
running.update(algorithm)

tau = algorithm.n_gen

if (tau > 0 and tau % self.delta_gen == 0) or force_plot:

f = running.delta_f
x = np.arange(len(f)) + 1
v = [max(ideal, nadir) > 0.005 for ideal, nadir in zip(running.delta_ideal, running.delta_nadir)]
self.data.append((tau, x, f, v))

fig, ax = plt.subplots()
self.draw(self.data, ax)

if self.key_press:
def press(event):
if event.key == 'q':
algorithm.termination.force_termination = True

fig.canvas.mpl_connect('key_press_event', press)

plt.draw()
plt.waitforbuttonpress()
plt.close('all')
if is_matplotlib_available():
# only conditionally define `RunningMetricAnimation` if matplotlib is available
from pymoo.visualization.matplotlib import plt
from pymoo.visualization.video.callback_video import AnimationCallback

class RunningMetricAnimation(AnimationCallback):

def __init__(self,
delta_gen,
n_plots=4,
key_press=True,
**kwargs) -> None:

super().__init__(**kwargs)
self.running = RunningMetric()
self.delta_gen = delta_gen
self.key_press = key_press
self.data = SlidingWindow(n_plots)

def draw(self, data, ax):

for tau, x, f, v in data[:-1]:
ax.plot(x, f, label="t=%s" % tau, alpha=0.6, linewidth=3)

tau, x, f, v = data[-1]
ax.plot(x, f, label="t=%s (*)" % tau, alpha=0.9, linewidth=3)

for k in range(len(v)):
if v[k]:
ax.plot([k + 1, k + 1], [0, f[k]], color="black", linewidth=0.5, alpha=0.5)
ax.plot([k + 1], [f[k]], "o", color="black", alpha=0.5, markersize=2)

ax.set_yscale("symlog")
ax.legend()

ax.set_xlabel("Generation")
ax.set_ylabel("$\Delta \, f$", rotation=0)

def do(self, _, algorithm, force_plot=False, **kwargs):
running = self.running

# update the running metric to have the most recent information
running.update(algorithm)

tau = algorithm.n_gen

if (tau > 0 and tau % self.delta_gen == 0) or force_plot:

f = running.delta_f
x = np.arange(len(f)) + 1
v = [max(ideal, nadir) > 0.005 for ideal, nadir in zip(running.delta_ideal, running.delta_nadir)]
self.data.append((tau, x, f, v))

fig, ax = plt.subplots()
self.draw(self.data, ax)

if self.key_press:
def press(event):
if event.key == 'q':
algorithm.termination.force_termination = True

fig.canvas.mpl_connect('key_press_event', press)

plt.draw()
plt.waitforbuttonpress()
plt.close('all')
else:
class RunningMetricAnimation:
"""Helper class that raises informative errors when matplotlib is not available."""

def __getattr__(self, name):
raise ImportError(
"Visualization features require matplotlib.\n"
"Install with: pip install pymoo[visualization]"
)

def __call__(self, *args, **kwargs):
raise ImportError(
"Visualization features require matplotlib.\n"
"Install with: pip install pymoo[visualization]"
)

4 changes: 2 additions & 2 deletions pymoo/util/value_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from scipy.optimize import minimize as scimin
from scipy.optimize import OptimizeResult
from pymoo.core.problem import Problem
import matplotlib.pyplot as plt
from scipy.optimize import NonlinearConstraint
from scipy.optimize import Bounds
from pymoo.algorithms.soo.nonconvex.es import ES
Expand Down Expand Up @@ -278,7 +277,8 @@ def poly_vf(P, x):


def plot_vf(P, vf, show=True):

# import plt function locally as matplotlib is an optional dependency
from pymoo.visualization.matplotlib import plt
plt.scatter(P[:,0], P[:,1], marker=".", color="red", s=200 )


Expand Down
4 changes: 2 additions & 2 deletions pymoo/visualization/matplotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# Export all commonly used matplotlib objects
__all__ = [
'matplotlib', 'plt', 'patches', 'colors', 'cm', 'animation',
'LineCollection', 'PatchCollection', 'ListedColormap', 'is_available'
'LineCollection', 'PatchCollection', 'ListedColormap', 'is_matplotlib_available'
]

except ImportError:
Expand Down Expand Up @@ -57,7 +57,7 @@ def __call__(self, *args, **kwargs):
ListedColormap = _MatplotlibNotAvailable()


def is_available():
def is_matplotlib_available():
"""Check if matplotlib is available for visualization."""
return _MATPLOTLIB_AVAILABLE

Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ requires-python = ">= 3.9"
dependencies = [
"numpy>=1.19.3",
"scipy>=1.1",
"matplotlib>=3",
"autograd>=1.4",
"cma>=3.2.2",
"moocore>=0.1.7",
Expand Down