LSST Applications g180d380827+0f66a164bb,g2079a07aa2+86d27d4dc4,g2305ad1205+7d304bc7a0,g29320951ab+500695df56,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g33d1c0ed96+0e5473021a,g3a166c0a6a+0e5473021a,g3ddfee87b4+e42ea45bea,g48712c4677+36a86eeaa5,g487adcacf7+2dd8f347ac,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+c70619cc9d,g5a732f18d5+53520f316c,g5ea96fc03c+341ea1ce94,g64a986408d+f7cd9c7162,g858d7b2824+f7cd9c7162,g8a8a8dda67+585e252eca,g99cad8db69+469ab8c039,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,gb0e22166c9+60f28cb32d,gba4ed39666+c2a2e4ac27,gbb8dafda3b+c92fc63c7e,gbd866b1f37+f7cd9c7162,gc120e1dc64+02c66aa596,gc28159a63d+0e5473021a,gc3e9b769f7+b0068a2d9f,gcf0d15dbbd+e42ea45bea,gdaeeff99f8+f9a426f77a,ge6526c86ff+84383d05b3,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gff1a9f87cc+f7cd9c7162,w.2024.17
LSST Data Management Base Package
Loading...
Searching...
No Matches
Functions | Variables
showVisitSkyMap Namespace Reference

Functions

 bboxToRaDec (bbox, wcs)
 
 getValueAtPercentile (values, percentile=0.5)
 
 get_cmap (n, name="hsv")
 
 main (repo, collections, skymapName=None, tracts=None, visits=None, physicalFilters=None, bands=None, ccds=None, ccdKey="detector", showPatch=False, saveFile=None, showCcds=False, visitVetoFile=None, minOverlapFraction=None, trimToTracts=False, doUnscaledLimitRatio=False, forceScaledLimitRatio=False)
 
 makeWhereInStr (parameterName, parameterList, parameterType)
 
 getTractLimitsDict (skymap, tractList)
 
 getMinMaxLimits (limitsDict)
 
 derivePlotLimits (limitsDict, raToDecLimitRatio=1.0, buffFrac=0.0)
 
 setLimitsToEqualRatio (xMin, xMax, yMin, yMax)
 
 getDetRaDecCorners (ccdKey, ccdId, visit, visitSummary=None, butler=None, doLogWarn=True)
 
 getBand (visitSummary=None, butler=None, visit=None)
 

Variables

 logger = lsstLog.Log.getLogger("showVisitSkyMap.py")
 
 parser = argparse.ArgumentParser()
 
 type
 
 help
 
 str
 
 nargs
 
 metavar
 
 required
 
 default
 
 None
 
 int
 
 action
 
 float
 
 args = parser.parse_args()
 
 collections
 
 skymapName
 
 tracts
 
 visits
 
 physicalFilters
 
 bands
 
 ccds
 
 ccdKey
 
 showPatch
 
 saveFile
 
 showCcds
 
 visitVetoFile
 
 minOverlapFraction
 
 trimToTracts
 
 doUnscaledLimitRatio
 
 forceScaledLimitRatio
 

Function Documentation

◆ bboxToRaDec()

showVisitSkyMap.bboxToRaDec ( bbox,
wcs )
Get the corners of a BBox and convert them to lists of RA and Dec.

Definition at line 42 of file showVisitSkyMap.py.

42def bboxToRaDec(bbox, wcs):
43 """Get the corners of a BBox and convert them to lists of RA and Dec."""
44 sphPoints = wcs.pixelToSky(geom.Box2D(bbox).getCorners())
45 ra = [float(sph.getRa().asDegrees()) for sph in sphPoints]
46 dec = [float(sph.getDec().asDegrees()) for sph in sphPoints]
47 return ra, dec
48
49
A floating-point coordinate rectangle geometry.
Definition Box.h:413

◆ derivePlotLimits()

showVisitSkyMap.derivePlotLimits ( limitsDict,
raToDecLimitRatio = 1.0,
buffFrac = 0.0 )
Derive the axis limits to encompass all points in limitsDict.

Parameters
----------
limitsDict : `dict` [`dict`]
    A dictionary keyed on any id. Each entry includes a `dict`
    keyed on "ras" and "decs" including (at least the minimum
    and maximum) RA and Dec values in units of degrees.
raToDecLimitRatio : `float`, optional
    The aspect ratio between RA and Dec to set the plot limits to.  This
    is to namely to set this ratio to that of the focal plane (i.e. such
    that a square detector appears as a square), but any aspect ratio can,
    in principle, be requested.

Returns
-------
xlim, ylim : `tuple` [`float`]
    Two tuples containing the derived min and max values for the x and
    y-axis limits (in degrees), respectively.

Definition at line 613 of file showVisitSkyMap.py.

