lsst.meas.astrom  16.0-13-g5f6c0b1+5
display.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2016 AURA/LSST.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 
23 __all__ = ["displayAstrometry", "plotAstrometry"]
24 
25 import math
26 
27 import numpy as np
28 
29 import lsst.afw.display as afwDisplay
30 from lsst.afw.image import ExposureF
31 from lsst.afw.table import Point2DKey
32 
33 
34 def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None,
35  matches=None, frame=1, title="", pause=True):
36  """Show an astrometry debug image
37 
38  - reference objects in refCat are shown as red X
39  - sources in sourceCat are shown as green +
40  - distorted sources in sourceCat (position given by distortedCentroidKey) are shown as green o
41  - matches are shown as a yellow circle around the source and a yellow line
42  connecting the reference object and source
43  - if both exposure and bbox are None, no image is displayed
44 
45  @param[in] refCat reference object catalog; must have fields "centroid_x" and "centroid_y"
46  @param[in] sourceCat source catalog; must have field "slot_Centroid_x" and "slot_Centroid_y"
47  @param[in] distortedCentroidKey key for sourceCat with field to use for distorted positions, or None
48  @param[in] exposure exposure to display, or None for a blank exposure
49  @param[in] bbox bounding box of exposure; used if exposure is None for a blank image
50  @param[in] matches a list of lsst.afw.table.ReferenceMatch, or None
51  @param[in] frame frame number for ds9 display
52  @param[in] title title for ds9 display
53  @param[in] pause pause for inspection of display? This is done by dropping into pdb.
54  """
55  disp = afwDisplay.getDisplay(frame)
56 
57  if exposure is not None:
58  disp.mtv(exposure, title=title)
59  elif bbox is not None:
60  disp.mtv(exposure=ExposureF(bbox), title=title)
61 
62  with disp.Buffering():
63  if refCat is not None:
64  refCentroidKey = Point2DKey(refCat.schema["centroid"])
65  for refObj in refCat:
66  rx, ry = refObj.get(refCentroidKey)
67  disp.dot("x", rx, ry, size=10, ctype=afwDisplay.RED)
68 
69  if sourceCat is not None:
70  sourceCentroidKey = Point2DKey(sourceCat.schema["slot_Centroid"])
71  for source in sourceCat:
72  sx, sy = source.get(sourceCentroidKey)
73  disp.dot("+", sx, sy, size=10, ctype=afwDisplay.GREEN)
74  if distortedCentroidKey is not None:
75  dx, dy = source.get(distortedCentroidKey)
76  disp.dot("o", dx, dy, size=10, ctype=afwDisplay.GREEN)
77  disp.line([(sx, sy), (dx, dy)], ctype=afwDisplay.GREEN)
78 
79  if matches is not None:
80  refCentroidKey = Point2DKey(matches[0].first.schema["centroid"])
81  sourceCentroidKey = Point2DKey(matches[0].second.schema["slot_Centroid"])
82  radArr = np.ndarray(len(matches))
83 
84  for i, m in enumerate(matches):
85  refCentroid = m.first.get(refCentroidKey)
86  sourceCentroid = m.second.get(sourceCentroidKey)
87  radArr[i] = math.hypot(*(refCentroid - sourceCentroid))
88  sx, sy = sourceCentroid
89  disp.dot("o", sx, sy, size=10, ctype=afwDisplay.YELLOW)
90  disp.line([refCentroid, sourceCentroid], ctype=afwDisplay.YELLOW)
91 
92  print("<match radius> = %.4g +- %.4g [%d matches]" %
93  (radArr.mean(), radArr.std(), len(matches)))
94 
95  if pause:
96  print("Dropping into debugger to allow inspection of display. Type 'continue' when done.")
97  import pdb
98  pdb.set_trace()
99 
100 
101 def plotAstrometry(
102  matches,
103  refCat=None,
104  sourceCat=None,
105  refMarker="x",
106  refColor="r",
107  sourceMarker="+",
108  sourceColor="g",
109  matchColor="y"
110 ):
111  """Plot reference objects, sources and matches
112 
113  By default:
114  - reference objects in refCat are shown as red X
115  - sources in sourceCat are shown as green +
116  - matches are shown as a yellow circle around the source and a line
117  connecting the reference object to the source
118 
119  @param[in] matches list of matches
120  @param[in] refCat reference object catalog, or None to not plot reference objects
121  @param[in] sourceCat source catalog, or None to not plot sources
122  @param[in] refMarker pyplot marker for reference objects
123  @param[in] refColor pyplot color for reference objects
124  @param[in] sourceMarker pyplot marker for sources
125  @param[in] sourceColor pyplot color for sources
126  @param[in] matchColor color for matches; can be a constant
127  or a function taking one match and returning a string
128  """
129  # delay importing plt to give users a chance to set the backend before calling this function
130  import matplotlib.pyplot as plt
131  refSchema = matches[0][0].schema
132  refCentroidKey = Point2DKey(refSchema["centroid"])
133  srcSchema = matches[0][1].schema
134  srcCentroidKey = Point2DKey(srcSchema["slot_Centroid"])
135 
136  if refCat is not None:
137  refXArr, refYArr = list(zip(*[ref.get(refCentroidKey) for ref in refCat]))
138  plt.plot(refXArr, refYArr, marker=refMarker, color=refColor, linestyle="")
139 
140  if sourceCat is not None:
141  srcXArr, srcYArr = list(zip(*[src.get(srcCentroidKey) for src in sourceCat]))
142  plt.plot(srcXArr, srcYArr, marker=sourceMarker, color=sourceColor, linestyle="")
143 
144  def makeLineSegmentData(refXYArr, srcXYArr, colorArr):
145  """Make a list of line segement data
146 
147  This is used to draw line segements between ref and src positions in the specified color
148 
149  The returned data has the format:
150  [(refX0, srcX0), (refY0, srcY0), color0, (refX1, srcX1), (refY1, srcY1), color1,...]
151  """
152  if len(refXYArr) != len(srcXYArr):
153  raise RuntimeError("len(refXYArr) = %d != %d = len(srcXYArr)" %
154  (len(refXYArr), len(srcXYArr)))
155  if len(refXYArr) != len(colorArr):
156  raise RuntimeError("len(refXYArr) = %d != %d = len(colorArr)" %
157  (len(refXYArr), len(colorArr)))
158 
159  refXArr, refYArr = list(zip(*refXYArr))
160  srcXArr, srcYArr = list(zip(*srcXYArr))
161  refSrcXArr = list(zip(refXArr, srcXArr))
162  refSrcYArr = list(zip(refYArr, srcYArr))
163  dataList = []
164  for xycolor in zip(refSrcXArr, refSrcYArr, colorArr):
165  for val in xycolor:
166  dataList.append(val)
167  return dataList
168 
169  refXYArr, srcXYArr = \
170  list(zip(*[(match[0].get(refCentroidKey), match[1].get(srcCentroidKey)) for match in matches]))
171 
172  def plotSourceCircles(matches, color):
173  srcXYArr = [match[1].get(srcCentroidKey) for match in matches]
174  srcXArr, srcYArr = list(zip(*srcXYArr))
175  plt.plot(srcXArr, srcYArr, "o", mec=color, mfc="none", ms=10,)
176 
177  if callable(matchColor):
178  # different matches have different colors
179  matchColorArr = [matchColor(match) for match in matches]
180 
181  # plot circles for each color separately
182  matchColorSet = set(matchColorArr)
183  for color in matchColorSet:
184  subMatches = [match for match in matches if matchColor(match) == color]
185  plotSourceCircles(subMatches, color=color)
186  else:
187  matchColorArr = [matchColor]*len(refXYArr)
188  plotSourceCircles(matches, color=matchColor)
189 
190  lineSegData = makeLineSegmentData(refXYArr, srcXYArr, matchColorArr)
191  plt.plot(*lineSegData)
192 
193  plt.show()
def plotAstrometry(matches, refCat=None, sourceCat=None, refMarker="x", refColor="r", sourceMarker="+", sourceColor="g", matchColor="y")
Definition: display.py:110
def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True)
Definition: display.py:35