LSST Applications g1653933729+34a971ddd9,g1a997c3884+34a971ddd9,g28da252d5a+32b12a4112,g2bbee38e9b+ffc559ee46,g2bc492864f+ffc559ee46,g2cdde0e794+704103fe75,g3156d2b45e+6e87dc994a,g347aa1857d+ffc559ee46,g35bb328faa+34a971ddd9,g3a166c0a6a+ffc559ee46,g3e281a1b8c+8ec26ec694,g4005a62e65+ba0306790b,g414038480c+9f5be647b3,g41af890bb2+686ab7cd58,g4e1a3235cc+1fd785b14f,g7b55021d1b+da0d0eec6b,g80478fca09+6e21f9dc20,g82479be7b0+6fa35d7547,g858d7b2824+356eaf3287,g9125e01d80+34a971ddd9,ga5288a1d22+ba1f9bb3ef,gae0086650b+34a971ddd9,gb4748cc0e8+fd26a265a0,gb4ec7eb0ab+356eaf3287,gb58c049af0+ace264a4f2,gc081298178+30f12d1e69,gc28159a63d+ffc559ee46,gcf0d15dbbd+4adb3139bd,gd6b7c0dfd1+aae9efebf5,gda3e153d99+356eaf3287,gda6a2b7d83+4adb3139bd,gdaeeff99f8+7774323b41,gdd5a9049c5+ea78b51778,ge2409df99d+fa478de0b0,ge33fd446bb+356eaf3287,ge79ae78c31+ffc559ee46,gf0baf85859+890af219f9,gf5289d68f6+e11c78aeea,w.2024.41
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 ----------
39 refCat : `lsst.afw.table.SimpleCatalog`
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
133 refCat : `lsst.afw.table.SimpleCatalog`
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()
displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True)
Definition display.py:34
plotAstrometry(matches, refCat=None, sourceCat=None, refMarker="x", refColor="r", sourceMarker="+", sourceColor="g", matchColor="y")
Definition display.py:126