fix(plot): a figure gives every row the same y gutter so the axes line up

This commit is contained in:
Martino Ferrari committed 2026-09-28 20:11:17 +02:00
1 parent 663b57c679
commit cae672bc99
6 files changed
+348 -5

No files matched your search

+16 -3
View File
@@ -836,7 +836,14 @@ const PlotLayout& Plot::layout() {
x_height = std::clamp(x_height, 0.0f, viewport_.h);
const f32 y_budget = (1.0f - kMinAxesShare) * viewport_.w;
const f32 x_budget = (1.0f - kMinAxesShare) * viewport_.h;
y_width = std::min(y_width, y_budget);
// The figure's common gutter, when one was imposed: a floor on `y_width + y_title_w`
// so every row's axes starts at the same x. It is served by the *label* strip -- the
// title column is one text line per titled axis and cannot be widened to fill a gutter
// -- and it is applied before the title column below, so the pair still fits the cap
// (the floor is clamped to the same budget) and the invariant `axes.w >= share` holds.
// `min_y_gutter_` is 0.0 unless a figure set it, so this is a no-op for a lone plot.
const f32 y_floor = std::min(min_y_gutter_, y_budget);
y_width = std::min(std::max(y_width, y_floor - y_title_w), y_budget);
x_height = std::min(x_height, x_budget);
const f32 y_title_width = std::min(y_title_w, y_budget - y_width);
const f32 x_title_height = std::min(x_title_h, x_budget - x_height);
@@ -865,8 +872,14 @@ const PlotLayout& Plot::layout() {
const f32 need_x =
x_labels ? std::min(std::clamp(text_->height() + 2.0f * pad, 0.0f, viewport_.h), x_budget)
: 0.0f;
if (need_y == y_width && need_x == x_height) break; // strips are a fixed point
y_width = need_y;
// What the strip *wants* is the label's own width or the figure's floor, whichever is
// greater -- the floor is a maximum over sources, settled by one `max` and not by
// asking the loop to grow the strip towards it pass by pass. Comparing the measured
// need alone would never agree once a floor sits above it, and the loop would run its
// cap out; comparing the want is what keeps it a fixed point here too.
const f32 want_y = std::min(std::max(need_y, y_floor - y_title_w), y_budget);
if (want_y == y_width && need_x == x_height) break; // strips are a fixed point
y_width = want_y;
x_height = need_x;
}