Skip to content

Commit 100c243

Browse files
authored
Merge pull request #359 from nrao/358-miscellaneous-bugs
358 miscellaneous bugs
2 parents 56a0d58 + f41ac88 commit 100c243

File tree

6 files changed

+95
-17
lines changed

6 files changed

+95
-17
lines changed

src/astrohack/core/extract_pointing.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def extract_pointing_chunk(pnt_params: dict, output_mds: AstrohackPointFile):
179179
tb.close()
180180
table_obj.close()
181181

182-
_evaluate_time_samping(direction_time, ant_name)
182+
_evaluate_time_sampling(direction_time, ant_name)
183183

184184
pnt_xds = xr.Dataset()
185185
coords = {"time": direction_time}
@@ -379,17 +379,22 @@ def _extract_scan_time_dict_jit(time, scan_ids, state_ids, ddi_ids, mapping_stat
379379
return scan_time_dict
380380

381381

382-
def _evaluate_time_samping(
383-
time_sampling, data_label, threshold=0.01, expected_interval=0.1
382+
def _evaluate_time_sampling(
383+
time_sampling, data_label, threshold=0.01, expected_interval=None
384384
):
385+
intervals = np.diff(time_sampling)
386+
unq_intervals, counts = np.unique(intervals, return_counts=True)
387+
if expected_interval is None:
388+
i_max_count = np.argmax(counts)
389+
expected_interval = unq_intervals[i_max_count]
390+
385391
bin_sz = expected_interval / 4
386392
time_bin_edge = np.arange(-bin_sz / 2, 2.5 * expected_interval, bin_sz)
387393
time_bin_axis = time_bin_edge[:-1] + bin_sz / 2
388394
i_mid = int(np.argmin(np.abs(time_bin_axis - expected_interval)))
389395

390-
intervals = np.diff(time_sampling)
391396
hist, edges = np.histogram(intervals, bins=time_bin_edge)
392-
n_total = np.sum(hist)
397+
n_total = np.nansum(hist)
393398
outlier_fraction = 1 - hist[i_mid] / n_total
394399

395400
if outlier_fraction > threshold:

src/astrohack/core/image_comparison_tool.py

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ def _init_as_fits(self, fits_filename, telescope_name, istokes=0, ichan=0):
127127
"""
128128
self.filename = fits_filename
129129
self.telescope_name = telescope_name
130-
self.rootname = ".".join(fits_filename.split(".")[:-1]) + "."
130+
fits_real_filename = fits_filename.split("/")[-1]
131+
self.rootname = ".".join(fits_real_filename.split(".")[:-1]) + "."
131132
self.header, self.data = read_fits(self.filename, header_as_dict=True)
132133
stokes_iaxis = get_stokes_axis_iaxis(self.header)
133134

@@ -152,12 +153,16 @@ def _init_as_fits(self, fits_filename, telescope_name, istokes=0, ichan=0):
152153
self.y_axis, _, self.y_unit = get_axis_from_fits_header(
153154
self.header, 2, pixel_offset=False
154155
)
156+
offset_scale = 1.5
157+
x_offset = offset_scale * np.unique(np.diff(self.x_axis))[0]
158+
y_offset = offset_scale * np.unique(np.diff(self.y_axis))[0]
159+
self.x_axis = np.flip(self.x_axis + x_offset)
160+
self.y_axis = np.flip(self.y_axis + y_offset)
155161
self.x_unit = "m"
156162
self.y_unit = "m"
157163
elif "Astrohack" in self.header["ORIGIN"]:
158164
self.x_axis, _, self.x_unit = get_axis_from_fits_header(self.header, 1)
159165
self.y_axis, _, self.y_unit = get_axis_from_fits_header(self.header, 2)
160-
self.data = np.fliplr(self.data)
161166
else:
162167
raise NotImplementedError(f'Unrecognized origin:\n{self.header["origin"]}')
163168
self._create_base_mask()
@@ -208,11 +213,13 @@ def resample(self, ref_image):
208213
x_mesh_dest, y_mesh_dest = np.meshgrid(
209214
ref_image.x_axis, ref_image.y_axis, indexing="ij"
210215
)
216+
raveled_data = self.data.ravel()
217+
valid_data = np.isfinite(raveled_data)
211218
resamp = griddata(
212-
(x_mesh_orig.ravel(), y_mesh_orig.ravel()),
213-
self.data.ravel(),
219+
(x_mesh_orig.ravel()[valid_data], y_mesh_orig.ravel()[valid_data]),
220+
raveled_data[valid_data],
214221
(x_mesh_dest.ravel(), y_mesh_dest.ravel()),
215-
method="linear",
222+
method="nearest",
216223
)
217224
size = ref_image.x_axis.shape[0], ref_image.y_axis.shape[0]
218225
self.x_axis = ref_image.x_axis
@@ -592,14 +599,24 @@ def export_to_fits(self, destination):
592599
reorder_axis=False,
593600
)
594601

595-
def scatter_plot(self, destination, ref_image, dpi=300, display=False):
602+
def scatter_plot(
603+
self,
604+
destination,
605+
ref_image,
606+
dpi=300,
607+
display=False,
608+
max_radius=None,
609+
min_radius=None,
610+
):
596611
"""
597612
Produce a scatter plot of self.data agains ref_image.data
598613
Args:
599614
destination: Location to store scatter plot
600615
ref_image: Reference FITSImage object
601616
dpi: png resolution on disk
602617
display: Show interactive view of plot
618+
max_radius: Maximum radius for scatter plot comparison as the outer panels can be crappy.
619+
min_radius: Minimum radius for scatter plot comparison as the innermost panels can be crappy.
603620
604621
Returns:
605622
None
@@ -610,10 +627,23 @@ def scatter_plot(self, destination, ref_image, dpi=300, display=False):
610627

611628
fig, ax = plt.subplots(1, 1, figsize=[10, 8])
612629

630+
x_mesh_orig, y_mesh_orig = np.meshgrid(self.x_axis, self.y_axis, indexing="ij")
631+
radius = np.sqrt(x_mesh_orig**2 + y_mesh_orig**2)
632+
633+
telescope = get_proper_telescope(self.telescope_name)
634+
if min_radius is None:
635+
min_radius = telescope.inner_radial_limit
636+
if max_radius is None:
637+
max_radius = telescope.outer_radial_limit - 1.0
613638
scatter_mask = np.isfinite(ref_image.data)
614639
scatter_mask = np.where(np.isfinite(self.data), scatter_mask, False)
640+
scatter_mask = np.where(radius < max_radius, scatter_mask, False)
641+
scatter_mask = np.where(radius > min_radius, scatter_mask, False)
642+
615643
ydata = self.data[scatter_mask]
616644
xdata = ref_image.data[scatter_mask]
645+
pl_max = np.max((np.max(xdata), np.max(ydata)))
646+
pl_min = np.min((np.min(xdata), np.min(ydata)))
617647

618648
scatter_plot(
619649
ax,
@@ -622,6 +652,12 @@ def scatter_plot(self, destination, ref_image, dpi=300, display=False):
622652
ydata,
623653
f"{self.filename} [{self.unit}]",
624654
add_regression=True,
655+
regression_method="siegelslopes",
656+
add_regression_reference=True,
657+
regression_reference_label="Perfect agreement",
658+
xlim=(pl_min, pl_max),
659+
ylim=[pl_min, pl_max],
660+
force_equal_aspect=True,
625661
)
626662
close_figure(
627663
fig,
@@ -641,7 +677,6 @@ def image_comparison_chunk(compare_params):
641677
Returns:
642678
A DataTree containing the Image and its reference Image.
643679
"""
644-
645680
image = FITSImage.from_fits_file(
646681
compare_params["this_image"], compare_params["telescope_name"]
647682
)
@@ -698,8 +733,8 @@ def image_comparison_chunk(compare_params):
698733
if compare_params["plot_scatter"]:
699734
image.scatter_plot(destination, ref_image, dpi=dpi, display=display)
700735

701-
img_node = xr.DataTree(name=image.filename, dataset=image.export_as_xds())
702-
ref_node = xr.DataTree(name=ref_image.filename, dataset=ref_image.export_as_xds())
736+
img_node = xr.DataTree(name=image.rootname, dataset=image.export_as_xds())
737+
ref_node = xr.DataTree(name=ref_image.rootname, dataset=ref_image.export_as_xds())
703738
tree_node = xr.DataTree(
704739
name=image.rootname[:-1], children={"Reference": ref_node, "Image": img_node}
705740
)

src/astrohack/extract_holog.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pathlib
2+
from copy import deepcopy
23

34
import toolviper.utils.parameter
45
import toolviper.utils.logger as logger
@@ -187,6 +188,9 @@ def extract_holog(
187188
}
188189
189190
"""
191+
# This copy here ensures that the user space holog_obs_dict given to extract_holog is not modified during execution
192+
if holog_obs_dict is not None:
193+
holog_obs_dict = deepcopy(holog_obs_dict)
190194

191195
# Doing this here allows it to get captured by locals()
192196
holog_name = get_default_file_name(ms_name, ".holog.zarr", holog_name)

src/astrohack/image_comparison_tool.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def rms_table_from_zarr_datatree(
201201
raise FileNotFoundError
202202

203203
xdt = xr.open_datatree(input_params["zarr_data_tree"])
204-
if xdt.attrs["origin"] != "compare_fits_images":
204+
if xdt.attrs["origin_info"]["creator_function"] != "compare_fits_images":
205205
logger.error("Data tree file was not created by astrohack.compare_fits_images")
206206
raise ValueError
207207

src/astrohack/utils/text.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ def get_default_file_name(
132132
else:
133133
output_filename = user_filename
134134

135+
if output_filename[-1] == "/":
136+
output_filename = output_filename[:-1]
137+
135138
logger.info(f"Creating output file name: {output_filename}")
136139
return output_filename
137140

src/astrohack/visualization/plot_tools.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import matplotlib.image
22
import numpy as np
3-
from scipy.stats import linregress
3+
from scipy.stats import linregress, theilslopes, siegelslopes
44

55
from matplotlib import pyplot as plt
66
from matplotlib.patches import Rectangle
@@ -251,6 +251,12 @@ def scatter_plot(
251251
add_regression=False,
252252
regression_linestyle="-",
253253
regression_color="black",
254+
regression_method="linregress",
255+
add_regression_reference=False,
256+
regression_reference=(1.0, 0.0),
257+
regression_reference_color="orange",
258+
regression_reference_label="Regression refrence",
259+
force_equal_aspect=False,
254260
add_legend=True,
255261
legend_location="best",
256262
):
@@ -287,6 +293,12 @@ def scatter_plot(
287293
add_regression: Add a linear regression between X and y data
288294
regression_linestyle: Line style for the regression plot
289295
regression_color: Color for the regression plot
296+
regression_method: Which scipy function to use for the linear regression: linregress, theilslopes or siegelslopes
297+
add_regression_reference: Add reference for the expected regression result
298+
regression_reference: 2 value array/tuple/list with a slope and intercept for reference
299+
regression_reference_color: Color for reference regression
300+
regression_reference_label: Label for reference regression
301+
force_equal_aspect: Force equal aspect on plot box
290302
add_legend: add legend to the plot
291303
legend_location: Location of the legend in the plot
292304
"""
@@ -325,7 +337,14 @@ def scatter_plot(
325337
)
326338

327339
if add_regression:
328-
slope, intercept, _, _, _ = linregress(xdata, ydata)
340+
if regression_method == "linregress":
341+
slope, intercept, _, _, _ = linregress(xdata, ydata)
342+
elif regression_method == "theilslopes":
343+
slope, intercept, _, _ = theilslopes(ydata, xdata)
344+
elif regression_method == "siegelslopes":
345+
slope, intercept = siegelslopes(ydata, xdata)
346+
else:
347+
raise RuntimeError(f"Unknown linear regression method: {regression_method}")
329348
regression_label = f"y = {slope:.4f}*x + {intercept:.4f}"
330349
yregress = slope * xdata + intercept
331350
ax.plot(
@@ -336,6 +355,15 @@ def scatter_plot(
336355
label=regression_label,
337356
lw=2,
338357
)
358+
if add_regression_reference:
359+
reg_ref = regression_reference[0] * xdata + regression_reference[1]
360+
ax.plot(
361+
xdata,
362+
reg_ref,
363+
ls=regression_linestyle,
364+
color=regression_reference_color,
365+
label=regression_reference_label,
366+
)
339367

340368
if model is not None:
341369
ax.plot(
@@ -373,6 +401,9 @@ def scatter_plot(
373401
ax_res.set_ylabel("Residuals")
374402
ax_res.set_xlabel(xlabel)
375403

404+
if force_equal_aspect:
405+
ax.set_aspect("equal", adjustable="box")
406+
376407
if title is not None:
377408
ax.set_title(title)
378409

0 commit comments

Comments
 (0)