feat(plot): a figure can keep an empty band to the right of its data
`layout_.axes` reached the viewport's right edge, so the rightmost x tick label -- centred on its tick -- had half of itself outside the plot, and the newest sample's ink landed on the frame. `Plot::set_right_gutter()` reserves a band there, out of the same `1 - kMinAxesShare` allowance the label and title strips are served from, so it can no more squeeze `axes` below the half-viewport floor than they can. `Figure` sets one value on every row, the left gutter's reason: the rows' axes have to end on a common column as well as start on one. Nothing is drawn in the band, so unlike the strips it is a want and never a measurement: no measuring pass, and it cannot feed the layout's fixed point. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
58473db384
commit
bee318870f
5 files changed
+93
-1
No files matched your search
@@ -425,6 +425,52 @@ PLOT_TEST(figure_gutter_never_squeezes_the_axes_below_the_floor) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The other side of the same band. `axes` reached the viewport's right edge, which left
|
||||
/// the rightmost x tick label -- centred on it -- half outside the plot, so a figure can
|
||||
/// ask for an empty band there. One value for every row, like the left gutter, because
|
||||
/// the rows' axes have to end on a common column as well as start on one.
|
||||
PLOT_TEST(figure_rows_share_one_right_gutter) {
|
||||
plot::Figure figure = different_magnitude_figure();
|
||||
figure.layout();
|
||||
const plot::f32 flush = figure.plot(0u).layout().axes.right();
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(figure.right_gutter()), 0.0, 1e-12);
|
||||
// The default is the layout as it always was: nothing between the data and the frame.
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(flush), static_cast<plot::f64>(kW), 1e-4);
|
||||
|
||||
figure.set_right_gutter(30.0f);
|
||||
figure.layout();
|
||||
const plot::Rect first = figure.plot(0u).layout().axes;
|
||||
for (plot::u32 row = 0; row < 3u; ++row) {
|
||||
const plot::PlotLayout& rl = figure.plot(row).layout();
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(rl.right_gutter), 30.0, 1e-4);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(rl.axes.right()), static_cast<plot::f64>(kW) - 30.0,
|
||||
1e-4);
|
||||
// The band comes off the right alone: the left gutter the rows agreed on is untouched,
|
||||
// so a host can balance the two sides without the one moving when it sets the other.
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(rl.axes.x), static_cast<plot::f64>(first.x), 1e-4);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(rl.axes.w), static_cast<plot::f64>(first.w), 1e-4);
|
||||
// ... and the x strip follows the data area rather than the viewport, or the shared
|
||||
// axis would be labelled over a band that holds no data.
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(rl.x_label_area.w), static_cast<plot::f64>(rl.axes.w),
|
||||
1e-4);
|
||||
}
|
||||
// Clamped by the same cap as the strips: a band wider than the whole figure cannot
|
||||
// squeeze `axes` below the floor `Plot::layout()` guarantees.
|
||||
figure.set_right_gutter(10.0f * kW);
|
||||
figure.layout();
|
||||
for (plot::u32 row = 0; row < 3u; ++row) {
|
||||
const plot::Rect& axes = figure.plot(row).layout().axes;
|
||||
PLOT_CHECK(axes.w >= 0.5f * kW - 1e-3f);
|
||||
}
|
||||
// Negative means "none", like the gutter and the row gap, and the data area goes back
|
||||
// to the viewport's edge.
|
||||
figure.set_right_gutter(-5.0f);
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(figure.right_gutter()), 0.0, 1e-12);
|
||||
figure.layout();
|
||||
PLOT_CHECK_NEAR(static_cast<plot::f64>(figure.plot(0u).layout().axes.right()),
|
||||
static_cast<plot::f64>(flush), 1e-4);
|
||||
}
|
||||
|
||||
/// The degenerate neighbour: a figure of one row imposes exactly what that row
|
||||
/// measured, so it lays out as the plot would on its own -- the gutter cannot move a
|
||||
/// row that has no sibling to line up with.
|
||||
|
||||
Reference in new issue
Block a user