Skip to content

Commit 7955a7e

Browse files
authored
Merge pull request #547 from PyAutoLabs/feature/arcsec-after-decimal
feat: per-call arcsec_after_decimal override for arcsecond tick labels
2 parents 35aa681 + 3e2493b commit 7955a7e

5 files changed

Lines changed: 101 additions & 7 deletions

File tree

autoarray/plot/array.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def plot_array(
6161
cb_unit: Optional[str] = None,
6262
line_colors: Optional[List] = None,
6363
origin_imshow: Optional[str] = None,
64+
arcsec_after_decimal: Optional[bool] = None,
6465
# --- figure control (used only when ax is None) -----------------------------
6566
figsize: Optional[Tuple[int, int]] = None,
6667
output_path: Optional[str] = None,
@@ -126,6 +127,11 @@ def plot_array(
126127
When ``True`` a ``LogNorm`` is applied.
127128
origin_imshow
128129
Passed directly to ``imshow`` (``"upper"`` or ``"lower"``).
130+
arcsec_after_decimal
131+
Per-call override of the ``ticks.symbol_over_decimal`` config flag.
132+
When ``True`` the arcsecond tick labels place the ``″`` symbol over the
133+
decimal point (``3.″8``) instead of suffixing it (``3.8"``); when ``False``
134+
the suffix form is forced. ``None`` (the default) reads the config.
129135
figsize
130136
Figure size in inches.
131137
output_path
@@ -320,7 +326,7 @@ def plot_array(
320326
)
321327

322328
if extent is not None:
323-
apply_extent(ax, extent)
329+
apply_extent(ax, extent, symbol_over_decimal=arcsec_after_decimal)
324330

325331
# --- output ----------------------------------------------------------------
326332
if owns_figure:

autoarray/plot/grid.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def plot_grid(
3737
buffer: float = 0.1,
3838
extent: Optional[Tuple[float, float, float, float]] = None,
3939
force_symmetric_extent: bool = True,
40+
arcsec_after_decimal: Optional[bool] = None,
4041
# --- figure control (used only when ax is None) -----------------------------
4142
figsize: Optional[Tuple[int, int]] = None,
4243
output_path: Optional[str] = None,
@@ -77,6 +78,11 @@ def plot_grid(
7778
force_symmetric_extent
7879
When ``True`` (and *extent* is auto-computed) the limits are made
7980
symmetric about the origin so the plot is centred.
81+
arcsec_after_decimal
82+
Per-call override of the ``ticks.symbol_over_decimal`` config flag.
83+
When ``True`` the arcsecond tick labels place the ``″`` symbol over the
84+
decimal point (``3.″8``) instead of suffixing it (``3.8"``); when ``False``
85+
the suffix form is forced. ``None`` (the default) reads the config.
8086
figsize
8187
Figure size in inches ``(width, height)``.
8288
output_path
@@ -178,7 +184,7 @@ def plot_grid(
178184
y_abs = max(abs(extent[2]), abs(extent[3]))
179185
extent = [-x_abs, x_abs, -y_abs, y_abs]
180186

181-
apply_extent(ax, extent)
187+
apply_extent(ax, extent, symbol_over_decimal=arcsec_after_decimal)
182188

183189
# --- output ----------------------------------------------------------------
184190
if owns_figure:

autoarray/plot/inversion.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def plot_inversion_reconstruction(
3434
use_log10: bool = False,
3535
zoom_to_brightest: bool = True,
3636
zoom_extent_scale: float = 1.0,
37+
arcsec_after_decimal: Optional[bool] = None,
3738
# --- overlays ---------------------------------------------------------------
3839
lines: Optional[List[np.ndarray]] = None,
3940
line_colors: Optional[List] = None,
@@ -73,6 +74,11 @@ def plot_inversion_reconstruction(
7374
Apply ``LogNorm``.
7475
zoom_to_brightest
7576
Pass through to ``mapper.extent_from``.
77+
arcsec_after_decimal
78+
Per-call override of the ``ticks.symbol_over_decimal`` config flag.
79+
When ``True`` the arcsecond tick labels place the ``″`` symbol over the
80+
decimal point (``3.″8``) instead of suffixing it (``3.8"``); when ``False``
81+
the suffix form is forced. ``None`` (the default) reads the config.
7682
lines
7783
Line overlays (e.g. critical curves).
7884
grid
@@ -163,7 +169,7 @@ def plot_inversion_reconstruction(
163169
if grid is not None:
164170
ax.scatter(grid[:, 1], grid[:, 0], s=1, c="w", alpha=0.5)
165171

166-
apply_extent(ax, extent)
172+
apply_extent(ax, extent, symbol_over_decimal=arcsec_after_decimal)
167173

168174
apply_labels(
169175
ax,

autoarray/plot/utils.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,7 +1106,7 @@ def _round_ticks(values: np.ndarray, sig: int = 2) -> np.ndarray:
11061106
return rounded
11071107

11081108

1109-
def _arcsec_labels(ticks) -> List[str]:
1109+
def _arcsec_labels(ticks, symbol_over_decimal: Optional[bool] = None) -> List[str]:
11101110
"""Format tick values as arcsecond coordinate strings.
11111111
11121112
Whole-number tick sets render without a decimal point, so
@@ -1117,6 +1117,16 @@ def _arcsec_labels(ticks) -> List[str]:
11171117
decimal labels keep the suffix form ``3.8"``. When
11181118
``ticks.symbol_over_decimal`` is true, labels use the double-prime arcsecond
11191119
symbol and decimal labels place it over the decimal point, e.g. ``3.″8``.
1120+
1121+
Parameters
1122+
----------
1123+
ticks
1124+
The tick values to label.
1125+
symbol_over_decimal
1126+
Per-call override of the ``ticks.symbol_over_decimal`` config flag.
1127+
``True`` forces the symbol-over-decimal form and ``False`` forces the
1128+
suffix form, whatever the config says. ``None`` (the default) reads
1129+
the config, so callers that do not pass it behave exactly as before.
11201130
"""
11211131
minus_in_math = _conf_ticks_flag("minus_in_math", False)
11221132

@@ -1132,7 +1142,9 @@ def _fmt_minus(label: str) -> str:
11321142
label if "." in label else f"{float(v):.1f}"
11331143
for label, v in zip(labels, ticks)
11341144
]
1135-
if _conf_ticks_flag("symbol_over_decimal", False):
1145+
if symbol_over_decimal is None:
1146+
symbol_over_decimal = _conf_ticks_flag("symbol_over_decimal", False)
1147+
if symbol_over_decimal:
11361148
symbol_labels = []
11371149
for label in labels:
11381150
if "." in label:
@@ -1147,13 +1159,18 @@ def _fmt_minus(label: str) -> str:
11471159
def apply_extent(
11481160
ax,
11491161
extent: Tuple[float, float, float, float],
1162+
symbol_over_decimal: Optional[bool] = None,
11501163
) -> None:
11511164
"""
11521165
Apply axis limits and inward-pulled, rounded, arcsecond-labelled ticks to *ax*.
11531166
11541167
Tick count and inward factor are read from ``visualize/general.yaml``
11551168
(``ticks.number_of_ticks_2d`` and ``ticks.extent_factor_2d``), defaulting
11561169
to 3 ticks and factor 0.75.
1170+
1171+
``symbol_over_decimal`` is a per-call override of the
1172+
``ticks.symbol_over_decimal`` config flag, forwarded to
1173+
:func:`_arcsec_labels`; ``None`` (the default) reads the config.
11571174
"""
11581175
factor = _conf_ticks("extent_factor_2d", 0.75)
11591176
n = int(_conf_ticks("number_of_ticks_2d", 3))
@@ -1166,8 +1183,8 @@ def apply_extent(
11661183
yticks = _round_ticks(_inward_ticks(ymin, ymax, factor, n))
11671184
ax.set_xticks(xticks)
11681185
ax.set_yticks(yticks)
1169-
ax.set_xticklabels(_arcsec_labels(xticks))
1170-
ax.set_yticklabels(_arcsec_labels(yticks))
1186+
ax.set_xticklabels(_arcsec_labels(xticks, symbol_over_decimal=symbol_over_decimal))
1187+
ax.set_yticklabels(_arcsec_labels(yticks, symbol_over_decimal=symbol_over_decimal))
11711188

11721189
# The y-tick labels are rotated 90 degrees elsewhere; without an explicit
11731190
# centre alignment a rotated label anchors at its right edge and visually

test_autoarray/plot/test_utils.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,65 @@ def test_arcsec_labels_minus_in_math():
9191
ticks["minus_in_math"] = original_minus
9292

9393

94+
def test_arcsec_labels_symbol_over_decimal_argument_overrides_config():
95+
# The per-call argument alone switches the format on, with the config flag
96+
# left at its default (false) and `conf.instance` never mutated.
97+
assert _arcsec_labels([-2.1, -0.044, 2.0], symbol_over_decimal=True) == [
98+
"-2.″1",
99+
"-0.″044",
100+
"2.″0",
101+
]
102+
assert _arcsec_labels([3.8], symbol_over_decimal=True) == ["3.″8"]
103+
assert _arcsec_labels([-1.0, 0.0, 1.0], symbol_over_decimal=True) == [
104+
"-1″",
105+
"0″",
106+
"1″",
107+
]
108+
109+
110+
def test_arcsec_labels_symbol_over_decimal_argument_false_beats_config():
111+
# The override wins in both directions: an explicit False forces the suffix
112+
# form even when the config flag is on.
113+
ticks = conf.instance["visualize"]["general"]["ticks"]
114+
original = ticks.get("symbol_over_decimal", False)
115+
try:
116+
ticks["symbol_over_decimal"] = True
117+
118+
assert _arcsec_labels([-2.1, -0.044, 2.0], symbol_over_decimal=False) == [
119+
'-2.1"',
120+
'-0.044"',
121+
'2.0"',
122+
]
123+
assert _arcsec_labels([3.8], symbol_over_decimal=False) == ['3.8"']
124+
finally:
125+
ticks["symbol_over_decimal"] = original
126+
127+
128+
def test_arcsec_labels_symbol_over_decimal_none_reads_config():
129+
# None (the default) leaves the config in charge, so every existing caller
130+
# is unchanged.
131+
ticks = conf.instance["visualize"]["general"]["ticks"]
132+
original = ticks.get("symbol_over_decimal", False)
133+
try:
134+
ticks["symbol_over_decimal"] = True
135+
136+
assert _arcsec_labels([-2.1, -0.044, 2.0], symbol_over_decimal=None) == [
137+
"-2.″1",
138+
"-0.″044",
139+
"2.″0",
140+
]
141+
142+
ticks["symbol_over_decimal"] = False
143+
144+
assert _arcsec_labels([-2.1, -0.044, 2.0], symbol_over_decimal=None) == [
145+
'-2.1"',
146+
'-0.044"',
147+
'2.0"',
148+
]
149+
finally:
150+
ticks["symbol_over_decimal"] = original
151+
152+
94153
class TestNormFrom:
95154
"""The one colour-norm helper `plot_array`, `plot_inversion_reconstruction`
96155
and `autogalaxy.util.plot_utils.norm_from` all build their norms with.

0 commit comments

Comments
 (0)