Skip to content

Commit 6f79e21

Browse files
arapovclaude
andcommitted
feat: place date/link footnotes beside their corner bird boxes
"Generated: <date>" now sits just left of the bottom-right owl box, and the optional project link (chart.show_project_link) just right of the bottom-left eagle box — both small, grey, and bottom-aligned to their box, positioned from the box's measured extent via a shared _bird_box_axes_extent helper. Drop the https:// prefix from the link. Applies to radar and scatter charts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 3e669c9 commit 6f79e21

2 files changed

Lines changed: 58 additions & 26 deletions

File tree

‎bird_plot/plots/base.py‎

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -167,36 +167,56 @@ def add_axis_labels(ax: Axes) -> None:
167167
plt.text(x, y, text, transform=ax.transAxes, rotation=rotation, va="center", ha="center", fontstyle="italic")
168168

169169

170+
def _bird_box_axes_extent(ax: Axes, x_data: float, y_data: float):
171+
"""Axes-fraction (left, right, bottom, top) of the corner bird box anchored
172+
at the given data point, or None if it can't be located/measured."""
173+
box = next(
174+
(
175+
a
176+
for a in ax.get_children()
177+
if isinstance(a, AnnotationBbox) and abs(a.xy[0] - x_data) < 1e-6 and abs(a.xy[1] - y_data) < 1e-6
178+
),
179+
None,
180+
)
181+
if box is None:
182+
return None
183+
try:
184+
ext = box.get_window_extent(ax.figure.canvas.get_renderer())
185+
inv = ax.transAxes.inverted()
186+
left, bottom = inv.transform((ext.x0, ext.y0))
187+
right, top = inv.transform((ext.x1, ext.y1))
188+
return left, right, bottom, top
189+
except Exception:
190+
return None
191+
192+
170193
def add_date(ax: Axes, config: dict) -> None:
171-
"""Add generation date and project link to the plot.
194+
"""Add the generation date (and optional project link) as subtle footnotes.
172195
173-
Args:
174-
ax: The matplotlib axes object to draw on
175-
config: Dictionary containing configuration including:
176-
- 'chart.show_project_link': whether to show project link
196+
The date sits just left of the bottom-right (owl) box; the project link, if
197+
enabled via ``chart.show_project_link``, sits just right of the bottom-left
198+
(eagle) box. Both are small, grey, and bottom-aligned to their box.
177199
"""
178-
# Format current date as YYYY-MM-DD
179200
date_string = datetime.now().strftime("%Y-%m-%d")
180-
y_pos = -0.1
181-
link_fontsize = 5
182-
date_fontsize = 10
201+
fontsize = 7
202+
max_value = config["chart"]["max_value"]
203+
204+
# Date: just left of the owl (bottom-right) box, aligned to its bottom edge.
205+
owl = _bird_box_axes_extent(ax, max_value, -max_value)
206+
if owl is not None:
207+
x, y, ha, va = owl[0] - 0.015, owl[2], "right", "bottom"
208+
else:
209+
x, y, ha, va = 1.0, -0.1, "right", "top"
210+
ax.text(x, y, f"Generated: {date_string}", transform=ax.transAxes, ha=ha, va=va, fontsize=fontsize, color="0.5")
211+
212+
# Project link (optional): mirror of the date, right of the eagle (bottom-left) box.
183213
if config.get("chart", {}).get("show_project_link", True):
184-
# Add project link centered under the plot
214+
eagle = _bird_box_axes_extent(ax, -max_value, -max_value)
215+
if eagle is not None:
216+
lx, ly, lha, lva = eagle[1] + 0.015, eagle[2], "left", "bottom"
217+
else:
218+
lx, ly, lha, lva = 0.0, -0.1, "left", "top"
185219
ax.text(
186-
0.5,
187-
y_pos,
188-
"https://github.com/arapov/bird-plot",
189-
transform=ax.transAxes,
190-
ha="center",
191-
fontsize=link_fontsize,
192-
color="black",
220+
lx, ly, "github.com/arapov/bird-plot",
221+
transform=ax.transAxes, ha=lha, va=lva, fontsize=fontsize, color="0.5",
193222
)
194-
# Add date text to the plot
195-
ax.text(
196-
1, # X position: right edge
197-
y_pos, # Y position: 10% below bottom of axes
198-
f"Generated: {date_string}",
199-
transform=ax.transAxes, # Use axes coordinates (0-1 range)
200-
ha="right",
201-
fontsize=date_fontsize,
202-
)

‎tests/test_base_render.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@ def test_add_date_defaults_to_showing_link_when_key_missing(fig_ax, base_config)
102102
assert len(ax.texts) - before == 2
103103

104104

105+
def test_add_date_positions_beside_bird_boxes(fig_ax, base_config):
106+
# With the bird boxes present and the link enabled, the date is placed by the
107+
# owl box and the link by the eagle box (the box-found branches).
108+
_, ax = fig_ax
109+
base_config["chart"]["show_project_link"] = True
110+
add_bird_images(ax, base_config)
111+
add_date(ax, base_config)
112+
texts = " ".join(t.get_text() for t in ax.texts)
113+
assert "Generated:" in texts
114+
assert "github.com/arapov/bird-plot" in texts
115+
116+
105117
def _count_annotation_boxes(ax):
106118
return sum(isinstance(c, AnnotationBbox) for c in ax.get_children())
107119

0 commit comments

Comments
 (0)