LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
display.py
Go to the documentation of this file.
1 from __future__ import absolute_import, division, print_function
2 
3 import math
4 
5 import numpy as np
6 
7 from lsst.afw.image import ExposureF
8 from lsst.afw.table import Point2DKey
9 
10 __all__ = ["displayAstrometry", "plotAstrometry"]
11 
12 def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None,
13  matches=None, frame=1, title="", pause=True):
14  """Show an astrometry debug image
15 
16  - reference objects in refCat are shown as red X
17  - sources in sourceCat are shown as green +
18  - distorted sources in sourceCat (position given by distortedCentroidKey) are shown as green o
19  - matches are shown as a yellow circle around the source and a yellow line
20  connecting the reference object and source
21  - if both exposure and bbox are None, no image is displayed
22 
23  @param[in] refCat reference object catalog; must have fields "centroid_x" and "centroid_y"
24  @param[in] sourceCat source catalog; must have field "slot_Centroid_x" and "slot_Centroid_y"
25  @param[in] distortedCentroidKey key for sourceCat with field to use for distorted positions, or None
26  @param[in] exposure exposure to display, or None for a blank exposure
27  @param[in] bbox bounding box of exposure; used if exposure is None for a blank image
28  @param[in] matches list of matches (an lsst.afw.table.ReferenceMatchVector), or None
29  @param[in] frame frame number for ds9 display
30  @param[in] title title for ds9 display
31  @param[in] pause pause for inspection of display? This is done by dropping into pdb.
32  """
33  import lsst.afw.display.ds9 as ds9
34 
35  if exposure is not None:
36  ds9.mtv(exposure, frame=frame, title=title)
37  elif bbox is not None:
38  ds9.mtv(exposure=ExposureF(bbox), frame=frame, title=title)
39 
40  with ds9.Buffering():
41  if refCat is not None:
42  refCentroidKey = Point2DKey(refCat.schema["centroid"])
43  for refObj in refCat:
44  rx, ry = refObj.get(refCentroidKey)
45  ds9.dot("x", rx, ry, size=10, frame=frame, ctype=ds9.RED)
46 
47  if sourceCat is not None:
48  sourceCentroidKey = Point2DKey(sourceCat.schema["slot_Centroid"])
49  for source in sourceCat:
50  sx, sy = source.get(sourceCentroidKey)
51  ds9.dot("+", sx, sy, size=10, frame=frame, ctype=ds9.GREEN)
52  if distortedCentroidKey is not None:
53  dx, dy = source.get(distortedCentroidKey)
54  ds9.dot("o", dx, dy, size=10, frame=frame, ctype=ds9.GREEN)
55  ds9.line([(sx, sy), (dx, dy)], ctype=ds9.GREEN, frame=frame)
56 
57  if matches is not None:
58  refCentroidKey = Point2DKey(matches[0].first.schema["centroid"])
59  sourceCentroidKey = Point2DKey(matches[0].second.schema["slot_Centroid"])
60  radArr = np.ndarray(len(matches))
61 
62  for i, m in enumerate(matches):
63  refCentroid = m.first.get(refCentroidKey)
64  sourceCentroid = m.second.get(sourceCentroidKey)
65  radArr[i] = math.hypot(*(refCentroid - sourceCentroid))
66  sx, sy = sourceCentroid
67  ds9.dot("o", sx, sy, size=10, frame=frame, ctype=ds9.YELLOW)
68  ds9.line([refCentroid, sourceCentroid], ctype=ds9.YELLOW)
69 
70  print("<match radius> = %.4g +- %.4g [%d matches]" %
71  (radArr.mean(), radArr.std(), len(matches)))
72 
73  if pause:
74  print("Dropping into debugger to allow inspection of display. Type 'continue' when done.")
75  import pdb;pdb.set_trace()
76 
77 def plotAstrometry(
78  matches,
79  refCat=None,
80  sourceCat=None,
81  refMarker="x",
82  refColor="r",
83  sourceMarker="+",
84  sourceColor="g",
85  matchColor="y"):
86  """Plot reference objects, sources and matches
87 
88  By default:
89  - reference objects in refCat are shown as red X
90  - sources in sourceCat are shown as green +
91  - matches are shown as a yellow circle around the source and a line
92  connecting the reference object to the source
93 
94  @param[in] matches list of matches
95  @param[in] refCat reference object catalog, or None to not plot reference objects
96  @param[in] sourceCat source catalog, or None to not plot sources
97  @param[in] refMarker pyplot marker for reference objects
98  @param[in] refColor pyplot color for reference objects
99  @param[in] sourceMarker pyplot marker for sources
100  @param[in] sourceColor pyplot color for sources
101  @param[in] matchColor color for matches; can be a constant
102  or a function taking one match and returning a string
103  """
104  # delay importing plt to give users a chance to set the backend before calling this function
105  import matplotlib.pyplot as plt
106  refSchema = matches[0][0].schema
107  refCentroidKey = Point2DKey(refSchema["centroid"])
108  srcSchema = matches[0][1].schema
109  srcCentroidKey = Point2DKey(srcSchema["slot_Centroid"])
110 
111  if refCat is not None:
112  refXArr, refYArr = zip(*[ref.get(refCentroidKey) for ref in refCat])
113  plt.plot(refXArr, refYArr, marker=refMarker, color=refColor, linestyle="")
114 
115  if sourceCat is not None:
116  srcXArr, srcYArr = zip(*[src.get(srcCentroidKey) for src in sourceCat])
117  plt.plot(srcXArr, srcYArr, marker=sourceMarker, color=sourceColor, linestyle="")
118 
119  def makeLineSegmentData(refXYArr, srcXYArr, colorArr):
120  """Make a list of line segement data
121 
122  This is used to draw line segements between ref and src positions in the specified color
123 
124  The returned data has the format:
125  [(refX0, srcX0), (refY0, srcY0), color0, (refX1, srcX1), (refY1, srcY1), color1,...]
126  """
127  if len(refXYArr) != len(srcXYArr):
128  raise RuntimeError("len(refXYArr) = %d != %d = len(srcXYArr)" %
129  (len(refXYArr), len(srcXYArr)))
130  if len(refXYArr) != len(colorArr):
131  raise RuntimeError("len(refXYArr) = %d != %d = len(colorArr)" %
132  (len(refXYArr), len(colorArr)))
133 
134  refXArr, refYArr = zip(*refXYArr)
135  srcXArr, srcYArr = zip(*srcXYArr)
136  refSrcXArr = zip(refXArr, srcXArr)
137  refSrcYArr = zip(refYArr, srcYArr)
138  dataList = []
139  for xycolor in zip(refSrcXArr, refSrcYArr, colorArr):
140  for val in xycolor:
141  dataList.append(val)
142  return dataList
143 
144  refXYArr, srcXYArr = \
145  zip(*[(match[0].get(refCentroidKey), match[1].get(srcCentroidKey)) for match in matches])
146 
147  def plotSourceCircles(matches, color):
148  srcXYArr = [match[1].get(srcCentroidKey) for match in matches]
149  srcXArr, srcYArr = zip(*srcXYArr)
150  plt.plot(srcXArr, srcYArr, "o", mec=color, mfc="none", ms=10,)
151 
152  if callable(matchColor):
153  # different matches have different colors
154  matchColorArr = [matchColor(match) for match in matches]
155 
156  # plot circles for each color separately
157  matchColorSet = set(matchColorArr)
158  for color in matchColorSet:
159  subMatches = [match for match in matches if matchColor(match) == color]
160  plotSourceCircles(subMatches, color=color)
161  else:
162  matchColorArr = [matchColor]*len(refXYArr)
163  plotSourceCircles(matches, color=matchColor)
164 
165  lineSegData = makeLineSegmentData(refXYArr, srcXYArr, matchColorArr)
166  plt.plot(*lineSegData)
167 
168  plt.show()
PointKey< double > Point2DKey
Definition: aggregates.h:111