LSST Applications 26.0.0,g0265f82a02+6660c170cc,g07994bdeae+30b05a742e,g0a0026dc87+17526d298f,g0a60f58ba1+17526d298f,g0e4bf8285c+96dd2c2ea9,g0ecae5effc+c266a536c8,g1e7d6db67d+6f7cb1f4bb,g26482f50c6+6346c0633c,g2bbee38e9b+6660c170cc,g2cc88a2952+0a4e78cd49,g3273194fdb+f6908454ef,g337abbeb29+6660c170cc,g337c41fc51+9a8f8f0815,g37c6e7c3d5+7bbafe9d37,g44018dc512+6660c170cc,g4a941329ef+4f7594a38e,g4c90b7bd52+5145c320d2,g58be5f913a+bea990ba40,g635b316a6c+8d6b3a3e56,g67924a670a+bfead8c487,g6ae5381d9b+81bc2a20b4,g93c4d6e787+26b17396bd,g98cecbdb62+ed2cb6d659,g98ffbb4407+81bc2a20b4,g9ddcbc5298+7f7571301f,ga1e77700b3+99e9273977,gae46bcf261+6660c170cc,gb2715bf1a1+17526d298f,gc86a011abf+17526d298f,gcf0d15dbbd+96dd2c2ea9,gdaeeff99f8+0d8dbea60f,gdb4ec4c597+6660c170cc,ge23793e450+96dd2c2ea9,gf041782ebf+171108ac67
LSST Data Management Base Package
Loading...
Searching...
No Matches
display.py
Go to the documentation of this file.
1# This file is part of meas_astrom.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21
22__all__ = ["displayAstrometry", "plotAstrometry"]
23
24import math
25
26import numpy as np
27
28import lsst.afw.display as afwDisplay
29from lsst.afw.image import ExposureF
30from lsst.afw.table import Point2DKey
31
32
33def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None,
34 matches=None, frame=1, title="", pause=True):
35 """Show an astrometry debug image.
36
37 Parameters
38 ----------
40 reference object catalog; must have fields "centroid_x" an
41 "centroid_y"
42 sourceCat : `lsst.afw.table.SourceCatalg`
43 source catalog; must have field "slot_Centroid_x" and "slot_Centroid_y"
44 distortedCentroidKey : `lsst.afw.table.Key`
45 key for sourceCat with field to use for distorted positions
46 exposure : `lsst.afw.image.Exposure`
47 exposure to display
48 bbox : `lsst.geom.Box2I`
49 bounding box of exposure; Used if the exposure is `None`
50 matches : `list` of `lsst.afw.table.ReferenceMatch`
51 List of matched objects
52 frame : `int`
53 frame number for display
54 title : `str`
55 title for display
56 pause : `bool`
57 pause for inspection of display? This is done by dropping into pdb.
58
59 Notes
60 -----
61
62 - reference objects in refCat are shown as red X
63 - sources in sourceCat are shown as green +
64 - distorted sources in sourceCat (position given by distortedCentroidKey)
65 are shown as green o
66 - matches are shown as a yellow circle around the source and a yellow line
67 connecting the reference object and source
68 - if both exposure and bbox are `None`, no image is displayed
69
70 """
71 disp = afwDisplay.getDisplay(frame=frame)
72
73 if exposure is not None:
74 disp.mtv(exposure, title=title)
75 elif bbox is not None:
76 disp.mtv(exposure=ExposureF(bbox), title=title)
77
78 with disp.Buffering():
79 if refCat is not None:
80 refCentroidKey = Point2DKey(refCat.schema["centroid"])
81 for refObj in refCat:
82 rx, ry = refObj.get(refCentroidKey)
83 disp.dot("x", rx, ry, size=10, ctype=afwDisplay.RED)
84
85 if sourceCat is not None:
86 sourceCentroidKey = Point2DKey(sourceCat.schema["slot_Centroid"])
87 for source in sourceCat:
88 sx, sy = source.get(sourceCentroidKey)
89 disp.dot("+", sx, sy, size=10, ctype=afwDisplay.GREEN)
90 if distortedCentroidKey is not None:
91 dx, dy = source.get(distortedCentroidKey)
92 disp.dot("o", dx, dy, size=10, ctype=afwDisplay.GREEN)
93 disp.line([(sx, sy), (dx, dy)], ctype=afwDisplay.GREEN)
94
95 if matches is not None:
96 refCentroidKey = Point2DKey(matches[0].first.schema["centroid"])
97 sourceCentroidKey = Point2DKey(matches[0].second.schema["slot_Centroid"])
98 radArr = np.ndarray(len(matches))
99
100 for i, m in enumerate(matches):
101 refCentroid = m.first.get(refCentroidKey)
102 sourceCentroid = m.second.get(sourceCentroidKey)
103 radArr[i] = math.hypot(*(refCentroid - sourceCentroid))
104 sx, sy = sourceCentroid
105 disp.dot("o", sx, sy, size=10, ctype=afwDisplay.YELLOW)
106 disp.line([refCentroid, sourceCentroid], ctype=afwDisplay.YELLOW)
107
108 print("<match radius> = %.4g +- %.4g [%d matches]" %
109 (radArr.mean(), radArr.std(), len(matches)))
110
111 if pause:
112 print("Dropping into debugger to allow inspection of display. Type 'continue' when done.")
113 import pdb
114 pdb.set_trace()
115
116
118 matches,
119 refCat=None,
120 sourceCat=None,
121 refMarker="x",
122 refColor="r",
123 sourceMarker="+",
124 sourceColor="g",
125 matchColor="y"
126):
127 """Plot reference objects, sources and matches
128
129 Parameters
130 ----------
131 matches : `list` of `lsst.afw.table.ReferenceMatch`
132 list of matches
134 reference object catalog, or None to not plot reference objects
135 sourceCat : `lsst.afw.table.SourceCatalog`
136 source catalog, or None to not plot sources
137 refMarker : `str`
138 pyplot marker for reference objects
139 refColor : `str`
140 pyplot color for reference objects
141 sourceMarker : `str`
142 pyplot marker for sources
143 sourceColor : `str`
144 pyplot color for sources
145 matchColor : `str`
146 color for matches; can be a constant
147 or a function taking one match and returning a string
148
149 Notes
150 -----
151 By default:
152
153 - reference objects in refCat are shown as red X
154 - sources in sourceCat are shown as green +
155 - matches are shown as a yellow circle around the source and a line
156 connecting the reference object to the source
157 """
158 # delay importing plt to give users a chance to set the backend before calling this function
159 import matplotlib.pyplot as plt
160 refSchema = matches[0][0].schema
161 refCentroidKey = Point2DKey(refSchema["centroid"])
162 srcSchema = matches[0][1].schema
163 srcCentroidKey = Point2DKey(srcSchema["slot_Centroid"])
164
165 if refCat is not None:
166 refXArr, refYArr = list(zip(*[ref.get(refCentroidKey) for ref in refCat]))
167 plt.plot(refXArr, refYArr, marker=refMarker, color=refColor, linestyle="")
168
169 if sourceCat is not None:
170 srcXArr, srcYArr = list(zip(*[src.get(srcCentroidKey) for src in sourceCat]))
171 plt.plot(srcXArr, srcYArr, marker=sourceMarker, color=sourceColor, linestyle="")
172
173 def makeLineSegmentData(refXYArr, srcXYArr, colorArr):
174 """Make a list of line segement data
175
176 This is used to draw line segements between ref and src positions in the specified color
177
178 Notes
179 -----
180 The returned data has the format:
181 [(refX0, srcX0), (refY0, srcY0), color0, (refX1, srcX1), (refY1, srcY1), color1,...]
182 """
183 if len(refXYArr) != len(srcXYArr):
184 raise RuntimeError("len(refXYArr) = %d != %d = len(srcXYArr)" %
185 (len(refXYArr), len(srcXYArr)))
186 if len(refXYArr) != len(colorArr):
187 raise RuntimeError("len(refXYArr) = %d != %d = len(colorArr)" %
188 (len(refXYArr), len(colorArr)))
189
190 refXArr, refYArr = list(zip(*refXYArr))
191 srcXArr, srcYArr = list(zip(*srcXYArr))
192 refSrcXArr = list(zip(refXArr, srcXArr))
193 refSrcYArr = list(zip(refYArr, srcYArr))
194 dataList = []
195 for xycolor in zip(refSrcXArr, refSrcYArr, colorArr):
196 for val in xycolor:
197 dataList.append(val)
198 return dataList
199
200 refXYArr, srcXYArr = \
201 list(zip(*[(match[0].get(refCentroidKey), match[1].get(srcCentroidKey)) for match in matches]))
202
203 def plotSourceCircles(matches, color):
204 srcXYArr = [match[1].get(srcCentroidKey) for match in matches]
205 srcXArr, srcYArr = list(zip(*srcXYArr))
206 plt.plot(srcXArr, srcYArr, "o", mec=color, mfc="none", ms=10,)
207
208 if callable(matchColor):
209 # different matches have different colors
210 matchColorArr = [matchColor(match) for match in matches]
211
212 # plot circles for each color separately
213 matchColorSet = set(matchColorArr)
214 for color in matchColorSet:
215 subMatches = [match for match in matches if matchColor(match) == color]
216 plotSourceCircles(subMatches, color=color)
217 else:
218 matchColorArr = [matchColor]*len(refXYArr)
219 plotSourceCircles(matches, color=matchColor)
220
221 lineSegData = makeLineSegmentData(refXYArr, srcXYArr, matchColorArr)
222 plt.plot(*lineSegData)
223
224 plt.show()
A class to contain the data, WCS, and other information needed to describe an image of the sky.
Definition Exposure.h:72
A class used as a handle to a particular field in a table.
Definition Key.h:53
Custom catalog class for record/table subclasses that are guaranteed to have an ID,...
An integer coordinate rectangle.
Definition Box.h:55
daf::base::PropertyList * list
Definition fits.cc:928
daf::base::PropertySet * set
Definition fits.cc:927
plotAstrometry(matches, refCat=None, sourceCat=None, refMarker="x", refColor="r", sourceMarker="+", sourceColor="g", matchColor="y")
Definition display.py:126
Lightweight representation of a geometric match between two records.
Definition Match.h:67