27 from lsst.daf.butler.formatters.fileFormatter
import FileFormatter
32 """Class to support bright object masks 34 N.b. I/O is done by providing a readFits method which fools the butler. 38 schema = afwTable.SimpleTable.makeMinimalSchema()
39 schema.addField(
"type", str,
"type of region (e.g. box, circle)", size=10)
40 schema.addField(
"radius",
"Angle",
"radius of mask (if type == circle")
41 schema.addField(
"height",
"Angle",
"height of mask (if type == box)")
42 schema.addField(
"width",
"Angle",
"width of mask (if type == box)")
43 schema.addField(
"angle",
"Angle",
"rotation of mask (if type == box)")
44 schema.addField(
"mag", float,
"object's magnitude")
46 self.
_catalog = afwTable.SimpleCatalog(schema)
47 self.
_catalog.table.setMetadata(dafBase.PropertyList())
66 """FitsCatalogStorage facade for `read`. 68 This method is intended for use by the Gen2 Butler only. 73 Name of the file to read. 75 Provided for compatibility with the "FitsCatalogStorage" read API 76 defined in `lsst.daf.persistence`, and ignored here. 78 Provided for compatibility with the "FitsCatalogStorage" read API 79 defined in `lsst.daf.persistence`, and ignored here. 83 Having a `readFits` method makes the `ObjectCatalogMask` class 84 duck-type compatible with `lsst.afw.table` catalogs, to the extent 85 needed to support reading by the Gen2 Butler with no specialized code 86 in `lsst.daf.persistence`. The on-disk type should actually be an 87 ASCII ds9 region file, typically with a ".reg" suffix. 89 return cls.
read(fileName)
93 """Read a ds9 region file, returning a ObjectMaskCatalog object 95 The files should be structured as follows: 97 # Description of catalogue as a comment 98 # CATALOG: catalog-id-string 105 circle(RA, DEC, RADIUS) # ID: 1, mag: 12.34 106 box(RA, DEC, XSIZE, YSIZE, THETA) # ID: 2, mag: 23.45 109 The ", mag: XX.YY" is optional 111 The commented lines must be present, with the relevant fields such as 112 tract patch and filter filled in. The coordinate system must be listed 113 as above. Each patch is specified as a box or circle, with RA, DEC, 114 and dimensions specified in decimal degrees (with or without an 117 Only (axis-aligned) boxes and circles are currently supported as 121 log = Log.getLogger(
"ObjectMaskCatalog")
124 checkedWcsIsFk5 =
False 125 NaN = float(
"NaN")*afwGeom.degrees
128 with open(fileName)
as fd:
129 for lineNo, line
in enumerate(fd.readlines(), 1):
132 if re.search(
r"^\s*#", line):
141 mat = re.search(
r"^\s*#\s*([a-zA-Z][a-zA-Z0-9_]+)\s*:\s*(.*)", line)
143 key, value = mat.group(1).lower(), mat.group(2)
147 brightObjects.table.getMetadata().set(key, value)
149 line = re.sub(
r"^\s*#.*",
"", line)
153 if re.search(
r"^\s*wcs\s*;\s*fk5\s*$", line, re.IGNORECASE):
154 checkedWcsIsFk5 =
True 159 mat = re.search(
r"^\s*(box|circle)" 161 r"(\d+(?:\.\d*)?([d]*))" r"(?:\s+|\s*,\s*)" 162 r"([+-]?\d+(?:\.\d*)?)([d]*)" r"(?:\s+|\s*,\s*)" 163 r"([+-]?\d+(?:\.\d*)?)([d]*)" r"(?:\s+|\s*,\s*)?" 164 r"(?:([+-]?\d+(?:\.\d*)?)([d]*)" 166 r"([+-]?\d+(?:\.\d*)?)([d]*)" 169 r"\s*#\s*ID:\s*(\d+)" 170 r"(?:\s*,\s*mag:\s*(\d+\.\d*))?" 173 _type, ra, raUnit, dec, decUnit, \
174 param1, param1Unit, param2, param2Unit, param3, param3Unit, \
175 _id, mag = mat.groups()
192 width =
convertToAngle(param1, param1Unit,
"width", fileName, lineNo)
193 height =
convertToAngle(param2, param2Unit,
"height", fileName, lineNo)
194 angle =
convertToAngle(param3, param3Unit,
"angle", fileName, lineNo)
197 log.warn(
"Rotated boxes are not supported: \"%s\" at %s:%d" % (
198 line, fileName, lineNo))
200 elif _type ==
"circle":
201 radius =
convertToAngle(param1, param1Unit,
"radius", fileName, lineNo)
203 if not (param2
is None and param3
is None):
204 log.warn(
"Extra parameters for circle: \"%s\" at %s:%d" % (
205 line, fileName, lineNo))
208 rec = brightObjects.addNew()
213 rec.setCoord(afwGeom.SpherePoint(ra, dec))
216 rec[
"height"] = height
218 rec[
"radius"] = radius
220 log.warn(
"Unexpected line \"%s\" at %s:%d" % (line, fileName, lineNo))
224 raise RuntimeError(
"Saw %d formatting errors in %s" % (nFormatError, fileName))
226 if not checkedWcsIsFk5:
227 raise RuntimeError(
"Expected to see a line specifying an fk5 wcs in %s" % fileName)
230 brightObjects._catalog = brightObjects._catalog.copy(
True)
236 """Given a variable and its units, return an afwGeom.Angle 238 what, fileName, and lineNo are used to generate helpful error messages 242 if varUnit
in (
"d",
"",
None):
249 raise RuntimeError(
"unsupported unit \"%s\" for %s at %s:%d" %
250 (varUnit, what, fileName, lineNo))
252 return var*afwGeom.degrees
256 """Plugin for reading DS9 region file catalogs with Gen3 Butler. 260 def _readFile(self, path, pytype):
262 if not os.path.exists(path):
265 return pytype.read(path)
267 def _writeFile(self, inMemoryDataset, fileDescriptor):
269 raise NotImplementedError(
"Write not implemented.")
def convertToAngle(var, varUnit, what, fileName, lineNo)
def __setitem__(self, i, v)
def readFits(cls, fileName, hdu=0, flags=0)