LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
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 
24 import math
25 
26 import numpy as np
27 
28 import lsst.afw.display as afwDisplay
29 from lsst.afw.image import ExposureF
30 from lsst.afw.table import Point2DKey
31 
32 
33 def 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()
daf::base::PropertyList * list
Definition: fits.cc:913
daf::base::PropertySet * set
Definition: fits.cc:912
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
PointKey< double > Point2DKey
Definition: aggregates.h:118
def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True)
Definition: display.py:34
def plotAstrometry(matches, refCat=None, sourceCat=None, refMarker="x", refColor="r", sourceMarker="+", sourceColor="g", matchColor="y")
Definition: display.py:126
afw::image::Exposure< float > ExposureF
Definition: VeresModel.cc:36