613def derivePlotLimits(limitsDict, raToDecLimitRatio=1.0, buffFrac=0.0):
614 """Derive the axis limits to encompass all points in limitsDict.
615
616 Parameters
617 ----------
618 limitsDict : `dict` [`dict`]
619 A dictionary keyed on any id. Each entry includes a `dict`
620 keyed on "ras" and "decs" including (at least the minimum
621 and maximum) RA and Dec values in units of degrees.
622 raToDecLimitRatio : `float`, optional
623 The aspect ratio between RA and Dec to set the plot limits to. This
624 is to namely to set this ratio to that of the focal plane (i.e. such
625 that a square detector appears as a square), but any aspect ratio can,
626 in principle, be requested.
627
628 Returns
629 -------
630 xlim, ylim : `tuple` [`float`]
631 Two tuples containing the derived min and max values for the x and
632 y-axis limits (in degrees), respectively.
633 """
634 xLimMin, xLimMax, yLimMin, yLimMax = getMinMaxLimits(limitsDict)
635
636 xDelta0 = xLimMax - xLimMin
637 yDelta0 = yLimMax - yLimMin
638 if raToDecLimitRatio is None:
639 padFrac = 0.05
640 xlim = xLimMax + padFrac*xDelta0, xLimMin - padFrac*xDelta0
641 ylim = yLimMin - padFrac*yDelta0, yLimMax + padFrac*yDelta0
642 return xlim, ylim
643
644 if raToDecLimitRatio == 1.0:
645 if xDelta0 > yDelta0:
646 xLimMin -= buffFrac*yDelta0
647 xLimMax += buffFrac*yDelta0
648 else:
649 yLimMin -= buffFrac*yDelta0
650 yLimMax += buffFrac*yDelta0
651 xLimMin, xLimMax, yLimMin, yLimMax = setLimitsToEqualRatio(xLimMin, xLimMax, yLimMin, yLimMax)
652 else:
653 xLimMin -= buffFrac*xDelta0
654 xLimMax += buffFrac*xDelta0
655 yLimMin -= buffFrac*yDelta0
656 yLimMax += buffFrac*yDelta0
657 xLimMin, xLimMax, yLimMin, yLimMax = setLimitsToEqualRatio(xLimMin, xLimMax, yLimMin, yLimMax)
658 xDelta = xLimMax - xLimMin
659 yDelta = yLimMax - yLimMin
660 if raToDecLimitRatio > 1.0:
661 if yDelta0 > xDelta:
662 xMid = xLimMin + 0.5*(xDelta)
663 xLimMin = xMid - 0.5*yDelta*raToDecLimitRatio
664 xLimMax = xMid + 0.5*yDelta*raToDecLimitRatio
665 else:
666 yMid = yLimMin + 0.5*(yDelta)
667 yLimMin = yMid - 0.5*xDelta/raToDecLimitRatio
668 yLimMax = yMid + 0.5*xDelta/raToDecLimitRatio
669 else:
670 if xDelta0 > yDelta0:
671 yMid = yLimMin + 0.5*(yDelta)
672 yLimMin = yMid - 0.5*xDelta/raToDecLimitRatio
673 yLimMax = yMid + 0.5*xDelta/raToDecLimitRatio
674 else:
675 xMid = xLimMin + 0.5*(xDelta)
676 xLimMin = xMid - 0.5*yDelta*raToDecLimitRatio
677 xLimMax = xMid + 0.5*yDelta*raToDecLimitRatio
678 xlim = xLimMax, xLimMin
679 ylim = yLimMin, yLimMax
680 return xlim, ylim
681
682

◆ get_cmap()

showVisitSkyMap.get_cmap ( n,
name = "hsv" )
Returns a function that maps each index in 0, 1, ..., n-1 to a distinct
RGB color; the keyword argument name must be a standard mpl colormap name.

Definition at line 72 of file showVisitSkyMap.py.

72def get_cmap(n, name="hsv"):
73 """Returns a function that maps each index in 0, 1, ..., n-1 to a distinct
74 RGB color; the keyword argument name must be a standard mpl colormap name.
75 """
76 return matplotlib.colormaps[name].resampled(n)
77
78

◆ getBand()

showVisitSkyMap.getBand ( visitSummary = None,
butler = None,
visit = None )
Determine band and physical filter for given visit.

Parameters
----------
visitSummary : `lsst.afw.table.ExposureCatalog` or `None`, optional
    The visitSummary table for the visit for which to determine the band.
butler : `lsst.daf.butler.Butler` or `None`, optional
    The butler from which to look up the Dimension Records. Only needed
    if ``visitSummary`` is `None`.
