Skip to content

Add "↑/↓ better" direction annotations to all metric y-axes - #3

Merged
kjappelbaum merged 2 commits into
mainfrom
copilot/make-axes-more-intuitive
Apr 12, 2026
Merged

Add "↑/↓ better" direction annotations to all metric y-axes#3
kjappelbaum merged 2 commits into
mainfrom
copilot/make-axes-more-intuitive

Conversation

Copilot AI commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Mixed metrics across subplots (MAE lower-is-better vs. F1/Accuracy higher-is-better) make figures hard to scan, especially since MAE panels visually trend in the opposite direction to the others.

Changes

  • New helpers in plotting_utils.py

    • _LOWER_IS_BETTER_METRICS constant set (mae, mape, rmse, mse)
    • _is_lower_better(metric) — classifies metric direction
    • _add_good_direction_annotation(ax, metric, compact) — places a small italic gray ↓ better or ↑ better label at the top-left of each axis
  • Applied to every metric y-axis across all plotting functions:

    • plot_performance_comparison() — each metric subplot
    • plot_parameter_sweep_results() — each parameter-sweep panel
    • _plot_meta_prediction_panel() — author/journal (F1 → ) and year (MAE → )
    • create_main_figure_panel() — bottom performance panel
    • plot_meta_comparison() — property prediction panel
# Example: MAE axis gets "↓ better", F1 axis gets "↑ better"
_add_good_direction_annotation(ax, 'mae')      # → "↓ better"
_add_good_direction_annotation(ax, 'f1_micro') # → "↑ better"

Summary by Sourcery

Annotate all metric plots with visual cues indicating whether higher or lower values are better.

Enhancements:

  • Introduce shared helpers to classify metric direction and annotate axes with '↑/↓ better' labels based on the metric.
  • Apply direction-of-improvement annotations to all metric-related y-axes across performance, parameter sweep, meta-prediction, main figure, and meta-comparison plots to improve readability.

Copilot AI linked an issue Apr 2, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Update axes for consistent interpretation in plots Add "↑/↓ better" direction annotations to all metric y-axes Apr 2, 2026
Copilot AI requested a review from kjappelbaum April 2, 2026 08:31
@kjappelbaum
kjappelbaum marked this pull request as ready for review April 12, 2026 06:04
@sourcery-ai

sourcery-ai Bot commented Apr 12, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a reusable helper to annotate metric plots with "↑/↓ better" indicators and applies it consistently to all metric y-axes across plotting routines so readers can immediately see whether higher or lower values are better for each metric.

Class diagram for plotting_utils metric direction helpers and usage

classDiagram
    class MetricDirectionHelper {
        <<module_helpers>>
        _LOWER_IS_BETTER_METRICS : set
        _is_lower_better(metric str) bool
        _add_good_direction_annotation(ax plt_Axes, metric str, compact bool) void
    }

    class PlotPerformanceComparison {
        plot_performance_comparison(results Dict_str_Any, target_type str) None
    }

    class PlotParameterSweepResults {
        plot_parameter_sweep_results(sweep_results List_Dict_str_Any, ...) None
    }

    class PlotMetaPredictionPanel {
        _plot_meta_prediction_panel(ax plt_Axes, results Dict_str_Any, meta_type str, metric str, compact bool) None
    }

    class CreateMainFigurePanel {
        create_main_figure_panel(results Dict_str_Any, main_metric str, ...) None
    }

    class PlotMetaComparison {
        plot_meta_comparison(comparison_results Dict_str_Any, primary_metric str, ...) None
    }

    MetricDirectionHelper <|.. PlotPerformanceComparison : uses
    MetricDirectionHelper <|.. PlotParameterSweepResults : uses
    MetricDirectionHelper <|.. PlotMetaPredictionPanel : uses
    MetricDirectionHelper <|.. CreateMainFigurePanel : uses
    MetricDirectionHelper <|.. PlotMetaComparison : uses

    PlotPerformanceComparison ..> MetricDirectionHelper : calls _add_good_direction_annotation
    PlotParameterSweepResults ..> MetricDirectionHelper : calls _add_good_direction_annotation
    PlotMetaPredictionPanel ..> MetricDirectionHelper : calls _add_good_direction_annotation
    CreateMainFigurePanel ..> MetricDirectionHelper : calls _add_good_direction_annotation
    PlotMetaComparison ..> MetricDirectionHelper : calls _add_good_direction_annotation
Loading

File-Level Changes

Change Details Files
Introduce shared helpers to classify metric direction and render a small "better" direction label on axes.
  • Define _LOWER_IS_BETTER_METRICS set to identify error metrics where lower scores indicate better performance.
  • Add _is_lower_better(metric: str) to centralize the lower-is-better check using case-insensitive matching.
  • Implement _add_good_direction_annotation(ax, metric, compact=False) to draw an italic gray "↓ better" or "↑ better" label near the top-left of an axis, with slightly smaller font when compact is True.
