LSST Applications g070148d5b3+33e5256705,g0d53e28543+25c8b88941,g0da5cf3356+2dd1178308,g1081da9e2a+62d12e78cb,g17e5ecfddb+7e422d6136,g1c76d35bf8+ede3a706f7,g295839609d+225697d880,g2e2c1a68ba+cc1f6f037e,g2ffcdf413f+853cd4dcde,g38293774b4+62d12e78cb,g3b44f30a73+d953f1ac34,g48ccf36440+885b902d19,g4b2f1765b6+7dedbde6d2,g5320a0a9f6+0c5d6105b6,g56b687f8c9+ede3a706f7,g5c4744a4d9+ef6ac23297,g5ffd174ac0+0c5d6105b6,g6075d09f38+66af417445,g667d525e37+2ced63db88,g670421136f+2ced63db88,g71f27ac40c+2ced63db88,g774830318a+463cbe8d1f,g7876bc68e5+1d137996f1,g7985c39107+62d12e78cb,g7fdac2220c+0fd8241c05,g96f01af41f+368e6903a7,g9ca82378b8+2ced63db88,g9d27549199+ef6ac23297,gabe93b2c52+e3573e3735,gb065e2a02a+3dfbe639da,gbc3249ced9+0c5d6105b6,gbec6a3398f+0c5d6105b6,gc9534b9d65+35b9f25267,gd01420fc67+0c5d6105b6,geee7ff78d7+a14128c129,gf63283c776+ede3a706f7,gfed783d017+0c5d6105b6,w.2022.47
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,...
Definition: SortedCatalog.h:42
An integer coordinate rectangle.
Definition: Box.h:55
daf::base::PropertyList * list
Definition: fits.cc:928
daf::base::PropertySet * set
Definition: fits.cc:927
def 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