visit : `int` or `None, optional
    The visit number for which to determine the band. Only needed
    if ``visitSummary`` is `None`.

Returns
-------
band, physicalFilter : `str`
    The band and physical filter for the given visit.

Definition at line 737 of file showVisitSkyMap.py.

737def getBand(visitSummary=None, butler=None, visit=None):
738 """Determine band and physical filter for given visit.
739
740 Parameters
741 ----------
742 visitSummary : `lsst.afw.table.ExposureCatalog` or `None`, optional
743 The visitSummary table for the visit for which to determine the band.
744 butler : `lsst.daf.butler.Butler` or `None`, optional
745 The butler from which to look up the Dimension Records. Only needed
746 if ``visitSummary`` is `None`.
747 visit : `int` or `None, optional
748 The visit number for which to determine the band. Only needed
749 if ``visitSummary`` is `None`.
750
751 Returns
752 -------
753 band, physicalFilter : `str`
754 The band and physical filter for the given visit.
755 """
756 if visitSummary is not None:
757 band = visitSummary[0]["band"]
758 physicalFilter = visitSummary[0]["physical_filter"]
759 else:
760 record = list(butler.registry.queryDimensionRecords("band", visit=visit))[0]
761 band = record.name
762 record = list(butler.registry.queryDimensionRecords("physical_filter", visit=visit))[0]
763 physicalFilter = record.name
764 return band, physicalFilter
765
766

◆ getDetRaDecCorners()

showVisitSkyMap.getDetRaDecCorners ( ccdKey,
ccdId,
visit,
visitSummary = None,
butler = None,
doLogWarn = True )
Compute the RA/Dec corners lists for a given detector in a visit.

Definition at line 712 of file showVisitSkyMap.py.

712def getDetRaDecCorners(ccdKey, ccdId, visit, visitSummary=None, butler=None, doLogWarn=True):
713 """Compute the RA/Dec corners lists for a given detector in a visit.
714 """
715 raCorners, decCorners = None, None
716 if visitSummary is not None:
717 row = visitSummary.find(ccdId)
718 if row is None:
719 if doLogWarn:
720 logger.warn("No row found for %d in visitSummary of visit %d. "
721 "Skipping and continuing...", ccdId, visit)
722 else:
723 raCorners = list(row["raCorners"])
724 decCorners = list(row["decCorners"])
725 else:
726 try:
727 dataId = {"visit": visit, ccdKey: ccdId}
728 wcs = butler.get("calexp.wcs", dataId)
729 bbox = butler.get("calexp.bbox", dataId)
730 raCorners, decCorners = bboxToRaDec(bbox, wcs)
731 except LookupError as e:
732 logger.warn("%s Skipping and continuing...", e)
733
734 return raCorners, decCorners
735
736

◆ getMinMaxLimits()

showVisitSkyMap.getMinMaxLimits ( limitsDict)
Derive the min and max axis limits of points in limitsDict.

Parameters
----------
limitsDict : `dict` [`dict`]
    A dictionary keyed on any id. Each entry includes a `dict`
    keyed on "ras" and "decs" including (at least the minimum
    and maximum) RA and Dec values in units of degrees.

Returns
-------
xLimMin, xLimMax, yLimMin, yLimMax : `tuple` [`float`]
    The min and max values for the x and y-axis limits, respectively.

Definition at line 587 of file showVisitSkyMap.py.

587def getMinMaxLimits(limitsDict):
588 """Derive the min and max axis limits of points in limitsDict.
589
590 Parameters
591 ----------
592 limitsDict : `dict` [`dict`]
593 A dictionary keyed on any id. Each entry includes a `dict`
594 keyed on "ras" and "decs" including (at least the minimum
595 and maximum) RA and Dec values in units of degrees.
596
597 Returns
598 -------
599 xLimMin, xLimMax, yLimMin, yLimMax : `tuple` [`float`]
600 The min and max values for the x and y-axis limits, respectively.
601 """
602 xLimMin, yLimMin = 1e12, 1e12
603 xLimMax, yLimMax = -1e12, -1e12
604 for limitId, limits in limitsDict.items():
605 xLimMin = min(xLimMin, min(limits["ras"]))
606 xLimMax = max(xLimMax, max(limits["ras"]))
607 yLimMin = min(yLimMin, min(limits["decs"]))
608 yLimMax = max(yLimMax, max(limits["decs"]))
609
610 return xLimMin, xLimMax, yLimMin, yLimMax
611
612
int min
int max

◆ getTractLimitsDict()

showVisitSkyMap.getTractLimitsDict ( skymap,
tractList )
Return a dict containing tract limits needed for outline plotting.

Parameters
----------
skymap : `lsst.skymap.BaseSkyMap`
    The sky map used for this dataset. Used to obtain tract
    parameters.
tractList : `list` [`int`]
    The list of tract ids (as integers) for which to determine the
    limits.

Returns
-------
tractLimitsDict : `dict` [`dict`]
    A dictionary keyed on tract id. Each entry includes a `dict`
    including the tract RA corners, Dec corners, and the tract center,
    all in units of degrees. These are used for plotting the tract
    outlines.

Definition at line 549 of file showVisitSkyMap.py.

549def getTractLimitsDict(skymap, tractList):
550 """Return a dict containing tract limits needed for outline plotting.
551
552 Parameters
553 ----------
554 skymap : `lsst.skymap.BaseSkyMap`
555 The sky map used for this dataset. Used to obtain tract
556 parameters.
557 tractList : `list` [`int`]
558 The list of tract ids (as integers) for which to determine the
559 limits.
560
561 Returns
562 -------
563 tractLimitsDict : `dict` [`dict`]
564 A dictionary keyed on tract id. Each entry includes a `dict`
565 including the tract RA corners, Dec corners, and the tract center,
566 all in units of degrees. These are used for plotting the tract
567 outlines.
568 """
569 tractLimitsDict = {}
570 for tract in tractList:
571 tractInfo = skymap[tract]
572 tractBbox = tractInfo.outer_sky_polygon.getBoundingBox()
573 tractCenter = tractBbox.getCenter()
574 tractRa0 = (tractCenter[0] - tractBbox.getWidth() / 2).asDegrees()
575 tractRa1 = (tractCenter[0] + tractBbox.getWidth() / 2).asDegrees()
576 tractDec0 = (tractCenter[1] - tractBbox.getHeight() / 2).asDegrees()
577 tractDec1 = (tractCenter[1] + tractBbox.getHeight() / 2).asDegrees()
578 tractLimitsDict[tract] = {
579 "ras": [tractRa0, tractRa1, tractRa1, tractRa0, tractRa0],
580 "decs": [tractDec0, tractDec0, tractDec1, tractDec1, tractDec0],
581 "center": [tractCenter[0].asDegrees(), tractCenter[1].asDegrees()],
582 }
583
584 return tractLimitsDict
585
586

◆ getValueAtPercentile()

showVisitSkyMap.getValueAtPercentile ( values,
percentile = 0.5 )
Return a value a fraction of the way between the min and max values in a
list.

Parameters
----------
values : `list` [`float`]
    The list of values under consideration.
percentile : `float`, optional
    The percentile (expressed as a number between 0.0 and 1.0) at which
    to determine the value in `values`.

Returns
-------
result : `float`
    The value at the given percentile of ``values``.

Definition at line 50 of file showVisitSkyMap.py.

50def getValueAtPercentile(values, percentile=0.5):
51 """Return a value a fraction of the way between the min and max values in a
52 list.
53
54 Parameters
55 ----------
56 values : `list` [`float`]
57 The list of values under consideration.
58 percentile : `float`, optional
59 The percentile (expressed as a number between 0.0 and 1.0) at which
60 to determine the value in `values`.
61
62 Returns
63 -------
64 result : `float`
65 The value at the given percentile of ``values``.
66 """
67 m = min(values)
68 interval = max(values) - m
69 return m + percentile*interval
70
71

◆ main()

showVisitSkyMap.main ( repo,
collections,
skymapName = None,
tracts = None,
visits = None,
physicalFilters = None,
bands = None,
ccds = None,
ccdKey = "detector",
showPatch = False,
saveFile = None,
showCcds = False,
visitVetoFile = None,
minOverlapFraction = None,
trimToTracts = False,
doUnscaledLimitRatio = False,
forceScaledLimitRatio = False )

Definition at line 79 of file showVisitSkyMap.py.

82 forceScaledLimitRatio=False):
83 if minOverlapFraction is not None and tracts is None:
84 raise RuntimeError("Must specify --tracts if --minOverlapFraction is set")
85 logger.info("Making butler for collections = {} in repo {}".format(collections, repo))
86 butler = dafButler.Butler(repo, collections=collections)
87 instrument = butler.find_dataset("camera").dataId["instrument"]
88 detectorSkipList = []
89 # Make a guess at the skymapName if not provided
90 if skymapName is None:
91 if instrument == "HSC":
92 skymapName = "hsc_rings_v1"
93 detectorSkipList = [9] # detector 9 has long been dead for HSC
94 elif instrument == "LSSTCam-imSim":
95 skymapName = "DC2"
96 elif instrument == "LSSTComCamSim":
97 skymapName = "ops_rehersal_prep_2k_v1"
98 elif instrument == "LATISS":
99 skymapName = "latiss_v1"
100 elif instrument == "DECam":
101 skymapName = "decam_rings_v1"
102 else:
103 logger.error("Unknown skymapName for instrument: %s. Must specify --skymapName on command line.",
104 instrument)
105 logger.info("instrument = {} skymapName = {}".format(instrument, skymapName))
106 camera = butler.get("camera", instrument=instrument)
107 skymap = butler.get("skyMap", instrument=instrument, skymap=skymapName)
108
109 whereStr = ""
110 if tracts is not None:
111 tractStr = makeWhereInStr("tract", tracts, int)
112 whereStr += tractStr
113
114 if physicalFilters is not None:
115 physicalFilterStr = makeWhereInStr("physical_filter", physicalFilters, str)
116 whereStr += " AND " + physicalFilterStr if len(whereStr) else " " + physicalFilterStr
117
118 if bands is not None:
119 bandStr = makeWhereInStr("band", bands, str)
120 whereStr += " AND " + bandStr if len(whereStr) else " " + bandStr
121
122 if len(whereStr) > 1:
123 whereStr = "instrument=\'" + instrument + "\' AND skymap=\'" + skymapName + "\' AND " + whereStr
124 else:
125 whereStr = "instrument=\'" + instrument + "\' AND skymap=\'" + skymapName + "\'"
126 logger.info("Applying the following where clause in dataId search: {} ".format(whereStr))
127
128 visitVetoList = []
129 if visitVetoFile is not None:
130 with open(visitVetoFile) as f:
131 content = f.readlines()
132 visitVetoList = [int(visit.strip()) for visit in content]
133
134 if visits is None:
135 dataRefs = list(butler.registry.queryDatasets("calexp", where=whereStr).expanded())
136 visits = []
137 for dataRef in dataRefs:
138 visit = dataRef.dataId.visit.id
139 if visit not in visits and visit not in visitVetoList:
140 visits.append(visit)
141 visits.sort()
142 logger.info("List of visits (N={}) satisfying where and veto clauses: {}".format(len(visits),
143 visits))
144 else:
145 if len(visitVetoList) > 1:
146 visitListTemp = visits.copy()
147 for visit in visitListTemp:
148 if visit in visitVetoList:
149 visits.remove(visit)
150 logger.info("List of visits (N={}) excluding veto list: {}".format(len(visits), visits))
151 logger.info("List of visits (N={}): {}".format(len(visits), visits))
152
153 ccdIdList = []
154 for ccd in camera:
155 ccdId = ccd.getId()
156 if ((ccds is None or ccdId in ccds) and ccd.getType() == cameraGeom.DetectorType.SCIENCE
157 and ccdId not in detectorSkipList):
158 ccdIdList.append(ccdId)
159 ccdIdList.sort()
160 nDetTot = len(ccdIdList)
161
162 visitIncludeList = []
163 # Determine the fraction of detectors that overlap any tract under
164 # consideration. If this fraction does not exceed minOverlapFraction,
165 # skip this visit.
166 if minOverlapFraction is not None:
167 for i_v, visit in enumerate(visits):
168 ccdOverlapList = []
169 try:
170 visitSummary = butler.get("visitSummary", visit=visit)
171 except LookupError as e:
172 logger.warn("%s Will try to get wcs from calexp.", e)
173 visitSummary = None
174 if tracts is not None:
175 for tract in tracts:
176 tractInfo = skymap[tract]
177 sphCorners = tractInfo.wcs.pixelToSky(geom.Box2D(tractInfo.bbox).getCorners())
178 tractConvexHull = sphgeom.ConvexPolygon.convexHull(
179 [coord.getVector() for coord in sphCorners])
180 for ccdId in ccdIdList:
181 if ccdId not in ccdOverlapList:
182 raCorners, decCorners = getDetRaDecCorners(
183 ccdKey, ccdId, visit, visitSummary=visitSummary, butler=butler,
184 doLogWarn=False)
185 if raCorners is not None and decCorners is not None:
186 detSphCorners = []
187 for ra, dec in zip(raCorners, decCorners):
188 pt = geom.SpherePoint(geom.Angle(ra, geom.degrees),
189 geom.Angle(dec, geom.degrees))
190 detSphCorners.append(pt)
191 detConvexHull = sphgeom.ConvexPolygon.convexHull(
192 [coord.getVector() for coord in detSphCorners])
193 if tractConvexHull.contains(detConvexHull):
194 ccdOverlapList.append(ccdId)
195
196 if len(ccdOverlapList)/nDetTot >= minOverlapFraction:
197 break
198 if len(ccdOverlapList)/nDetTot < minOverlapFraction:
199 logger.info("Fraction of detectors overlaping any tract for visit %d (%.2f) < "
200 "minimum required (%.2f). Skipping visit...",
201 visit, len(ccdOverlapList)/nDetTot, minOverlapFraction)
202 else:
203 if visit not in visitIncludeList:
204 visitIncludeList.append(visit)
205 else:
206 visitIncludeList = visits
207
208 # Draw the CCDs.
209 ras, decs = [], []
210 bboxesPlotted = []
211 cmap = get_cmap(len(visitIncludeList))
212 alphaEdge = 0.7
213 maxVisitForLegend = 20
214 finalVisitList = []
215 includedBands = []
216 includedPhysicalFilters = []
217 for i_v, visit in enumerate(visitIncludeList):
218 print("Working on visit %d [%d of %d]" % (visit, i_v + 1, len(visitIncludeList)), end="\r")
219 inLegend = False
220 color = cmap(i_v)
221 fillKwargs = {"fill": False, "alpha": alphaEdge, "facecolor": None, "edgecolor": color, "lw": 0.6}
222 try:
223 visitSummary = butler.get("visitSummary", visit=visit)
224 except Exception as e:
225 logger.warn("%s Will try to get wcs from calexp.", e)
226 visitSummary = None
227
228 band, physicalFilter = getBand(visitSummary=visitSummary, butler=butler, visit=visit)
229 if band not in includedBands:
230 includedBands.append(band)
231 if physicalFilter not in includedPhysicalFilters:
232 includedPhysicalFilters.append(physicalFilter)
233
234 for ccdId in ccdIdList:
235 raCorners, decCorners = getDetRaDecCorners(
236 ccdKey, ccdId, visit, visitSummary=visitSummary, butler=butler)
237 if raCorners is not None and decCorners is not None:
238 ras += raCorners
239 decs += decCorners
240 if not inLegend and len(visitIncludeList) <= maxVisitForLegend:
241 plt.fill(raCorners, decCorners, label=str(visit), **fillKwargs)
242 inLegend = True
243 else:
244 plt.fill(raCorners, decCorners, **fillKwargs)
245 plt.fill(raCorners, decCorners, fill=True, alpha=alphaEdge/4, color=color,
246 edgecolor=color)
247 if visit not in finalVisitList:
248 finalVisitList.append(visit)
249 # add CCD serial numbers
250 if showCcds:
251 overlapFrac = 0.2
252 deltaRa = max(raCorners) - min(raCorners)
253 deltaDec = max(decCorners) - min(decCorners)
254 minPoint = geom.Point2D(min(raCorners) + overlapFrac*deltaRa,
255 min(decCorners) + overlapFrac*deltaDec)
256 maxPoint = geom.Point2D(max(raCorners) - overlapFrac*deltaRa,
257 max(decCorners) - overlapFrac*deltaDec)
258 # Use doubles in Box2D to check overlap
259 bboxDouble = geom.Box2D(minPoint, maxPoint)
260 overlaps = [not bboxDouble.overlaps(otherBbox) for otherBbox in bboxesPlotted]
261 if all(overlaps):
262 plt.text(getValueAtPercentile(raCorners), getValueAtPercentile(decCorners),
263 str(ccdId), fontsize=6, ha="center", va="center", color="darkblue")
264 bboxesPlotted.append(bboxDouble)
265
266 logger.info("Final list of visits (N={}) satisfying where and minOverlapFraction clauses: {}"
267 .format(len(finalVisitList), finalVisitList))
268
269 raToDecLimitRatio = None
270 if len(ras) > 0:
271 tractList = list(set(skymap.findTractIdArray(ras, decs, degrees=True)))
272 minVisitRa, maxVisitRa = min(ras), max(ras)
273 minVisitDec, maxVisitDec = min(decs), max(decs)
274 raVisitDiff = maxVisitRa - minVisitRa
275 decVisitDiff = maxVisitDec - minVisitDec
276 midVisitRa = minVisitRa + 0.5*raVisitDiff
277 midVisitDec = minVisitDec + 0.5*decVisitDiff
278 midRa = np.atleast_1d((midVisitRa*units.deg).to(units.radian).value).astype(np.float64)
279 midDec = np.atleast_1d((midVisitDec*units.deg).to(units.radian).value).astype(np.float64)
280 midSkyCoord = SkyCoord(midVisitRa*units.deg, midVisitDec*units.deg)
281 else:
282 if tracts is not None:
283 logger.info("No calexps were found, but --tracts list was provided, so will go ahead and "
284 "plot the empty tracts.")
285 tractList = tracts
286 trimToTracts = True
287 else:
288 raise RuntimeError("No data to plot (if you want to plot empty tracts, include them as "
289 "a blank-space separated list to the --tracts option.")
290 tractList.sort()
291 logger.info("List of tracts overlapping data: {}".format(tractList))
292 tractLimitsDict = getTractLimitsDict(skymap, tractList)
293
294 if forceScaledLimitRatio:
295 doUnscaledLimitRatio = False
296 else:
297 # Roughly compute radius in degrees of a single detector. If RA/Dec
298 # coverage is more than 30 times the detector radius, and the RA/Dec
299 # limit ratio is greater than raDecScaleThresh, don't try to scale to
300 # detector coords.
301 radiusMm = camera.computeMaxFocalPlaneRadius()
302 fpRadiusPt = geom.Point2D(radiusMm, radiusMm)
303 focalPlaneToFieldAngle = camera.getTransformMap().getTransform(
304 cameraGeom.FOCAL_PLANE, cameraGeom.FIELD_ANGLE
305 )
306 fpRadiusDeg = np.rad2deg(focalPlaneToFieldAngle.applyForward(fpRadiusPt))[0]
307 detectorRadiusDeg = fpRadiusDeg/np.sqrt(len(camera))
308
309 if trimToTracts:
310 xLimMin, xLimMax, yLimMin, yLimMax = getMinMaxLimits(tractLimitsDict)
311 xDelta0 = xLimMax - xLimMin
312 yDelta0 = yLimMax - yLimMin
313 else:
314 xDelta0 = raVisitDiff
315 yDelta0 = decVisitDiff
316 yLimMin = minVisitDec
317 yLimMax = maxVisitDec
318 raDecScaleThresh = 1.5 # This is a best guess with current testing.
319 if (
320 (xDelta0/yDelta0 > raDecScaleThresh or yDelta0/xDelta0 > raDecScaleThresh)
321 and max(xDelta0, yDelta0) > 70*detectorRadiusDeg
322 and yLimMin < 75.0 and yLimMax > -75.0
323 ):
324 logger.info(
325 "Sky coverage is large (and not too close to a pole), so not scaling to detector coords."
326 )
327 doUnscaledLimitRatio = True
328
329 if not doUnscaledLimitRatio:
330 # Find a detector that contains the mid point in RA/Dec (or the closest
331 # one) to set the plot aspect ratio.
332 minDistToMidCoord = 1e12
333 minSepVisit = None
334 minSepCcdId = None
335 for i_v, visit in enumerate(visits):
336 try:
337 visitSummary = butler.get("visitSummary", visit=visit)
338 except Exception as e:
339 logger.warn("%s Will try to get wcs from calexp.", e)
340 visitSummary = None
341 for ccdId in ccdIdList:
342 raCorners, decCorners = getDetRaDecCorners(
343 ccdKey, ccdId, visit, visitSummary=visitSummary, butler=butler, doLogWarn=False)
344 if raCorners is not None and decCorners is not None:
345 detSphCorners = []
346 for ra, dec in zip(raCorners, decCorners):
347 pt = geom.SpherePoint(geom.Angle(ra, geom.degrees),
348 geom.Angle(dec, geom.degrees))
349 detSphCorners.append(pt)
350 ptSkyCoord = SkyCoord(ra*units.deg, dec*units.deg)
351 separation = (midSkyCoord.separation(ptSkyCoord)).degree
352 if separation < minDistToMidCoord:
353 minSepVisit = visit
354 minSepCcdId = ccdId
355 minDistToMidCoord = separation
356 detConvexHull = sphgeom.ConvexPolygon(
357 [coord.getVector() for coord in detSphCorners])
358 if detConvexHull.contains(midRa, midDec) and raToDecLimitRatio is None:
359 logger.info(
360 "visit/det overlapping plot coord mid point in RA/Dec: %d %d", visit, ccdId
361 )
362 raToDecLimitRatio = (
363 (max(raCorners) - min(raCorners))/(max(decCorners) - min(decCorners))
364 )
365 det = camera[ccdId]
366 width = det.getBBox().getWidth()
367 height = det.getBBox().getHeight()
368 if raToDecLimitRatio > 1.0:
369 raToDecLimitRatio /= max(height/width, width/height)
370 else:
371 if raToDecLimitRatio < 1.0:
372 raToDecLimitRatio *= max(height/width, width/height)
373 break
374 if raToDecLimitRatio is not None:
375 break
376
377 if raToDecLimitRatio is None and minSepVisit is not None:
378 try:
379 visitSummary = butler.get("visitSummary", visit=minSepVisit)
380 except Exception as e:
381 logger.warn("%s Will try to get wcs from calexp.", e)
382 visitSummary = None
383 raCorners, decCorners = getDetRaDecCorners(
384 ccdKey, minSepCcdId, minSepVisit, visitSummary=visitSummary, butler=butler, doLogWarn=False)
385 for ra, dec in zip(raCorners, decCorners):
386 pt = geom.SpherePoint(geom.Angle(ra, geom.degrees),
387 geom.Angle(dec, geom.degrees))
388 detSphCorners.append(pt)
389 detConvexHull = sphgeom.ConvexPolygon([coord.getVector() for coord in detSphCorners])
390 logger.info(
391 "visit/det closest to plot coord mid point in RA/Dec (none actually overlap it): %d %d",
392 minSepVisit, minSepCcdId
393 )
394 raToDecLimitRatio = (max(raCorners) - min(raCorners))/(max(decCorners) - min(decCorners))
395 det = camera[minSepCcdId]
396 width = det.getBBox().getWidth()
397 height = det.getBBox().getHeight()
398 if raToDecLimitRatio > 1.0:
399 raToDecLimitRatio /= max(height/width, width/height)
400 else:
401 if raToDecLimitRatio < 1.0:
402 raToDecLimitRatio *= max(height/width, width/height)
403
404 if trimToTracts is True:
405 xlim, ylim = derivePlotLimits(tractLimitsDict, raToDecLimitRatio=raToDecLimitRatio, buffFrac=0.04)
406 else:
407 visitLimitsDict = {"allVisits": {"ras": [minVisitRa, maxVisitRa], "decs": [minVisitDec, maxVisitDec]}}
408 xlim, ylim = derivePlotLimits(visitLimitsDict, raToDecLimitRatio=raToDecLimitRatio, buffFrac=0.04)
409
410 if doUnscaledLimitRatio:
411 boxAspectRatio = abs((ylim[1] - ylim[0])/(xlim[1] - xlim[0]))
412 else:
413 boxAspectRatio = 1.0
414
415 # Draw the skymap.
416 alpha0 = 1.0
417 tractHandleList = []
418 tractStrList = []
419 if tracts is not None:
420 tractOutlineList = list(set(tracts + tractList))
421 else:
422 tractOutlineList = tractList
423 tractOutlineList.sort()
424 logger.info("List of tract outlines being plotted: {}".format(tractOutlineList))
425 for i_t, tract in enumerate(tractOutlineList):
426 alpha = max(0.1, alpha0 - i_t*1.0/len(tractOutlineList))
427 tractInfo = skymap[tract]
428 tCenter = tractInfo.ctr_coord
429 tCenterRa = tCenter.getRa().asDegrees()
430 tCenterDec = tCenter.getDec().asDegrees()
431 fracDeltaX = 0.02*abs((xlim[1] - xlim[0]))
432 fracDeltaY = 0.02*abs((ylim[1] - ylim[0]))
433 if (xlim[1] + fracDeltaX < tCenterRa < xlim[0] - fracDeltaX
434 and ylim[0] + fracDeltaY < tCenterDec < ylim[1] - fracDeltaY):
435 if len(tractOutlineList) > 1 or not showPatch:
436 if not showPatch:
437 plt.text(tCenterRa, tCenterDec, tract, fontsize=7, alpha=alpha, ha="center", va="center")
438 else:
439 plt.text(tCenterRa, tCenterDec, tract, fontsize=7, alpha=1, color="white",
440 path_effects=[pathEffects.withStroke(linewidth=3, foreground="black")],
441 fontweight=500, ha="center", va="center", zorder=5)
442 ra, dec = bboxToRaDec(tractInfo.bbox, tractInfo.getWcs())
443 plt.fill(ra, dec, fill=False, edgecolor="k", lw=1, linestyle="dashed", alpha=alpha)
444 tractArtist = matplotlib.patches.Patch(fill=False, edgecolor="k", linestyle="dashed", alpha=alpha)
445 tractHandleList.append(tractArtist)
446 tractStrList.append(str(tract))
447 if showPatch:
448 patchColor = "k"
449 for patch in tractInfo:
450 ra, dec = bboxToRaDec(patch.getInnerBBox(), tractInfo.getWcs())
451 plt.fill(ra, dec, fill=False, edgecolor=patchColor, lw=0.5, linestyle=(0, (5, 6)),
452 alpha=alpha)
453 if (xlim[1] + fracDeltaX < getValueAtPercentile(ra) < xlim[0] - fracDeltaX
454 and ylim[0] + fracDeltaY < getValueAtPercentile(dec) < ylim[1] - fracDeltaY):
455 plt.text(getValueAtPercentile(ra), getValueAtPercentile(dec),
456 str(patch.sequential_index), fontsize=5, color=patchColor,
457 ha="center", va="center", alpha=alpha)
458
459 # Add labels and save.
460 ax = plt.gca()
461 ax.set_xlim(xlim)
462 ax.set_ylim(ylim)
463 ax.set_box_aspect(boxAspectRatio)
464 if abs(xlim[1] > 99.99):
465 ax.tick_params("x", labelrotation=45, pad=0, labelsize=8)
466 else:
467 ax.tick_params("x", labelrotation=0, pad=0, labelsize=8)
468 ax.tick_params("y", labelsize=8)
469 ax.set_xlabel("RA (deg)", fontsize=9)
470 ax.set_ylabel("Dec (deg)", fontsize=9)
471
472 visitScaleOffset = None
473 if len(visitIncludeList) > maxVisitForLegend:
474 nz = matplotlib.colors.Normalize()
475 colorBarScale = finalVisitList
476 if max(finalVisitList) > 9999999:
477 visitScaleOffset = min(finalVisitList)
478 colorBarScale = [visit - visitScaleOffset for visit in finalVisitList]
479 nz.autoscale(colorBarScale)
480 cax, _ = matplotlib.colorbar.make_axes(plt.gca(), pad=0.03)
481 cax.tick_params(labelsize=7)
482 cb = matplotlib.colorbar.ColorbarBase(cax, cmap=cmap, norm=nz, alpha=alphaEdge,
483 format=lambda x, _: f"{x:.0f}")
484 cb.ax.yaxis.get_offset_text().set_fontsize(7)
485 colorBarLabel = "visit number"
486 if visitScaleOffset is not None:
487 colorBarLabel += " - {:d}".format(visitScaleOffset)
488 cb.set_label(colorBarLabel, rotation=-90, labelpad=13, fontsize=9)
489 tractLegend = Legend(ax, tractHandleList, tractStrList, loc="upper right", fancybox=True,
490 shadow=True, fontsize=5, title_fontsize=6, title="tracts")
491 ax.add_artist(tractLegend)
492 else:
493 if len(visitIncludeList) > 0:
494 xBboxAnchor = min(1.25, max(1.03, boxAspectRatio*1.15))
495 ax.legend(loc="center left", bbox_to_anchor=(xBboxAnchor, 0.5), fancybox=True,
496 shadow=True, fontsize=6, title_fontsize=6, title="visits")
497 # Create the second legend and add the artist manually.
498 tractLegend = Legend(ax, tractHandleList, tractStrList, loc="center left", bbox_to_anchor=(1.0, 0.5),
499 fancybox=True, shadow=True, fontsize=6, title_fontsize=6, title="tracts")
500 ax.add_artist(tractLegend)
501
502 titleStr = repo + "\n" + collections[0]
503 if len(collections) > 1:
504 for collection in collections[1:]:
505 titleStr += "\n" + collection
506 titleStr += "\nnVisit: {}".format(str(len(finalVisitList)))
507 if minOverlapFraction is not None:
508 titleStr += " (minOvlpFrac = {:.2f})".format(minOverlapFraction)
509 if len(includedBands) > 0:
510 titleStr += " bands: {}".format(str(includedBands).translate({ord(i): None for i in "[]\'"}))
511 if len(includedPhysicalFilters) > 0:
512 if len(includedPhysicalFilters[0]) > 9:
513 titleStr += "\n"
514 titleStr += " physical filters: {}".format(str(includedPhysicalFilters).translate(
515 {ord(i): None for i in "[]\'"}))
516 ax.set_title("{}".format(titleStr), fontsize=8)
517
518 fig = plt.gcf()
519 if boxAspectRatio > 1.0:
520 minInches = max(4.0, 0.3*abs(xlim[1] - xlim[0]))
521 xInches = minInches
522 yInches = min(120.0, boxAspectRatio*minInches)
523 fig.set_size_inches(xInches, yInches)
524 if boxAspectRatio < 1.0:
525 minInches = max(4.0, 0.3*abs(ylim[1] - ylim[0]))
526 xInches = min(120.0, minInches/boxAspectRatio)
527 yInches = minInches
528 fig.set_size_inches(xInches, yInches)
529 if saveFile is not None:
530 logger.info("Saving file in: %s", saveFile)
531 fig.savefig(saveFile, bbox_inches="tight", dpi=150)
532 else:
533 fig.show()
534
535
A class representing an angle.
Definition Angle.h:128
Point in an unspecified spherical coordinate system.
Definition SpherePoint.h:57
daf::base::PropertySet * set
Definition fits.cc:931

◆ makeWhereInStr()

showVisitSkyMap.makeWhereInStr ( parameterName,
parameterList,
parameterType )
Create the string to be used in the where clause for registry lookup.

Definition at line 536 of file showVisitSkyMap.py.

536def makeWhereInStr(parameterName, parameterList, parameterType):
537 """Create the string to be used in the where clause for registry lookup.
538 """
539 typeStr = "\'" if parameterType is str else ""
540 whereInStr = parameterName + " IN (" + typeStr + str(parameterList[0]) + typeStr
541 if len(parameterList) > 1:
542 for param in parameterList[1:]:
543 whereInStr += ", " + typeStr + str(param) + typeStr
544 whereInStr += ")"
545
546 return whereInStr
547
548

◆ setLimitsToEqualRatio()

showVisitSkyMap.setLimitsToEqualRatio ( xMin,
xMax,
yMin,
yMax )
For a given set of x/y min/max, redefine to have equal aspect ratio.

The limits are extended on both ends such that the central value is
preserved.

Parameters
----------
xMin, xMax, yMin, yMax : `float`
    The min/max values of the x/y ranges for which to match in dynamic
    range while perserving the central values.

Returns
-------
xMin, xMax, yMin, yMax : `float`
    The adjusted min/max values of the x/y ranges with equal aspect ratios.

Definition at line 683 of file showVisitSkyMap.py.

683def setLimitsToEqualRatio(xMin, xMax, yMin, yMax):
684 """For a given set of x/y min/max, redefine to have equal aspect ratio.
685
686 The limits are extended on both ends such that the central value is
687 preserved.
688
689 Parameters
690 ----------
691 xMin, xMax, yMin, yMax : `float`
692 The min/max values of the x/y ranges for which to match in dynamic
693 range while perserving the central values.
694
695 Returns
696 -------
697 xMin, xMax, yMin, yMax : `float`
698 The adjusted min/max values of the x/y ranges with equal aspect ratios.
699 """
700 xDelta = xMax - xMin
701 yDelta = yMax - yMin
702 deltaDiff = yDelta - xDelta
703 if deltaDiff > 0:
704 xMin -= 0.5 * deltaDiff
705 xMax += 0.5 * deltaDiff
706 elif deltaDiff < 0:
707 yMin -= 0.5 * abs(deltaDiff)
708 yMax += 0.5 * abs(deltaDiff)
709 return xMin, xMax, yMin, yMax
710
711

Variable Documentation

◆ action

showVisitSkyMap.action

Definition at line 789 of file showVisitSkyMap.py.

◆ args

showVisitSkyMap.args = parser.parse_args()

Definition at line 808 of file showVisitSkyMap.py.

◆ bands

showVisitSkyMap.bands

Definition at line 810 of file showVisitSkyMap.py.

◆ ccdKey

showVisitSkyMap.ccdKey

Definition at line 810 of file showVisitSkyMap.py.

◆ ccds

showVisitSkyMap.ccds

Definition at line 810 of file showVisitSkyMap.py.

◆ collections

showVisitSkyMap.collections

Definition at line 809 of file showVisitSkyMap.py.

◆ default

showVisitSkyMap.default

Definition at line 774 of file showVisitSkyMap.py.

◆ doUnscaledLimitRatio

showVisitSkyMap.doUnscaledLimitRatio

Definition at line 813 of file showVisitSkyMap.py.

◆ float

showVisitSkyMap.float

Definition at line 798 of file showVisitSkyMap.py.

◆ forceScaledLimitRatio

showVisitSkyMap.forceScaledLimitRatio

Definition at line 814 of file showVisitSkyMap.py.

◆ help

showVisitSkyMap.help

Definition at line 770 of file showVisitSkyMap.py.

◆ int

showVisitSkyMap.int

Definition at line 775 of file showVisitSkyMap.py.

◆ logger

showVisitSkyMap.logger = lsstLog.Log.getLogger("showVisitSkyMap.py")

Definition at line 39 of file showVisitSkyMap.py.

◆ metavar

showVisitSkyMap.metavar

Definition at line 773 of file showVisitSkyMap.py.

◆ minOverlapFraction

showVisitSkyMap.minOverlapFraction

Definition at line 812 of file showVisitSkyMap.py.

◆ nargs

showVisitSkyMap.nargs

Definition at line 771 of file showVisitSkyMap.py.

◆ None

showVisitSkyMap.None

Definition at line 774 of file showVisitSkyMap.py.

◆ parser

showVisitSkyMap.parser = argparse.ArgumentParser()

Definition at line 768 of file showVisitSkyMap.py.

◆ physicalFilters

showVisitSkyMap.physicalFilters

Definition at line 810 of file showVisitSkyMap.py.

◆ required

showVisitSkyMap.required

Definition at line 773 of file showVisitSkyMap.py.

◆ saveFile

showVisitSkyMap.saveFile

Definition at line 811 of file showVisitSkyMap.py.

◆ showCcds

showVisitSkyMap.showCcds

Definition at line 811 of file showVisitSkyMap.py.

◆ showPatch

showVisitSkyMap.showPatch

Definition at line 811 of file showVisitSkyMap.py.

◆ skymapName

showVisitSkyMap.skymapName

Definition at line 809 of file showVisitSkyMap.py.

◆ str

showVisitSkyMap.str

Definition at line 771 of file showVisitSkyMap.py.

◆ tracts

showVisitSkyMap.tracts

Definition at line 809 of file showVisitSkyMap.py.

◆ trimToTracts

showVisitSkyMap.trimToTracts

Definition at line 813 of file showVisitSkyMap.py.

◆ type

showVisitSkyMap.type

Definition at line 769 of file showVisitSkyMap.py.

◆ visits

showVisitSkyMap.visits

Definition at line 809 of file showVisitSkyMap.py.

◆ visitVetoFile

showVisitSkyMap.visitVetoFile

Definition at line 812 of file showVisitSkyMap.py.