visualize2d() and visualize3d() (matplotlib backend) only call plt.close() when both screenshot_as and blocking are true. In all other code paths, figures are never closed. On headless servers (Agg backend), plt.show() is a no-op that does not release figures, so they accumulate indefinitely.
Even in the safe path (save_preview uses blocking=True, screenshot_as=...), plt.close() without an explicit figure reference relies on pyplot's implicit "current figure" tracking, which is fragile across repeated calls.
Fix: use matplotlib's OO API (fig, ax = plt.subplots() / plt.close(fig)) instead of the pyplot state machine.
visualize2d()andvisualize3d()(matplotlib backend) only callplt.close()when bothscreenshot_asandblockingare true. In all other code paths, figures are never closed. On headless servers (Agg backend),plt.show()is a no-op that does not release figures, so they accumulate indefinitely.Even in the safe path (
save_previewusesblocking=True, screenshot_as=...),plt.close()without an explicit figure reference relies on pyplot's implicit "current figure" tracking, which is fragile across repeated calls.Fix: use matplotlib's OO API (
fig, ax = plt.subplots()/plt.close(fig)) instead of the pyplot state machine.