fix: imshow_origin "lower" mirrors the raster but not the vector overlays` #14
Unanswered
ClarkGuilty
asked this question in
Bugs & Errors
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
imshow_origin: lowermirrors the image raster but not the vector overlaysTarget repository: PyAutoArray
(the defect is in
autoarray/plot/array.py; it surfaces through everyPyAutoLens/PyAutoGalaxy plot that draws overlays).
Searched existing issues: yes.
imshow_originmatches only two closed pullrequests in PyAutoArray — #247
("Visualization final: config origin, fits API, output mode"), which appears to
be where the config lever was introduced, and
#510. No open issue covers
this. Nothing in PyAutoLens.
Summary
visualize/general.yaml -> general -> imshow_originis presented as a supportedchoice between
"upper"and"lower", and_conf_imshow_originvalidates it assuch. Setting it to
"lower"mirrors the image raster but leaves every vectoroverlay — critical curves, caustics, mask edge, border, grid, mesh grid,
positions, the origin marker and quiver vectors — in unmirrored data
coordinates.
The figure still looks plausible, so the failure is silent. In lens modelling the
visible symptom is critical curves and caustics no longer tracing the arcs they
belong to.
Expected behaviour
An overlay drawn at a given
(y, x)lands on the image feature at that(y, x),for any accepted value of
imshow_origin.Actual behaviour
Under
imshow_origin: "lower"the overlay is reflected about the horizontalmidline of the extent relative to the raster. In the example below a marker
placed at the coordinates of a bright block renders 2.5" away from it.
There is no traceback: nothing raises, nothing warns, and the figure is
produced normally. That silence is the main reason this is worth fixing.
Minimal reproducible example
Self-contained — no data files and no lens model. A bright block is placed
off-centre in
y, and apositionsmarker is placed at that block's owncoordinates. The marker must land on the block.
Result. In
mre_upper.pngthe black marker sits on the red block, aty = +1.25". Inmre_lower.pngthe block has moved toy = -1.25"while themarker stayed at
y = +1.25". Same forlines=(critical curves and causticstravel through the same code path).
Root cause
In
plot_array(autoarray/plot/array.py) the raster honoursorigin:while the overlays are drawn straight in data coordinates and never consult it:
imshowwith an explicitextentmaps row 0 toymaxunderorigin="upper"and to
yminunderorigin="lower". PyAutoArray's own convention gives row 0the largest
y—Grid2D.uniform(shape_native=(100, 100), pixel_scales=0.05)reports
y = +2.475at row 0 — so"upper"is the only setting that renders anarray consistently with the coordinate system its overlays live in.
_apply_contoursinautoarray/plot/utils.pyalready handles this correctly:No equivalent adjustment exists for the
ax.plot/ax.scatter/ax.quiveroverlays, which is what makes this look like an oversight rather than a design
decision.
Suggested resolution
Either would close it:
_apply_contoursalready is: reflectoverlay
yabout the extent midpoint whenorigin == "lower".native
row 0 == ymaxorientation, have_conf_imshow_originraise on"lower". It already raisesValueErrorfor valuesimshowitself wouldreject, so this would fit the existing contract and fail loudly.
Option 1 seems the more useful outcome, because users of FITS imaging reasonably
want north-up display:
ndarray_via_hdu_from(PyAutoNerves) does a barehdu.data.astype("float")with no flip, so array row 0 is the first FITS row,which for a standard WCS (
CD2_2 > 0) is the southern edge.One caveat worth documenting alongside the config key either way:
imshow_originonly changes presentation. It does not change the internal
yconvention, sounder
"lower"the displayed axis and the reported model parameters disagree insign on
y. Achieving north-up display with matching parameter signs requiresflipping the data at load time instead — a different operation, and one that
flips the sign of every y-odd model parameter.
Proposed regression test
Origin-agnostic: it reads the position the marker was actually drawn at, maps
that through the image's own extent and origin, and asserts the image is bright
there. It therefore keeps passing under a fix that mirrors the overlays, rather
than encoding today's behaviour.
Observed on 2026.8.29.1:
Impact
Silent and easy to miss. Images look correct on their own; circular overlays such
as a typical mask edge look unchanged; only asymmetric overlays reveal it. A user
can reach a wrong conclusion about where a feature lies on the sky before
noticing. Encountered while modelling a Euclid strong-lens candidate: the
critical curve had visibly slid off the lensed arc in the fit subplot.
Environment
AI assistance
This report was drafted with AI assistance, per the PyAutoLabs
AI policy.
How the claims were checked, rather than merely generated:
output PNGs were inspected. The
"upper"marker lands on the block; the"lower"marker is 2.5" away. It is not a hypothesised reproduction.row 0 == ymaxconvention was confirmed by evaluating a light profile at aknown centre and locating its peak by array index (
centre=(y=+1.0, x=0.0)ona 100x100, 0.05"/pix grid peaks at row 30), not inferred from documentation.
ndarray_via_hdu_fromwas confirmed by reading theinstalled source.
estimated. The surrounding code is quoted so they remain locatable if they
have since moved. (
originalso reachesimshowat lines 184 and 212, theRGB and
array_overlaybranches.)"upper"andfails under
"lower"on this version.All reactions