22__all__ = [
"ObjectMaskCatalog",
"RegionFileFormatter"]
30from lsst.daf.butler.formatters.file
import FileFormatter
34 """Class to support bright object masks
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")
47 self.
_catalog.table.setMetadata(dafBase.PropertyList())
66 """Read a ds9 region file, returning a ObjectMaskCatalog object
68 The files should be structured as follows:
78 circle(RA, DEC, RADIUS)
79 box(RA, DEC, XSIZE, YSIZE, THETA)
82 The
", mag: XX.YY" is optional
84 The commented lines must be present,
with the relevant fields such
as
85 tract patch
and filter filled
in. The coordinate system must be listed
86 as above. Each patch
is specified
as a box
or circle,
with RA, DEC,
87 and dimensions specified
in decimal degrees (
with or without an
90 Only (axis-aligned) boxes
and circles are currently supported
as
94 log = logging.getLogger("lsst.ObjectMaskCatalog")
97 checkedWcsIsFk5 =
False
98 NaN = float(
"NaN")*geom.degrees
101 with open(fileName)
as fd:
102 for lineNo, line
in enumerate(fd.readlines(), 1):
105 if re.search(
r"^\s*#", line):
114 mat = re.search(
r"^\s*#\s*([a-zA-Z][a-zA-Z0-9_]+)\s*:\s*(.*)", line)
116 key, value = mat.group(1).lower(), mat.group(2)
120 brightObjects.table.getMetadata().set(key, value)
122 line = re.sub(
r"^\s*#.*",
"", line)
126 if re.search(
r"^\s*wcs\s*;\s*fk5\s*$", line, re.IGNORECASE):
127 checkedWcsIsFk5 =
True
132 mat = re.search(
r"^\s*(box|circle)"
134 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
136 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
138 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
141 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
144 r"([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)([d]*)"
148 r"#\s*ID:[\w\s]*(\d+)"
149 r"(?:\s*,?\s*mag:\s*([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?))?"
152 _type, ra, raUnit, dec, decUnit, \
153 param1, param1Unit, param2, param2Unit, param3, param3Unit, \
154 _id, mag = mat.groups()
168 angle = 0.0*geom.degrees
171 width =
convertToAngle(param1, param1Unit,
"width", fileName, lineNo)
172 height =
convertToAngle(param2, param2Unit,
"height", fileName, lineNo)
173 if param3
is not None:
174 angle =
convertToAngle(param3, param3Unit,
"angle", fileName, lineNo)
177 log.warning(
"Rotated boxes are not supported: \"%s\" at %s:%d",
178 line, fileName, lineNo)
180 elif _type ==
"circle":
181 radius =
convertToAngle(param1, param1Unit,
"radius", fileName, lineNo)
183 if not (param2
is None and param3
is None):
184 log.warning(
"Extra parameters for circle: \"%s\" at %s:%d",
185 line, fileName, lineNo)
188 rec = brightObjects.addNew()
196 rec[
"height"] = height
198 rec[
"radius"] = radius
200 log.warning(
"Unexpected line \"%s\" at %s:%d", line, fileName, lineNo)
204 raise RuntimeError(
"Saw %d formatting errors in %s" % (nFormatError, fileName))
206 if not checkedWcsIsFk5:
207 raise RuntimeError(
"Expected to see a line specifying an fk5 wcs in %s" % fileName)
210 brightObjects._catalog = brightObjects._catalog.copy(
True)
216 """Given a variable and its units, return an geom.Angle
218 what, fileName, and lineNo are used to generate helpful error messages
222 if varUnit
in (
"d",
"",
None):
229 raise RuntimeError(
"unsupported unit \"%s\" for %s at %s:%d" %
230 (varUnit, what, fileName, lineNo))
232 return var*geom.degrees
236 """Plugin for reading DS9 region file catalogs with Gen3 Butler.
242 if not os.path.exists(path):
245 return pytype.read(path)
249 raise NotImplementedError(
"Write not implemented.")
convertToAngle(var, varUnit, what, fileName, lineNo)