Source code for gunz_ml.plots.pareto_continuous_color

"""
Plotting function for Pareto frontiers colored by a continuous hyperparameter.
"""
# =============================================================================
# METADATA
# =============================================================================
__author__ = "Yeremia Gunawan Adhisantoso"
__email__ = "adhisant@tnt.uni-hannover.de"
__license__ = "Clear BSD"
__version__ = "1.0.0"

# =============================================================================
# STANDARD LIBRARY IMPORTS
# =============================================================================
import itertools
import logging
import pathlib
import typing as t

# =============================================================================
# THIRD-PARTY IMPORTS
# =============================================================================
import pandas as pd
import plotly.graph_objects as go
from omegaconf import DictConfig
from optuna.study import StudyDirection

# =============================================================================
# LOCAL APPLICATION IMPORTS
# =============================================================================
from .utils import DEFAULT_PLOT_CONFIG

[docs] def plot_pareto_continuous_color( #? --- Data Inputs --- metric_df: pd.DataFrame, param_df: pd.DataFrame, #? --- Plotting Configuration --- objective_metrics: t.List[str], study_directions: t.List[StudyDirection], output_path: pathlib.Path, continuous_params_map: t.Dict[str, str], plot_cfg: t.Union[DictConfig, t.Dict], ) -> None: """ Generates Pareto fronts of 2 objectives, colored by a continuous parameter. """ if not continuous_params_map: logging.warning("Skipping continuous Pareto plots: no continuous params found.") return logging.info("--- Starting Continuous Pareto Plot Generation ---") plot_output_path = output_path / "continuous_pareto" cfg = {**DEFAULT_PLOT_CONFIG, **plot_cfg} combined_df = pd.concat([metric_df, param_df], axis=1) directions_map = {name: d for name, d in zip(objective_metrics, study_directions)} for metric_x, metric_y in itertools.combinations(objective_metrics, 2): for param_name, param_type in continuous_params_map.items(): pareto_df = find_pareto_frontier_fast(combined_df, metric_x, metric_y, directions_map[metric_x], directions_map[metric_y]) fig = go.Figure() fig.add_trace(go.Scatter( x=combined_df[metric_x], y=combined_df[metric_y], mode='markers', marker=dict(color='grey', opacity=0.2, size=4), name='All Trials', customdata=combined_df.index, hovertemplate=f'<b>Trial</b>: %{{customdata}}<br><b>{metric_x}</b>: %{{x}}<br><b>{metric_y}</b>: %{{y}}<extra></extra>' )) fig.add_trace(go.Scatter( x=pareto_df[metric_x], y=pareto_df[metric_y], mode='lines+markers', marker=dict(color=pareto_df[param_name], colorscale='Cividis', showscale=True, colorbar_title=param_name.replace('/', '_'), size=10), line=dict(width=3), name='Pareto Frontier', customdata=pareto_df.index, hovertemplate=f'<b>Trial</b>: %{{customdata}}<br><b>{param_name}</b>: %{{marker.color}}<br><b>{metric_x}</b>: %{{x}}<br><b>{metric_y}</b>: %{{y}}<extra></extra>' )) fig.update_layout( title=f'Pareto: {metric_x} vs. {metric_y}<br><sub>Colored by {param_name}</sub>', xaxis_title=f"{metric_x} ({directions_map[metric_x].name})", yaxis_title=f"{metric_y} ({directions_map[metric_y].name})", template=cfg["template"] ) param_output_path = plot_output_path / param_name param_output_path.mkdir(parents=True, exist_ok=True) fname = f"{metric_x}_vs_{metric_y}.html".replace('/', '_') fig.write_html(param_output_path / fname)