Render ranking exports and save the figure owning the supplied axes
This commit is contained in:
parent
4b156e1286
commit
85355bce11
2 changed files with 40 additions and 6 deletions
|
|
@ -1,9 +1,10 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional, TypeVar
|
from typing import Dict, List, Optional, TypeVar, cast
|
||||||
|
|
||||||
import matplotlib
|
import matplotlib
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from matplotlib.figure import Figure
|
||||||
from sklearn.metrics import average_precision_score, precision_recall_curve
|
from sklearn.metrics import average_precision_score, precision_recall_curve
|
||||||
|
|
||||||
from ..unique import unique
|
from ..unique import unique
|
||||||
|
|
@ -45,7 +46,8 @@ def evaluate_ranking(
|
||||||
|
|
||||||
assert 0 <= target_recall <= 1
|
assert 0 <= target_recall <= 1
|
||||||
|
|
||||||
if plot and axes is None:
|
render = plot or output_svg is not None
|
||||||
|
if render and axes is None:
|
||||||
fig = plt.figure(figsize=(10, 10))
|
fig = plt.figure(figsize=(10, 10))
|
||||||
fig.patch.set_facecolor("white")
|
fig.patch.set_facecolor("white")
|
||||||
ax = plt.axes()
|
ax = plt.axes()
|
||||||
|
|
@ -56,7 +58,7 @@ def evaluate_ranking(
|
||||||
str_classes = [str(c) for c in classes]
|
str_classes = [str(c) for c in classes]
|
||||||
|
|
||||||
with matplotlib.rc_context({"font.size": 20}):
|
with matplotlib.rc_context({"font.size": 20}):
|
||||||
if plot:
|
if render:
|
||||||
ax.set_xmargin(0)
|
ax.set_xmargin(0)
|
||||||
|
|
||||||
draw_f1_iso_lines(axes=ax)
|
draw_f1_iso_lines(axes=ax)
|
||||||
|
|
@ -87,14 +89,14 @@ def evaluate_ranking(
|
||||||
)
|
)
|
||||||
results[classes[i]] = precision_at_closest_recall
|
results[classes[i]] = precision_at_closest_recall
|
||||||
|
|
||||||
if plot:
|
if render:
|
||||||
ax.plot(
|
ax.plot(
|
||||||
recall,
|
recall,
|
||||||
precision,
|
precision,
|
||||||
label=f"{'|'.join(str_classes[:i + 1])} ↔ {'|'.join(str_classes[i+1:])} (P@{target_recall:.2f}={precision_at_closest_recall:.2f}, AP={average_precision:.2f})",
|
label=f"{'|'.join(str_classes[:i + 1])} ↔ {'|'.join(str_classes[i+1:])} (P@{target_recall:.2f}={precision_at_closest_recall:.2f}, AP={average_precision:.2f})",
|
||||||
)
|
)
|
||||||
|
|
||||||
if plot:
|
if render:
|
||||||
ax.legend(loc="upper right")
|
ax.legend(loc="upper right")
|
||||||
ax.axvline(x=target_recall, linestyle="--", color="#55c6bb", linewidth=2.0)
|
ax.axvline(x=target_recall, linestyle="--", color="#55c6bb", linewidth=2.0)
|
||||||
|
|
||||||
|
|
@ -112,6 +114,8 @@ def evaluate_ranking(
|
||||||
if axes is None:
|
if axes is None:
|
||||||
plt.show()
|
plt.show()
|
||||||
elif output_svg:
|
elif output_svg:
|
||||||
plt.savefig(output_svg, format="svg")
|
cast(Figure, ax.get_figure(root=True)).savefig(output_svg, format="svg")
|
||||||
|
if not plot and axes is None:
|
||||||
|
plt.close(ax.get_figure(root=True))
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import matplotlib
|
import matplotlib
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
matplotlib.use("Agg") # don't show a window for each test
|
matplotlib.use("Agg") # don't show a window for each test
|
||||||
|
|
@ -108,3 +109,32 @@ def test_save() -> None:
|
||||||
|
|
||||||
assert path.exists()
|
assert path.exists()
|
||||||
path.unlink()
|
path.unlink()
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_saves_the_supplied_axes_figure(tmp_path: Path) -> None:
|
||||||
|
intended, axes = plt.subplots()
|
||||||
|
unrelated, other = plt.subplots()
|
||||||
|
other.set_title("unrelated figure")
|
||||||
|
output = tmp_path / "ranking.svg"
|
||||||
|
try:
|
||||||
|
evaluate_ranking(
|
||||||
|
[0, 1],
|
||||||
|
[0.1, 0.9],
|
||||||
|
target_recall=1,
|
||||||
|
axes=axes,
|
||||||
|
output_svg=output,
|
||||||
|
title="intended ranking",
|
||||||
|
)
|
||||||
|
content = output.read_text()
|
||||||
|
assert "intended ranking" in content
|
||||||
|
assert "unrelated figure" not in content
|
||||||
|
finally:
|
||||||
|
plt.close(intended)
|
||||||
|
plt.close(unrelated)
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_without_display_still_renders(tmp_path: Path) -> None:
|
||||||
|
output = tmp_path / "ranking.svg"
|
||||||
|
evaluate_ranking([0, 1], [0.1, 0.9], target_recall=1, plot=False, output_svg=output)
|
||||||
|
assert "Precision" in output.read_text()
|
||||||
|
assert "Recall" in output.read_text()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue