Fix 3D axes to properly support non-linear scales (log, symlog, etc.)#30980
Fix 3D axes to properly support non-linear scales (log, symlog, etc.)#30980QuLogic merged 21 commits intomatplotlib:mainfrom
Conversation
de9840d to
4866c27
Compare
4ab0014 to
ed8aef6
Compare
greglucas
left a comment
There was a problem hiding this comment.
Looks like a really nice addition to me and makes sense for how to handle it.
There are a lot of images here for all the different plot styles, some with a lot of lines/ticks on them as well, do we need all artist types to cover these cases or could we reduce it down to just a few of the image tests which would cover all of the capability?
a13837f to
303a23f
Compare
I think we do need all artists exercised, but I consolidated them down into a single test image instead of 7. |
|
I think this is good to go, this is definitely a nice update to the 3d suite.
There are pros and cons to that because now it is a much larger image file and if one artist gets changed/updated you need to regenerate the entire image file. It might have actually been a similar size before just seven separate tests, and if so, I'd probably suggest we go with more individual images instead. I don't have a major preference either way. |
This fixes a long-standing issue where 3D plots ignored scale transforms. The methods set_xscale(), set_yscale(), set_zscale() existed but the transforms were never applied to data or coordinates. Key changes: - axes3d.py: Add _get_scaled_limits() to transform axis limits through scale transforms. Modify get_proj() to use scaled limits for world transformation. Override _update_transScale() to use identity transforms since 3D projection handles scales internally. Update autoscale_view() and _set_lim3d() to apply margins in transformed space. - art3d.py: Add _apply_scale_transforms() utility function. Update all do_3d_projection() methods to apply scale transforms before projection. - axis3d.py: Update _get_coord_info() to return scaled-space bounds. Modify _draw_ticks() to transform tick locations to scaled space. Update draw() and draw_grid() for proper coordinate handling. The fix ensures that: - Data coordinates are transformed through scale transforms before projection (e.g., log10 for log scale) - World transformation matrix maps scaled coordinates to unit cube - Axis ticks, labels, and grid lines position correctly - 2D display transforms remain linear (no double-transformation) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Baseline images regen Baseline images regen
5cfd346 to
6116e4d
Compare
|
Congratulations on fixing a 3-digit bug with a 5-digit PR. |
|
This has been my "white whale" bug for years, super happy to see it merged! Thanks both for reviewing. |

PR summary
This fixes a long-standing issue where 3D plots ignored scale transforms. The methods set_xscale(), set_yscale(), set_zscale() existed but the transforms were never applied to data or coordinates. There are quite a few new test images, but I think it's necessary to cover all the new behavior.
Closes #209 - a 15 year old bug and matplotlib's oldest open issue!
Out of scope here is the addition of
semilogx,semilogxy, etc. helper functions. If we want those it will need to be in a follow-on PR.Example usage:
Notes on generative AI usage
Details
This issue has been sitting in my to-solve backlog for a few years, and on a whim I decided to have Claude Code take a crack at it. I'm blown away by the results - the first commit in this PR which substantially solved the issue was completely written by Opus 4.5 over the course of only about 1 hour with minimal prompting. I left Claude authorship on the commit.My own domain expertise in the 3D section of the codebase definitely helped frame the question and set the direction, but I had basically no experience with the scale transform logic or where all the transform gaps in the 3D code might be. I had already spent a day on this back in 2023, and I expect this would have taken me several more days to learn the right sections of the codebase and implement on my own. In particular, needing to overwrite
_update_transScaleto an identity transform was a tricky insight that I think would have taken a long time to identify.The workflow I used, as a case study:
Initial claude code prompt in plan mode:
CC's plan:
I accepted the plan without edits, and CC started working in agent mode. After each iteration I would check the output figure, and send essentially the same message:
After the 4th or 5th iteration things looked like they were working as expected, and that result is what's in the first commit: b73427f
The follow-on commits took half a day, and were more much more manual to ensure correct behavior and test coverage.
PR checklist