Skip to content

Commit 8c3d87b

Browse files
authored
Merge pull request #652 from DavidT3/refine/imageRegions
Changed the way that Image objects handle regions, closes issue #651
2 parents cde51c3 + b8a0c25 commit 8c3d87b

File tree

1 file changed

+40
-12
lines changed

1 file changed

+40
-12
lines changed

xga/products/phot.py

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import warnings
66
from typing import Tuple, List, Union
7+
from copy import deepcopy
78

89
import numpy as np
910
import pandas as pd
@@ -15,7 +16,7 @@
1516
from matplotlib import pyplot as plt
1617
from matplotlib.axes import Axes
1718
from matplotlib.patches import Circle
18-
from regions import read_ds9, PixelRegion
19+
from regions import read_ds9, PixelRegion, SkyRegion
1920
from scipy.cluster.hierarchy import fclusterdata
2021
from scipy.signal import fftconvolve
2122

@@ -76,7 +77,7 @@ def __init__(self, path: str, obs_id: str, instrument: str, stdout_str: str, std
7677

7778
# This checks whether a region file has been passed, and if it has then processes it
7879
if reg_file_path != '' and os.path.exists(reg_file_path):
79-
self._regions = self._process_regfile(reg_file_path)
80+
self._regions = self._process_regions(reg_file_path)
8081
self._reg_file_path = reg_file_path
8182
elif reg_file_path != '' and not os.path.exists(reg_file_path):
8283
warnings.warn("That region file path does not exist")
@@ -201,21 +202,38 @@ def _read_wcs_on_demand(self):
201202
raise FailedProductError("SAS has generated this image without a WCS capable of "
202203
"going from pixels to RA-DEC.")
203204

204-
def _process_regfile(self, path: str) -> List[PixelRegion]:
205+
def _process_regions(self, path: str = None, reg_list: List[Union[PixelRegion, SkyRegion]] = None) \
206+
-> List[PixelRegion]:
205207
"""
206208
This internal function just takes the path to a region file and processes it into a form that
207209
this object requires for viewing.
208210
209-
:param str path: The path to the region file to be processed
211+
:param str path: The path of a region file to be processed, can be None but only if the
212+
other argument is given.
213+
:param List[PixelRegion/SkyRegion] reg_list: A list of region objects to be processed, default is None.
210214
:return: A list of pixel regions.
211215
:rtype: List[PixelRegion]
212216
"""
213-
ds9_regs = read_ds9(path)
217+
# This method can deal with either an input of a region file path or of a list of region objects, but
218+
# firstly we need to check that at least one of the inputs isn't None
219+
if all([path is None, reg_list is None]):
220+
raise ValueError("Either a path or a list of region objects must be passed, you have passed neither")
221+
elif all([path is not None, reg_list is not None]):
222+
raise ValueError("You have passed both a path and a list of regions, pass one or the other.")
223+
224+
# The behaviour here depends on whether regions or a path have been passed
225+
if path is not None:
226+
ds9_regs = read_ds9(path)
227+
else:
228+
ds9_regs = deepcopy(reg_list)
229+
230+
# Checking what kind of regions there are, as that changes whether they need to be converted or not
214231
final_regs = []
215232
for reg in ds9_regs:
216233
if isinstance(reg, PixelRegion):
217234
final_regs.append(reg)
218235
else:
236+
# Regions in sky coordinates need to be in pixels for overlaying on the image
219237
final_regs.append(reg.to_pixel(self._wcs_radec))
220238

221239
return final_regs
@@ -413,20 +431,30 @@ def regions(self) -> List[PixelRegion]:
413431
return self._regions
414432

415433
@regions.setter
416-
def regions(self, new_path: str):
434+
def regions(self, new_reg: Union[str, List[Union[SkyRegion, PixelRegion]]]):
417435
"""
418436
A setter for regions associated with this object, a region file path is passed, then that file
419437
is processed into the required format.
420438
421-
:param str new_path: A new region file path.
439+
:param str/List[SkyRegion/PixelRegion] new_reg: A new region file path, or a list of region objects.
422440
"""
423-
if new_path != '' and os.path.exists(new_path):
424-
self._reg_file_path = new_path
425-
self._regions = self._process_regfile(new_path)
426-
elif new_path == '':
441+
if not isinstance(new_reg, (str, list)):
442+
raise TypeError("Please pass either a path to a region file or a list of "
443+
"SkyRegion/PixelRegion objects.")
444+
445+
if isinstance(new_reg, str) and new_reg != '' and os.path.exists(new_reg):
446+
self._reg_file_path = new_reg
447+
self._regions = self._process_regions(new_reg)
448+
elif isinstance(new_reg, str) and new_reg == '':
427449
pass
428-
else:
450+
elif isinstance(new_reg, str):
429451
warnings.warn("That region file path does not exist")
452+
elif isinstance(new_reg, List) and all([isinstance(r, (SkyRegion, PixelRegion)) for r in new_reg]):
453+
self._reg_file_path = ""
454+
self._regions = self._process_regions(reg_list=new_reg)
455+
else:
456+
raise ValueError("That value of new_reg is not valid, please pass either a path to a region file or "
457+
"a list of SkyRegion/PixelRegion objects")
430458

431459
@property
432460
def shape(self) -> Tuple[int, int]:

0 commit comments

Comments
 (0)