Skip to content

PERF: 3d draw speedups#30994

Draft
scottshambaugh wants to merge 9 commits intomatplotlib:mainfrom
scottshambaugh:3d_draw_speed
Draft

PERF: 3d draw speedups#30994
scottshambaugh wants to merge 9 commits intomatplotlib:mainfrom
scottshambaugh:3d_draw_speed

Conversation

@scottshambaugh
Copy link
Contributor

@scottshambaugh scottshambaugh commented Jan 19, 2026

PR summary

A collection of speedups for 3d plotting, from playing around with the py-spy profiler today.

Waiting on #30980 as a dependency. Diff to that is here:
https://github.com/matplotlib/matplotlib/compare/4ab0014840c3e86b3ca820dba7531857cb168ed6..scottshambaugh:3d_draw_speed

I measure a 40% speedup in our non-agg-rendering code from these changes, which results in a 20% speedup in total runtime for my test script.

Summary of changes:

  • Prefer filling arrays with nans directly, instead of masked arrays that later get filled
  • Move _get_coord_info from axis3d to axes3d, since there's nothing axis-specific in it
  • Cache axes3d calculations that are used multiple times per draw by each axis: scaled_limits, bounds, transformed_cube, and coord_info.
  • Call axis._update_ticks() once per axis at start of draw, instead of multiple times in methods
  • Batch the axis tick 3d projections rather than calling once per tick

Before:
image

After (less time spent in things that aren't draw or draw_text:
image

Test script:

import time
import numpy as np
import matplotlib.pyplot as plt

print("Starting...")

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

x = y = np.linspace(-1, 1, 1000)
X, Y = np.meshgrid(x, y)
Z = X ** 2 + Y ** 2

print("Timing...")

start_time = time.perf_counter()
ax.plot_wireframe(X, Y, Z, axlim_clip=False)
ax.set_xlim(0, 1)
ax.set_xscale('symlog')
ax.set_yscale('symlog')
for i in range(100):
    ax.view_init(elev=i, azim=i)
    fig.canvas.draw()
end_time = time.perf_counter()

plt.close()

print(f"Time taken: {end_time - start_time:.4f} seconds")

PR checklist

@github-actions github-actions bot added the Documentation: examples files in galleries/examples label Jan 19, 2026
@scottshambaugh scottshambaugh removed the Documentation: examples files in galleries/examples label Jan 19, 2026
@github-actions github-actions bot added the Documentation: examples files in galleries/examples label Jan 19, 2026
@scottshambaugh scottshambaugh removed the Documentation: examples files in galleries/examples label Jan 19, 2026
@github-actions github-actions bot added the Documentation: examples files in galleries/examples label Jan 19, 2026
@scottshambaugh scottshambaugh changed the title [PERF] 3d draw speedups PERF: 3d draw speedups Jan 19, 2026
@scottshambaugh scottshambaugh force-pushed the 3d_draw_speed branch 3 times, most recently from e067442 to 54fdb74 Compare January 21, 2026 22:35
@scottshambaugh
Copy link
Contributor Author

Note to self: Update to use and match cache pattern in #31012 once that hits

@scottshambaugh
Copy link
Contributor Author

scottshambaugh commented Feb 2, 2026

TODO: art3d._zalpha speedup/caching, based on this script:

import numpy as np
import matplotlib.pyplot as plt


def main():
    rng = np.random.default_rng(42)

    fig = plt.figure()
    ax = fig.add_subplot(projection='3d')

    for _ in range(200):
        x = rng.random(25)
        y = rng.random(25)
        z = rng.random(25)
        ax.scatter(x, y, z, s=20)

    for _ in range(20):
        fig.canvas.draw()

    plt.close(fig)

@scottshambaugh
Copy link
Contributor Author

Waiting on #31012 as a dependency

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant