(
matrix: dict[str, Any],
*,
output_path: str,
title: str | None = None,
ylabel: str | None = None,
)
| 6 | |
| 7 | |
| 8 | def render_grouped_bar_chart( |
| 9 | matrix: dict[str, Any], |
| 10 | *, |
| 11 | output_path: str, |
| 12 | title: str | None = None, |
| 13 | ylabel: str | None = None, |
| 14 | ) -> None: |
| 15 | try: |
| 16 | import matplotlib.pyplot as plt |
| 17 | import numpy as np |
| 18 | except ImportError as exc: |
| 19 | raise RuntimeError("matplotlib is required for plot generation.") from exc |
| 20 | |
| 21 | rows = list(matrix.get("rows", [])) |
| 22 | cols = list(matrix.get("cols", [])) |
| 23 | values = matrix.get("values", {}) |
| 24 | metric = str(matrix.get("metric", "value")) |
| 25 | |
| 26 | if not rows or not cols: |
| 27 | raise ValueError("No data available for plotting.") |
| 28 | |
| 29 | x = np.arange(len(rows)) |
| 30 | width = 0.8 / max(len(cols), 1) |
| 31 | |
| 32 | fig, ax = plt.subplots(figsize=(max(6.0, len(rows) * 1.1), 3.6)) |
| 33 | for index, column in enumerate(cols): |
| 34 | offsets = x + ((index - (len(cols) - 1) / 2) * width) |
| 35 | series_values = [values.get(row, {}).get(column, 0) or 0 for row in rows] |
| 36 | ax.bar(offsets, series_values, width, label=column) |
| 37 | |
| 38 | ax.set_xticks(x) |
| 39 | ax.set_xticklabels(rows, rotation=20, ha="right") |
| 40 | ax.set_ylabel(ylabel or metric.replace("_", " ").title()) |
| 41 | if title: |
| 42 | ax.set_title(title) |
| 43 | ax.legend() |
| 44 | fig.tight_layout() |
| 45 | fig.savefig(output_path, dpi=300, bbox_inches="tight") |
| 46 | plt.close(fig) |
no test coverage detected