|
4 | 4 | import os
|
5 | 5 | import warnings
|
6 | 6 | from typing import Tuple, List, Union
|
| 7 | +from copy import deepcopy |
7 | 8 |
|
8 | 9 | import numpy as np
|
9 | 10 | import pandas as pd
|
|
15 | 16 | from matplotlib import pyplot as plt
|
16 | 17 | from matplotlib.axes import Axes
|
17 | 18 | from matplotlib.patches import Circle
|
18 |
| -from regions import read_ds9, PixelRegion |
| 19 | +from regions import read_ds9, PixelRegion, SkyRegion |
19 | 20 | from scipy.cluster.hierarchy import fclusterdata
|
20 | 21 | from scipy.signal import fftconvolve
|
21 | 22 |
|
@@ -76,7 +77,7 @@ def __init__(self, path: str, obs_id: str, instrument: str, stdout_str: str, std
|
76 | 77 |
|
77 | 78 | # This checks whether a region file has been passed, and if it has then processes it
|
78 | 79 | 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) |
80 | 81 | self._reg_file_path = reg_file_path
|
81 | 82 | elif reg_file_path != '' and not os.path.exists(reg_file_path):
|
82 | 83 | warnings.warn("That region file path does not exist")
|
@@ -201,21 +202,38 @@ def _read_wcs_on_demand(self):
|
201 | 202 | raise FailedProductError("SAS has generated this image without a WCS capable of "
|
202 | 203 | "going from pixels to RA-DEC.")
|
203 | 204 |
|
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]: |
205 | 207 | """
|
206 | 208 | This internal function just takes the path to a region file and processes it into a form that
|
207 | 209 | this object requires for viewing.
|
208 | 210 |
|
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. |
210 | 214 | :return: A list of pixel regions.
|
211 | 215 | :rtype: List[PixelRegion]
|
212 | 216 | """
|
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 |
214 | 231 | final_regs = []
|
215 | 232 | for reg in ds9_regs:
|
216 | 233 | if isinstance(reg, PixelRegion):
|
217 | 234 | final_regs.append(reg)
|
218 | 235 | else:
|
| 236 | + # Regions in sky coordinates need to be in pixels for overlaying on the image |
219 | 237 | final_regs.append(reg.to_pixel(self._wcs_radec))
|
220 | 238 |
|
221 | 239 | return final_regs
|
@@ -413,20 +431,30 @@ def regions(self) -> List[PixelRegion]:
|
413 | 431 | return self._regions
|
414 | 432 |
|
415 | 433 | @regions.setter
|
416 |
| - def regions(self, new_path: str): |
| 434 | + def regions(self, new_reg: Union[str, List[Union[SkyRegion, PixelRegion]]]): |
417 | 435 | """
|
418 | 436 | A setter for regions associated with this object, a region file path is passed, then that file
|
419 | 437 | is processed into the required format.
|
420 | 438 |
|
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. |
422 | 440 | """
|
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 == '': |
427 | 449 | pass
|
428 |
| - else: |
| 450 | + elif isinstance(new_reg, str): |
429 | 451 | 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") |
430 | 458 |
|
431 | 459 | @property
|
432 | 460 | def shape(self) -> Tuple[int, int]:
|
|
0 commit comments