Hi, I investigated a performance issue in mplot3d for Axes3D.plot_surface(...), focusing on regular surface meshes such as spheres.
I ran a small set of layered experiments:
- baseline redraw profiling
no_aggcomparisonno_projectioncomparisonPoly3DCollection.do_3d_projection()breakdownset_verts()timing before/after a prototype fast path
These experiments consistently suggest that the main bottleneck is not primarily:
- Agg rasterization
- projection math itself
- the
sorted(...)call itself
Instead, the dominant cost appears to be the rebuild pipeline inside the surface redraw path, especially:
- per-face rebuild work in
Poly3DCollection.do_3d_projection() - downstream polygon/path rebuild in
PolyCollection.set_verts()
For example, in one mesh=96 profiling run, Poly3DCollection.do_3d_projection() took about 380.22 ms, while proj_transform itself was only about 1.04 ms (0.27%). The dominant costs were the rebuild stages, especially sort_and_stack and set_verts.
I then built a small prototype specialized for regular quad surfaces:
- keep the existing projection step
- replace the per-face rebuild/sort packaging path with a batch-oriented C++ helper
- emit regular
ndarray[num_faces, 4, 2]vertex data for downstream use
This is not a full patch, only a focused prototype to validate the direction.
On my test cases, it reduced average redraw time substantially:
- mesh=12:
5.58 ms -> 2.32 ms(-58.4%) - mesh=24:
16.84 ms -> 4.32 ms(-74.3%) - mesh=48:
67.53 ms -> 12.00 ms(-82.2%) - mesh=96:
537.18 ms -> 187.87 ms(-65.0%)
It also reduced set_verts() time significantly:
- mesh=12:
1.32 ms -> 0.24 ms(-81.8%) - mesh=24:
4.81 ms -> 0.90 ms(-81.3%) - mesh=48:
21.92 ms -> 3.63 ms(-83.4%) - mesh=96:
176.40 ms -> 87.64 ms(-50.3%)
My current interpretation is:
- the main performance problem is the rebuild pipeline for many faces
- regular surface meshes may benefit from a specialized fast path
- making the intermediate geometry data more regular also helps downstream
set_verts()
I am not proposing that this prototype should be merged as-is.
What I want to ask is:
- Would a
plot_surface-specific fast path for regular surface meshes be considered in scope for Matplotlib? - If yes, would the project be open to an implementation that reduces Python-side per-face rebuild work, potentially with a compiled helper?
- If not, is there a preferred direction for improving this part of
mplot3d?
If helpful, I can also provide a more structured write-up of the profiling steps and prototype details.
Some results are here , I feel faster when I drag them!
origin:
origin:
I expect it would be even faster if C++ patches were added for other parameters as well!



