From 853e5ca001869130c7c08e960d38fbc3e0c7aa43 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 17 Aug 2026 09:50:49 +0000 Subject: [PATCH] Fix radar_plot axis ranges for asymmetric padding and constant metrics The upper padding was derived from the range after the lower bound had already been shifted, so the top of each axis was padded by 11% of the data range instead of 10%. A metric with the same value for every model also produced a zero-width range, which made matplotlib warn about singular limits and collapsed every other metric onto a single radius (or produced NaN coordinates when all metrics were constant). Co-authored-by: Tony Coder <407243179@qq.com> --- src/evaluate/visualization.py | 11 +++++------ tests/test_viz.py | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/evaluate/visualization.py b/src/evaluate/visualization.py index b8be86058..19bbc7070 100644 --- a/src/evaluate/visualization.py +++ b/src/evaluate/visualization.py @@ -184,12 +184,11 @@ def radar_plot(data, model_names, invert_range=[], config=None, fig=None): if all(x in variables for x in invert_range) is False: raise ValueError("All of the metrics in `invert_range` should be in the data provided.") min_max_per_variable = data.describe().T[["min", "max"]] - min_max_per_variable["min"] = min_max_per_variable["min"] - 0.1 * ( - min_max_per_variable["max"] - min_max_per_variable["min"] - ) - min_max_per_variable["max"] = min_max_per_variable["max"] + 0.1 * ( - min_max_per_variable["max"] - min_max_per_variable["min"] - ) + padding = 0.1 * (min_max_per_variable["max"] - min_max_per_variable["min"]) + # variables that take a single value across all models would otherwise get a zero-width range + padding = padding.where(padding > 0, 0.1) + min_max_per_variable["min"] = min_max_per_variable["min"] - padding + min_max_per_variable["max"] = min_max_per_variable["max"] + padding ranges = list(min_max_per_variable.itertuples(index=False, name=None)) ranges = [ diff --git a/tests/test_viz.py b/tests/test_viz.py index c44e5104e..b6bd7de8c 100644 --- a/tests/test_viz.py +++ b/tests/test_viz.py @@ -1,6 +1,7 @@ from unittest import TestCase import matplotlib.pyplot as plt +import numpy as np from evaluate.visualization import radar_plot @@ -22,3 +23,23 @@ def test_output_is_plot(self): invert_range = ["latency_in_seconds"] out_plt = radar_plot(data, model_names, invert_range) self.assertIsInstance(out_plt, plt.Figure) + + def test_range_padding_is_symmetric(self): + data = [{"accuracy": 0.0, "precision": 1.0}, {"accuracy": 10.0, "precision": 2.0}] + model_names = ["model1", "model2"] + out_plt = radar_plot(data, model_names) + # the accuracy values span 10, so both ends of its axis are padded by 1 + low, high = out_plt.axes[0].get_ylim() + self.assertAlmostEqual(low, -1.0) + self.assertAlmostEqual(high, 11.0) + + def test_metric_with_identical_values(self): + data = [{"accuracy": 0.9, "precision": 0.8}, {"accuracy": 0.9, "precision": 0.6}] + model_names = ["model1", "model2"] + out_plt = radar_plot(data, model_names) + # accuracy is identical for both models, but precision is not, so the two + # plotted shapes must still differ from each other + first, second = (line.get_ydata() for line in out_plt.axes[1].lines) + self.assertTrue(np.isfinite(first).all()) + self.assertTrue(np.isfinite(second).all()) + self.assertFalse(np.array_equal(first, second))