nmoo.plotting.performance_indicators

Performance indicators plotting

 1"""
 2Performance indicators plotting
 3"""
 4__docformat__ = "google"
 5
 6from typing import Iterable, Optional
 7
 8import seaborn as sns
 9
10from nmoo.benchmark import Benchmark
11
12
13# TODO: replace the benchmark argument by a benchmark_or_results_file_path, and
14# retrieve the relevant benchmark specifications from the csv file.
15def plot_performance_indicators(
16    benchmark: Benchmark,
17    row: Optional[str] = None,
18    *,
19    algorithms: Optional[Iterable[str]] = None,
20    performance_indicators: Optional[Iterable[str]] = None,
21    problems: Optional[Iterable[str]] = None,
22    legend: bool = True,
23    x: str = "n_gen",
24    logscale: bool = False,
25) -> sns.FacetGrid:
26    """
27    Plots all performance indicators in a grid of line plots.
28
29    <center>
30        <img src="https://github.com/altaris/noisy-moo/raw/main/imgs/plot_performance_indicators.png"
31        alt="Example"/>
32    </center>
33
34    The columns of this grid correspond to the performance indicators, whereas
35    the rows can be set to correspond to either `n_run`, `problem` or
36    `algorithm`. For example, if `row="algorithm"` (as is the case above), then
37    each row will correspond to an algorithm, whereas `n_run` and `problem`
38    will be compounded in the line plots. If left to `None`, then `n_run`,
39    `problem` and `algorithm` will all be compounded together.
40
41    Note:
42        If you have the benchmark definition, the `benchmark.csv` file, but do
43        not want to rerun the benchmark, you can use the following trick:
44
45            benchmark = Benchmark(...)                               # Benchmark specification
46            benchmark._results = pd.read_csv(path_to_benchmark_csv)  # Inject results
47            plot_performance_indicators(benchmark, ...)              # Plot
48
49    Args:
50        benckmark: A (ran) benchmark object.
51        row (Optional[str]): See above.
52        algorithms (Optional[Iterable[str]]): List of algorithms to plot,
53            defaults to all.
54        performance_indicators (Optional[Iterable[str]]): List of performance
55            indicators to plot, defaults to all.
56        problems (Optional[Iterable[str]]): List of problems to plot, defaults
57            to all.
58        legend (bool): Wether to display the legend. Defaults to `True`.
59        logscale (bool): Wether to have a logarithmic y scale. Defaults to
60            `False`.
61        x (str): Column for the x axis. Should be among `n_gen` (the default),
62            `n_eval`, or `timedelta`.
63    """
64    if algorithms is None:
65        algorithms = benchmark._algorithms.keys()
66    if performance_indicators is None:
67        performance_indicators = benchmark._performance_indicators
68    if problems is None:
69        problems = benchmark._problems.keys()
70    df = benchmark._results[
71        ["algorithm", "n_eval", "n_gen", "n_run", "problem", "timedelta"]
72        + ["perf_" + pi for pi in performance_indicators]
73    ]
74    df = df[(df.algorithm.isin(algorithms)) & (df.problem.isin(problems))]
75    df.rename(
76        columns={f"perf_{pi}": pi for pi in performance_indicators},
77        inplace=True,
78    )
79    df = df.melt(
80        id_vars=[
81            c for c in df.columns if c not in benchmark._performance_indicators
82        ],
83        var_name="pi",
84    )
85    grid = sns.FacetGrid(df, col="pi", row=row, sharey=False)
86    if row == "algorithm":
87        grid.map_dataframe(sns.lineplot, x=x, y="value", hue="problem")
88    elif row == "problem":
89        grid.map_dataframe(sns.lineplot, x=x, y="value", hue="algorithm")
90    else:
91        grid.map_dataframe(
92            sns.lineplot, x=x, y="value", hue="algorithm", style="problem"
93        )
94    if legend:
95        grid.add_legend()
96    if logscale:
97        grid.set(yscale="log")
98    return grid
def plot_performance_indicators( benchmark: nmoo.benchmark.Benchmark, row: Union[str, NoneType] = None, *, algorithms: Union[Iterable[str], NoneType] = None, performance_indicators: Union[Iterable[str], NoneType] = None, problems: Union[Iterable[str], NoneType] = None, legend: bool = True, x: str = 'n_gen', logscale: bool = False) -> seaborn.axisgrid.FacetGrid:
16def plot_performance_indicators(
17    benchmark: Benchmark,
18    row: Optional[str] = None,
19    *,
20    algorithms: Optional[Iterable[str]] = None,
21    performance_indicators: Optional[Iterable[str]] = None,
22    problems: Optional[Iterable[str]] = None,
23    legend: bool = True,
24    x: str = "n_gen",
25    logscale: bool = False,
26) -> sns.FacetGrid:
27    """
28    Plots all performance indicators in a grid of line plots.
29
30    <center>
31        <img src="https://github.com/altaris/noisy-moo/raw/main/imgs/plot_performance_indicators.png"
32        alt="Example"/>
33    </center>
34
35    The columns of this grid correspond to the performance indicators, whereas
36    the rows can be set to correspond to either `n_run`, `problem` or
37    `algorithm`. For example, if `row="algorithm"` (as is the case above), then
38    each row will correspond to an algorithm, whereas `n_run` and `problem`
39    will be compounded in the line plots. If left to `None`, then `n_run`,
40    `problem` and `algorithm` will all be compounded together.
41
42    Note:
43        If you have the benchmark definition, the `benchmark.csv` file, but do
44        not want to rerun the benchmark, you can use the following trick:
45
46            benchmark = Benchmark(...)                               # Benchmark specification
47            benchmark._results = pd.read_csv(path_to_benchmark_csv)  # Inject results
48            plot_performance_indicators(benchmark, ...)              # Plot
49
50    Args:
51        benckmark: A (ran) benchmark object.
52        row (Optional[str]): See above.
53        algorithms (Optional[Iterable[str]]): List of algorithms to plot,
54            defaults to all.
55        performance_indicators (Optional[Iterable[str]]): List of performance
56            indicators to plot, defaults to all.
57        problems (Optional[Iterable[str]]): List of problems to plot, defaults
58            to all.
59        legend (bool): Wether to display the legend. Defaults to `True`.
60        logscale (bool): Wether to have a logarithmic y scale. Defaults to
61            `False`.
62        x (str): Column for the x axis. Should be among `n_gen` (the default),
63            `n_eval`, or `timedelta`.
64    """
65    if algorithms is None:
66        algorithms = benchmark._algorithms.keys()
67    if performance_indicators is None:
68        performance_indicators = benchmark._performance_indicators
69    if problems is None:
70        problems = benchmark._problems.keys()
71    df = benchmark._results[
72        ["algorithm", "n_eval", "n_gen", "n_run", "problem", "timedelta"]
73        + ["perf_" + pi for pi in performance_indicators]
74    ]
75    df = df[(df.algorithm.isin(algorithms)) & (df.problem.isin(problems))]
76    df.rename(
77        columns={f"perf_{pi}": pi for pi in performance_indicators},
78        inplace=True,
79    )
80    df = df.melt(
81        id_vars=[
82            c for c in df.columns if c not in benchmark._performance_indicators
83        ],
84        var_name="pi",
85    )
86    grid = sns.FacetGrid(df, col="pi", row=row, sharey=False)
87    if row == "algorithm":
88        grid.map_dataframe(sns.lineplot, x=x, y="value", hue="problem")
89    elif row == "problem":
90        grid.map_dataframe(sns.lineplot, x=x, y="value", hue="algorithm")
91    else:
92        grid.map_dataframe(
93            sns.lineplot, x=x, y="value", hue="algorithm", style="problem"
94        )
95    if legend:
96        grid.add_legend()
97    if logscale:
98        grid.set(yscale="log")
99    return grid

