Let a plot be drawn in a unit of the caller's choosing - #201
Merged
Conversation
A system is free to describe its parts in whichever units suit them, and a detector measured in microns beside optics measured in millimeters is quite normal: ESIS is built that way, its sensor coming from `msfc-ccd` where a pixel pitch is naturally microns. Nothing reconciles those units on the way to matplotlib. `quantity_support` does it on a 2D axes, but not on a 3D one, where a surface given in microns is drawn a thousand times too large and the instrument around it collapses to a speck. Plotting the ESIS design in 3D gives a `zlim` of 121491, being microns read as millimeters, and the detectors land outside the frame entirely without anything saying so. `plot` now takes a `unit`, and converts every length to it before drawing: surfaces, both apertures, and the rays. Passing `u.mm` for that same system gives a `zlim` of 135.8. This mirrors `_write_to_dxf`, which has always taken a unit and converted, and leaves the default behaviour as it was. The alternative was to make the sensor describe itself in millimeters, which would fix ESIS and no one else, and would put the burden on how a part is specified rather than on how it is drawn. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #201 +/- ##
=======================================
Coverage 99.58% 99.58%
=======================================
Files 118 118
Lines 6933 6963 +30
=======================================
+ Hits 6904 6934 +30
Misses 29 29
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The aperture test reached the conversion of a surface but never the one applied to the rays, since nothing called `plot` on a whole system with a unit. The system is now drawn twice, in millimeters and in microns, and the magnitudes handed to matplotlib have to differ by exactly the factor between the two. That covers the rays, and it checks the thing worth checking: that everything drawn is converted, not merely some of it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A system is free to describe its parts in whichever units suit them, and a
detector measured in microns beside optics measured in millimeters is quite
normal. ESIS is built that way: its sensor comes from
msfc-ccd, where a pixelpitch is naturally microns, while the optics are millimeters.
Nothing reconciles those units on the way to matplotlib.
astropy.visualization.quantity_supportdoes it on a 2D axes, but not on a3D one, so a surface given in microns is drawn a thousand times too large:
That is microns being read as millimeters. The instrument collapses to a speck
and the detectors land outside the frame entirely, with nothing to say so. It
is a quiet failure: the geometry is correct, only the scale it is drawn at is
wrong, so a layout figure simply comes out missing its detectors.
The change
plotgains aunit, and converts every length to it before drawing: thesurfaces, both of their apertures, and the rays.
The default is unchanged, so nothing that works today moves.
This mirrors
_write_to_dxf, which sits directly belowplotin each of theseclasses and has always taken a
unitand converted. The plotting path was theone that did not.
Why not fix the sensor
The other option was to have the sensor describe itself in millimeters, as the
older
kgpymodel did, where the detector's clear width was computed as(width_pixels * shape_pixels).to(u.mm). That would fix ESIS and no one else,and it puts the burden on how a part is specified rather than on how it is
drawn. Specifying a pixel pitch in microns should stay comfortable.
Testing
test_plot_unitbuilds the same aperture twice, once in millimeters and oncein microns, and checks the magnitude handed to matplotlib. Without a unit the
two differ by a factor of a thousand; with one they agree; and asking for
microns converts rather than relabels. I checked it fails without the change.
The existing suites pass: 1641 in
apertures, 451 insystems/_sequential.