Source code for gemseo.post.para_coord

# -*- coding: utf-8 -*-
# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

# Contributors:
#    INITIAL AUTHORS - API and implementation and/or documentation
#        :author: Francois Gallard
#        :author: Damien Guenot
#    OTHER AUTHORS   - MACROSCOPIC CHANGES
"""A parallel coordinates plot of functions and x."""

from __future__ import division, unicode_literals

import logging
from typing import Sequence

import matplotlib as mpl
from matplotlib import pyplot
from matplotlib.figure import Figure
from numpy import array, ndarray

from gemseo.post.core.colormaps import PARULA
from gemseo.post.opt_post_processor import OptPostProcessor, OptPostProcessorOptionType

LOGGER = logging.getLogger(__name__)


[docs]class ParallelCoordinates(OptPostProcessor): """Parallel coordinates among design variables, outputs functions and constraints.""" DEFAULT_FIG_SIZE = (10.0, 2.0)
[docs] @classmethod def parallel_coordinates( cls, y_data, # type: ndarray x_names, # type: Sequence[str] color_criteria, # type: Sequence[float] ): # type: (...) -> Figure """Plot the parallel coordinates. Args: y_data: The lines data to plot. x_names: The names of the abscissa. color_criteria: The values of same length as `y_data` to colorize the lines. """ n_x, n_cols = y_data.shape assert n_cols == len(x_names) assert n_x == len(color_criteria) x_values = list(range(n_cols)) fig = pyplot.figure(figsize=cls.DEFAULT_FIG_SIZE) main_ax = pyplot.gca() c_max = color_criteria.max() c_min = color_criteria.min() color_criteria_n = (color_criteria - c_min) / (c_max - c_min) for i in range(n_x): color = array(PARULA(color_criteria_n[i])).flatten() main_ax.plot(x_values, y_data[i, :], c=color) norm = mpl.colors.Normalize(vmin=c_min, vmax=c_max) cax, _ = mpl.colorbar.make_axes(main_ax) mpl.colorbar.ColorbarBase(cax, norm=norm, cmap=PARULA) for i in x_values: main_ax.axvline(i, linewidth=1, color="black") main_ax.set_xticks(x_values) main_ax.set_xticklabels(x_names) main_ax.grid() return fig
def _plot( self, **options # type: OptPostProcessorOptionType ): # type: (...) -> None all_funcs = self.opt_problem.get_all_functions_names() design_variables = self.opt_problem.get_design_variable_names() vals, vname, _ = self.database.get_history_array(all_funcs, add_dv=True) n_x = len(self.database.get_x_by_iter(0)) x_names = [] for d_v in design_variables: dv_size = self.opt_problem.design_space.variables_sizes[d_v] if dv_size == 1: x_names.append(d_v) else: for i in range(dv_size): x_names.append(d_v + "_" + str(i)) func_names = vname[: len(vname) - n_x] obj_name = self.opt_problem.get_objective_name() obj_val = vals[:, vname.index(obj_name)] x_vals = vals[:, vals.shape[1] - len(x_names) :] x_vals = self.opt_problem.design_space.normalize_vect(x_vals) fig = self.parallel_coordinates(x_vals, x_names, obj_val) fig.suptitle( "Design variables history colored" + " by '" + obj_name + "' value" ) self._add_figure(fig, "para_coord_des_vars") func_vals = vals[:, : vals.shape[1] - len(x_names)] fig = self.parallel_coordinates(func_vals, func_names, obj_val) fig.suptitle( "Objective function and constraints history" + " colored by '" + obj_name + "' value" ) self._add_figure(fig, "para_coord_funcs")