Plots all performance indicators in a grid of line plots.

Example

The columns of this grid correspond to the performance indicators, whereas the rows can be set to correspond to either n_run, problem or algorithm. For example, if row="algorithm" (as is the case above), then each row will correspond to an algorithm, whereas n_run and problem will be compounded in the line plots. If left to None, then n_run, problem and algorithm will all be compounded together.

Note:

If you have the benchmark definition, the benchmark.csv file, but do not want to rerun the benchmark, you can use the following trick:

benchmark = Benchmark(...)                               # Benchmark specification
benchmark._results = pd.read_csv(path_to_benchmark_csv)  # Inject results
plot_performance_indicators(benchmark, ...)              # Plot
Arguments:
  • benckmark: A (ran) benchmark object.
  • row (Optional[str]): See above.
  • algorithms (Optional[Iterable[str]]): List of algorithms to plot, defaults to all.
  • performance_indicators (Optional[Iterable[str]]): List of performance indicators to plot, defaults to all.
  • problems (Optional[Iterable[str]]): List of problems to plot, defaults to all.
  • legend (bool): Wether to display the legend. Defaults to True.
  • logscale (bool): Wether to have a logarithmic y scale. Defaults to False.
  • x (str): Column for the x axis. Should be among n_gen (the default), n_eval, or timedelta.