Plotting¶
hotcoco includes publication-quality plotting for evaluation results. Install the optional dependency:
pip install hotcoco[plot]
All plot functions return (Figure, Axes) for further customization,
accept an optional ax to draw on existing axes, and accept save_path
to write directly to disk.
PDF evaluation report¶
report() runs a full evaluation and saves a self-contained, single-page PDF —
useful for archiving results or sharing with collaborators.
from hotcoco.plot import report
gt = hotcoco.COCO("instances_val2017.json")
dt = gt.load_res("bbox_results.json")
ev = hotcoco.COCOeval(gt, dt, "bbox")
ev.run()
report(ev, save_path="report.pdf", gt_path="instances_val2017.json", dt_path="bbox_results.json")
The report includes a run context block (dataset paths, eval params, image/annotation counts), a full metrics table, precision-recall curves at IoU 0.50, 0.75, and the mean, F1 peak, and a per-category AP bar chart sorted from best to worst.
Works with all three evaluation modes — hotcoco automatically selects the right metric rows for each:
| Mode | Rows |
|---|---|
bbox / segm |
AP, AP50, AP75, APs, APm, APl · AR1, AR10, AR100, ARs, ARm, ARl |
keypoints |
AP, AP50, AP75, APm, APl · AR, AR50, AR75, ARm, ARl |
| LVIS | AP, AP50, AP75, APs, APm, APl, APr, APc, APf · AR@300, ARs@300, ARm@300, ARl@300 |
Or from the CLI (requires pip install hotcoco[plot]):
coco eval --gt instances_val2017.json --dt bbox_results.json --report report.pdf
Quick start¶
import hotcoco
from hotcoco.plot import pr_curve, per_category_ap
gt = hotcoco.COCO("instances_val2017.json")
dt = gt.load_res("detections.json")
ev = hotcoco.COCOeval(gt, dt, "bbox")
ev.run()
fig, ax = pr_curve(ev, save_path="pr.png")
fig, ax = per_category_ap(ev.results(per_class=True), save_path="ap.png")
Available plots¶
Precision-recall curves¶
from hotcoco.plot import pr_curve
# IoU sweep (default) — one line per IoU threshold
fig, ax = pr_curve(ev)
# Single category
fig, ax = pr_curve(ev, cat_id=1)
# Top 10 categories at IoU=0.50
fig, ax = pr_curve(ev, iou_thr=0.50, top_n=10)
Per-category AP¶
from hotcoco.plot import per_category_ap
results = ev.results(per_class=True)
fig, ax = per_category_ap(results)
Shows horizontal bars sorted by AP with a mean AP reference line. When there are many categories, the top 20 and bottom 5 are shown with a visual break.
Confusion matrix¶
from hotcoco.plot import confusion_matrix
fig, ax = confusion_matrix(ev.confusion_matrix())
For datasets with many categories (>30), the matrix auto-filters to the 25 most confused categories. You can also aggregate by supercategory:
# Build supercategory groups from the dataset
cats = gt.load_cats(gt.get_cat_ids())
groups = {}
for c in cats:
groups.setdefault(c["supercategory"], []).append(c["name"])
fig, ax = confusion_matrix(ev.confusion_matrix(), group_by="supercategory", cat_groups=groups)
Top confusions¶
from hotcoco.plot import top_confusions
fig, ax = top_confusions(ev.confusion_matrix())
A bar chart of the most common misclassifications — more readable than a full heatmap when you have many categories.
TIDE error breakdown¶
from hotcoco.plot import tide_errors
fig, ax = tide_errors(ev.tide_errors())
Shows the six TIDE error types (Cls, Loc, Both, Dupe, Bkg, Miss) as horizontal bars with their delta-AP values.
Model comparison¶
from hotcoco import compare
from hotcoco.plot import comparison_bar, category_deltas
result = compare(ev_a, ev_b, n_bootstrap=1000)
fig, ax = comparison_bar(result) # grouped bar chart of all metrics
fig, ax = category_deltas(result, top_k=10) # per-category AP delta bars
comparison_bar shows Model A vs Model B side by side for each metric, with
bootstrap CI error bars when available. category_deltas shows per-category
AP deltas sorted by magnitude — green for improvements, red for regressions.
Themes¶
Every plot function accepts a theme argument:
| Theme | Description |
|---|---|
"cold-brew" |
Default. Warm off-white background, 10-color infographic palette. |
"warm-slate" |
Warm off-white background, terracotta + slate palette. |
"scientific-blue" |
Cool/academic. Blue-grey background, navy + red anchor colors. |
"ember" |
Warm/editorial. Parchment background, rust + copper + amber palette. |
fig, ax = pr_curve(ev, theme="scientific-blue")
fig, ax = per_category_ap(results, theme="ember")
Add paper_mode=True to force white backgrounds — useful when embedding in LaTeX or PowerPoint:
fig, ax = pr_curve(ev, theme="scientific-blue", paper_mode=True, save_path="pr.pdf")
To apply a theme to your own matplotlib code, use the style() context manager:
from hotcoco.plot import style
import matplotlib.pyplot as plt
with style(theme="cold-brew", paper_mode=True):
fig, ax = plt.subplots()
ax.plot(recall, precision)
fig.savefig("custom.pdf")
To use a completely different style (seaborn, corporate rcParams, etc.), simply don't call
hotcoco plot functions inside a style() context — the default matplotlib style applies:
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_theme()
fig, ax = plt.subplots()
# your own plotting code here
Composing plots¶
Pass an existing ax to draw on a subplot:
import matplotlib.pyplot as plt
from hotcoco.plot import pr_curve, per_category_ap
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
pr_curve(ev, ax=ax1)
per_category_ap(ev.results(per_class=True), ax=ax2)
fig.savefig("dashboard.png", dpi=150)