src/scripts/plotting_utils.py
Annotate all performance-related plots with the new direction labels for their metric y-axes.
  • In plot_performance_comparison, call _add_good_direction_annotation for each metric subplot after configuring the y-label.
  • In plot_parameter_sweep_results, call _add_good_direction_annotation for each parameter-sweep panel using the panel’s metric.
  • In _plot_meta_prediction_panel, invoke _add_good_direction_annotation with compact=True-aware behavior so meta panels get direction labels without crowding.
  • In create_main_figure_panel, annotate the bottom performance panel’s main_metric axis with the appropriate direction label.
  • In plot_meta_comparison, add a direction annotation for the primary_metric axis of the property prediction panel.
src/scripts/plotting_utils.py

Assessment against linked issues

Issue Objective Addressed Explanation
#1 Make it clear for each metric axis (F1, accuracy, MAE, etc.) which direction on the y-axis corresponds to better performance, so readers are not confused by mixed higher-is-better and lower-is-better metrics across subplots.
#1 Increase the behavioral consistency of the y-axes across plots (e.g., F1/accuracy vs. MAE), so that all panels visually behave in the same way with respect to better/worse performance (rather than some going up→good and others up→bad). The PR adds '↑/↓ better' annotations to all metric y-axes, which clarifies interpretation but does not change the underlying axis orientation or metric choice. MAE panels still visually trend in the opposite direction to F1/accuracy panels (up→worse), so the plots do not actually behave more consistently; they are only better labeled.

Possibly linked issues

  • #make axes more intuitive: PR directly clarifies metric improvement directions on all y-axes, resolving the issue’s confusing, inconsistent plot behavior.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • Currently any metric not in _LOWER_IS_BETTER_METRICS is treated as ↑ better; consider either making the mapping explicit for all expected metrics or skipping/raising for unknown names so you don’t silently mislabel new or custom metrics.
  • You might want an optional flag on the public plotting functions (e.g., show_direction_annotations: bool = True) that is passed into _add_good_direction_annotation so callers can disable these labels when they conflict with tight layouts or custom figure styling.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Currently any metric not in `_LOWER_IS_BETTER_METRICS` is treated as `↑ better`; consider either making the mapping explicit for all expected metrics or skipping/raising for unknown names so you don’t silently mislabel new or custom metrics.
- You might want an optional flag on the public plotting functions (e.g., `show_direction_annotations: bool = True`) that is passed into `_add_good_direction_annotation` so callers can disable these labels when they conflict with tight layouts or custom figure styling.

## Individual Comments

### Comment 1
<location path="src/scripts/plotting_utils.py" line_range="64-66" />
<code_context>
+_LOWER_IS_BETTER_METRICS = {'mae', 'mape', 'rmse', 'mse'}
+
+
+def _is_lower_better(metric: str) -> bool:
+    """Return True if lower values are better for this metric."""
+    return metric.lower() in _LOWER_IS_BETTER_METRICS
+
+
</code_context>
<issue_to_address>
**suggestion:** Normalize metric strings more defensively to avoid subtle mismatches.

`_is_lower_better` currently requires an exact lowercase match. If callers pass names with whitespace or minor decoration (e.g. `'rmse '`, `'RMSE\n'`, `'rmse (val)'`), it will incorrectly fall back to higher-is-better. Consider normalizing more aggressively (e.g. `metric.strip().lower()`) and, if relevant, handling simple aliases/suffixes before the membership check to avoid wrong arrow directions from small naming differences.

```suggestion
def _is_lower_better(metric: str) -> bool:
    """Return True if lower values are better for this metric.

    Normalizes common formatting variations (whitespace, case, and
    simple parenthetical decorations like "rmse (val)").
    """
    # Normalize whitespace and case
    normalized = metric.strip().lower()

    # Drop simple parenthetical decorations, e.g. "rmse (val)" -> "rmse"
    if "(" in normalized:
        normalized = normalized.split("(", 1)[0].rstrip()

    return normalized in _LOWER_IS_BETTER_METRICS
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +64 to +66
def _is_lower_better(metric: str) -> bool:
"""Return True if lower values are better for this metric."""
return metric.lower() in _LOWER_IS_BETTER_METRICS

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Normalize metric strings more defensively to avoid subtle mismatches.

_is_lower_better currently requires an exact lowercase match. If callers pass names with whitespace or minor decoration (e.g. 'rmse ', 'RMSE\n', 'rmse (val)'), it will incorrectly fall back to higher-is-better. Consider normalizing more aggressively (e.g. metric.strip().lower()) and, if relevant, handling simple aliases/suffixes before the membership check to avoid wrong arrow directions from small naming differences.

Suggested change
def _is_lower_better(metric: str) -> bool:
"""Return True if lower values are better for this metric."""
return metric.lower() in _LOWER_IS_BETTER_METRICS
def _is_lower_better(metric: str) -> bool:
"""Return True if lower values are better for this metric.
Normalizes common formatting variations (whitespace, case, and
simple parenthetical decorations like "rmse (val)").
"""
# Normalize whitespace and case
normalized = metric.strip().lower()
# Drop simple parenthetical decorations, e.g. "rmse (val)" -> "rmse"
if "(" in normalized:
normalized = normalized.split("(", 1)[0].rstrip()
return normalized in _LOWER_IS_BETTER_METRICS

@kjappelbaum
kjappelbaum merged commit 92e4261 into main Apr 12, 2026
1 of 3 checks passed
@kjappelbaum
kjappelbaum deleted the copilot/make-axes-more-intuitive branch April 12, 2026 06:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

make axes more intuitive

2 participants