Source code for pymoo.visualization.radar

"""Radar plot visualization for multi-objective optimization results."""

import numpy as np

from pymoo.docs import parse_doc_string
from pymoo.core.plot import Plot
from pymoo.util.misc import set_if_none_from_tuples
from pymoo.visualization.util import (
    plot_axes_lines,
    plot_axis_labels,
    plot_polygon,
    get_circle_points,
    plot_radar_line,
    equal_axis,
    no_ticks,
    parse_bounds,
    normalize,
)


[docs] class Radar(Plot): """Radar plot visualization. Args: normalize_each_objective: Whether each objective is normalized. Otherwise, the inner and outer bound is plotted. n_partitions: Number of partitions to show in the radar. point_style: The style being used to visualize the points. reverse: {reverse} axis_style: {axis_style} labels: {labels} figsize: {figsize} title: {title} legend: {legend} tight_layout: {tight_layout} cmap: {cmap} """ def __init__( self, normalize_each_objective: bool = True, n_partitions: int = 3, point_style: dict | None = None, **kwargs, ) -> None: super().__init__(**kwargs) self.normalize_each_objective = normalize_each_objective self.n_partitions = n_partitions if point_style is None: point_style = {} self.point_style = point_style set_if_none_from_tuples(self.point_style, ("s", 15)) set_if_none_from_tuples( self.axis_style, ("color", "black"), ("linewidth", 0.5), ("alpha", 0.75) ) def _plot( self, ax, _F: np.ndarray, inner: np.ndarray, outer: np.ndarray, kwargs: dict ) -> None: set_if_none_from_tuples(kwargs, ("alpha", 0.5)) # equal axis length and no ticks equal_axis(ax) no_ticks(ax) # draw the axis lines and labels plot_axes_lines(ax, outer, extend_factor=1.0, **self.axis_style) plot_axis_labels( ax, outer, self.get_labels(), margin=0.015, **self.axis_label_style ) # plot the outer radar line and the inner polygon plot_radar_line(ax, outer, **self.axis_style) plot_polygon(ax, inner) # find the corresponding point _F = inner + _F[:, None] * (outer - inner) # plot the points and no polygon ax.scatter(_F[:, 0], _F[:, 1], **self.point_style) plot_polygon(ax, _F, **kwargs) def _do(self) -> None: if self.bounds is None: raise Exception("The boundaries must be provided.") _F = np.vstack([e[0] for e in self.to_plot]) if np.any(_F < self.bounds[0]) or np.any(_F > self.bounds[1]): raise Exception( "Points out of the boundaries exist! Please make sure the boundaries are indeed boundaries." ) n_rows = len(self.to_plot) n_cols = max([len(e[0]) for e in self.to_plot]) self.init_figure(n_rows=n_rows, n_cols=n_cols, force_axes_as_matrix=True) # normalize the input bounds = parse_bounds(self.bounds, self.n_dim) to_plot_norm = normalize(self.to_plot, bounds, reverse=self.reverse) # get the endpoints of circle V = get_circle_points(self.n_dim) if self.normalize_each_objective: inner = np.zeros((self.n_dim, 1)) * V outer = np.ones((self.n_dim, 1)) * V else: inner = bounds[[0]].T * V outer = (bounds[[1]].T * V) / bounds[1].max() for k, (F, kwargs) in enumerate(to_plot_norm): for j, _F in enumerate(F): self._plot(self.ax[k, j], _F, inner, outer, kwargs)
parse_doc_string(Radar.__init__)