Summary
Add support for arranging multiple plots in a grid layout within a single Figure, matching matplotlib's plt.subplot() / fig.add_subplot() workflow.
Motivation
Performance comparisons routinely need side-by-side panels: throughput vs. latency, before vs. after, different input sizes. Without subplots, users must create separate PPM files and stitch them manually. This is a significant quality-of-life gap vs. matplotlib.
Proposed API
sepia::plot2d::Figure fig(1200, 800);
auto ax1 = fig.subplot(2, 2, 0); // 2 rows, 2 cols, panel index 0 (top-left)
auto ax2 = fig.subplot(2, 2, 1); // top-right
auto ax3 = fig.subplot(2, 2, 2); // bottom-left
auto ax4 = fig.subplot(2, 2, 3); // bottom-right
ax1.plot(x1, y1, n).label("throughput");
ax2.plot(x2, y2, n).label("latency");
// ...
fig.render();
fig.save_ppm("comparison.ppm");
Each Axes object returned by subplot() has the same API as Figure today (plot, scatter, bar, set_xlabel, etc.) but renders into a sub-region of the parent canvas.
Implementation Notes
subplot(rows, cols, idx) computes a BBox (pixel rect) for that cell and stores it
- Returns an
Axes handle that holds a reference to the parent Canvas and a CoordTransform scoped to that cell's pixel rect
- Each
Axes renders its own grid, axis, and legend within its BBox
- Layout: divide
Figure pixel area into a uniform grid, apply shared margins + inter-panel spacing parameter
Figure::render() iterates all Axes and calls axes.render_into(canvas)
- Shared X/Y axis labels:
subplot(2,1,0, share_x=true) suppresses X tick labels on the top panel
Acceptance Criteria
Summary
Add support for arranging multiple plots in a grid layout within a single
Figure, matching matplotlib'splt.subplot()/fig.add_subplot()workflow.Motivation
Performance comparisons routinely need side-by-side panels: throughput vs. latency, before vs. after, different input sizes. Without subplots, users must create separate PPM files and stitch them manually. This is a significant quality-of-life gap vs. matplotlib.
Proposed API
Each
Axesobject returned bysubplot()has the same API asFiguretoday (plot, scatter, bar, set_xlabel, etc.) but renders into a sub-region of the parent canvas.Implementation Notes
subplot(rows, cols, idx)computes aBBox(pixel rect) for that cell and stores itAxeshandle that holds a reference to the parentCanvasand aCoordTransformscoped to that cell's pixel rectAxesrenders its own grid, axis, and legend within itsBBoxFigurepixel area into a uniform grid, apply shared margins + inter-panel spacing parameterFigure::render()iterates allAxesand callsaxes.render_into(canvas)subplot(2,1,0, share_x=true)suppresses X tick labels on the top panelAcceptance Criteria
subplot(rows, cols, idx)allocates correct pixel regionsshare_x/share_ysuppresses redundant axis labelsexamples/subplots.cppwith a 2×2 performance comparison grid