Coverage for examples/designdoc.py : 0%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import matplotlib
2matplotlib.use('Agg') # noqa E402
3import pylab as plt
4import numpy as np
5import lsst.afw.image as afwImage
6import lsst.afw.detection as afwDet
7import lsst.log
9from .utils import footprintToImage, getExtent, get_sigma1, getFamilies, plotDeblendFamily, readCatalog
10from .suprime import getSuprimeDataref
13def main():
14 '''
15 Runs the deblender and creates plots for the "design document",
16 doc/design.tex. See the file NOTES for how to get set up to the
17 point where you can actually run this on data.
18 '''
20 from optparse import OptionParser
21 parser = OptionParser()
22 parser.add_option('--root', dest='root', help='Root directory for Subaru data')
23 parser.add_option('--outroot', '-o', dest='outroot', help='Output root directory for Subaru data')
24 parser.add_option('--sources', help='Read a FITS table of sources')
25 parser.add_option('--calexp', help='Read a FITS calexp')
26 parser.add_option('--psf', help='Read a FITS PSF')
28 parser.add_option('--drill', '-D', dest='drill', action='append', type=str, default=[],
29 help='Drill down on individual source IDs')
30 parser.add_option('--drillxy', dest='drillxy', action='append', type=str, default=[],
31 help='Drill down on individual source positions, eg 132,46;54,67')
32 parser.add_option('--visit', dest='visit', type=int, default=108792, help='Suprimecam visit id')
33 parser.add_option('--ccd', dest='ccd', type=int, default=5, help='Suprimecam CCD number')
34 parser.add_option('--prefix', dest='prefix', default='design-', help='plot filename prefix')
35 parser.add_option('--suffix', dest='suffix', default=None, help='plot filename suffix (default: ".png")')
36 parser.add_option(
37 '--pat', dest='pat',
38 help='Plot filename pattern: eg, "design-%(pid)04i-%(name).png"; overrides --prefix and --suffix')
39 parser.add_option('--pdf', dest='pdf', action='store_true', default=False, help='save in PDF format?')
40 parser.add_option('-v', dest='verbose', action='store_true')
41 parser.add_option('--figw', dest='figw', type=float, help='Figure window width (inches)',
42 default=4.)
43 parser.add_option('--figh', dest='figh', type=float, help='Figure window height (inches)',
44 default=4.)
45 parser.add_option('--order', dest='order', type=str, help='Child order: eg 3,0,1,2')
47 parser.add_option('--sdss', dest='sec', action='store_const', const='sdss',
48 help='Produce plots for the SDSS section.')
49 parser.add_option('--mono', dest='sec', action='store_const', const='mono',
50 help='Produce plots for the "monotonic" section.')
51 parser.add_option('--median', dest='sec', action='store_const', const='median',
52 help='Produce plots for the "median filter" section.')
53 parser.add_option('--ramp', dest='sec', action='store_const', const='ramp',
54 help='Produce plots for the "ramp edges" section.')
55 parser.add_option('--ramp2', dest='sec', action='store_const', const='ramp2',
56 help='Produce plots for the "ramp edges + stray flux" section.')
57 parser.add_option('--patch', dest='sec', action='store_const', const='patch',
58 help='Produce plots for the "patch edges" section.')
60 opt, args = parser.parse_args()
62 # Logging
63 if opt.verbose:
64 lsst.log.setLevel('', lsst.log.DEBUG)
65 else:
66 lsst.log.setLevel('', lsst.log.INFO)
68 if opt.sec is None:
69 opt.sec = 'sdss'
70 if opt.pdf:
71 if opt.suffix is None:
72 opt.suffix = ''
73 opt.suffix += '.pdf'
74 if not opt.suffix:
75 opt.suffix = '.png'
77 if opt.pat:
78 plotpattern = opt.pat
79 else:
80 plotpattern = opt.prefix + '%(pid)04i-%(name)s' + opt.suffix
82 if opt.order is not None:
83 opt.order = [int(x) for x in opt.order.split(',')]
84 invorder = np.zeros(len(opt.order))
85 invorder[opt.order] = np.arange(len(opt.order))
87 def mapchild(i):
88 if opt.order is None:
89 return i
90 return invorder[i]
92 def savefig(pid, figname):
93 fn = plotpattern % dict(pid=pid, name=figname)
94 plt.savefig(fn)
96 # Load data using the butler, if desired
97 dr = None
98 if opt.sources is None or opt.calexp is None:
99 print('Creating DataRef...')
100 dr = getSuprimeDataref(opt.visit, opt.ccd, rootdir=opt.root,
101 outrootdir=opt.outroot)
102 print('Got', dr)
104 # Which parent ids / deblend families are we going to plot?
105 keepids = None
106 if len(opt.drill):
107 keepids = []
108 for d in opt.drill:
109 for dd in d.split(','):
110 keepids.append(int(dd))
111 print('Keeping parent ids', keepids)
113 keepxys = None
114 if len(opt.drillxy):
115 keepxys = []
116 for d in opt.drillxy:
117 for dd in d.split(';'):
118 xy = dd.split(',')
119 assert(len(xy) == 2)
120 keepxys.append((int(xy[0]), int(xy[1])))
121 print('Keeping parents at xy', keepxys)
123 # Read from butler or local file
124 cat = readCatalog(opt.sources, None, dataref=dr, keepids=keepids,
125 keepxys=keepxys, patargs=dict(visit=opt.visit, ccd=opt.ccd))
126 print('Got', len(cat), 'sources')
128 # Load data from butler or local files
129 if opt.calexp is not None:
130 print('Reading exposure from', opt.calexp)
131 exposure = afwImage.ExposureF(opt.calexp)
132 else:
133 exposure = dr.get('calexp')
134 print('Exposure', exposure)
135 mi = exposure.getMaskedImage()
137 if opt.psf is not None:
138 print('Reading PSF from', opt.psf)
139 psf = afwDet.Psf.readFits(opt.psf)
140 print('Got', psf)
141 elif dr:
142 psf = dr.get('psf')
143 else:
144 psf = exposure.getPsf()
146 sigma1 = get_sigma1(mi)
148 fams = getFamilies(cat)
149 print(len(fams), 'deblend families')
151 if False:
152 for j, (parent, children) in enumerate(fams):
153 print('parent', parent)
154 print('children', children)
155 plotDeblendFamily(mi, parent, children, cat, sigma1, ellipses=False)
156 fn = '%04i.png' % parent.getId()
157 plt.savefig(fn)
158 print('wrote', fn)
160 def nlmap(X):
161 return np.arcsinh(X / (3.*sigma1))
163 def myimshow(im, **kwargs):
164 kwargs = kwargs.copy()
165 mn = kwargs.get('vmin', -5*sigma1)
166 kwargs['vmin'] = nlmap(mn)
167 mx = kwargs.get('vmax', 100*sigma1)
168 kwargs['vmax'] = nlmap(mx)
169 plt.imshow(nlmap(im), **kwargs)
170 plt.figure(figsize=(opt.figw, opt.figh))
171 plt.subplot(1, 1, 1)
172 plt.subplots_adjust(left=0.01, right=0.99, bottom=0.01, top=0.99,
173 wspace=0.05, hspace=0.1)
175 # Make plots for each deblend family.
177 for j, (parent, children) in enumerate(fams):
178 print('parent', parent.getId())
179 print('children', [ch.getId() for ch in children])
180 print('parent x,y', parent.getX(), parent.getY())
182 pid = parent.getId()
183 fp = parent.getFootprint()
184 bb = fp.getBBox()
185 pim = footprintToImage(parent.getFootprint(), mi).getArray()
186 pext = getExtent(bb)
187 imargs = dict(interpolation='nearest', origin='lower', vmax=pim.max() * 0.95, vmin=-3.*sigma1)
188 pksty = dict(linestyle='None', marker='+', color='r', mew=3, ms=20, alpha=0.6)
190 plt.clf()
191 myimshow(afwImage.ImageF(mi.getImage(), bb).getArray(), **imargs)
192 plt.gray()
193 plt.xticks([])
194 plt.yticks([])
195 savefig(pid, 'image')
197 # Parent footprint
198 plt.clf()
199 myimshow(pim, extent=pext, **imargs)
200 plt.gray()
201 pks = fp.getPeaks()
202 plt.plot([pk.getIx() for pk in pks], [pk.getIy() for pk in pks], **pksty)
203 plt.xticks([])
204 plt.yticks([])
205 plt.axis(pext)
206 savefig(pid, 'parent')
208 from lsst.meas.deblender.baseline import deblend
210 xc = int((bb.getMinX() + bb.getMaxX()) / 2.)
211 yc = int((bb.getMinY() + bb.getMaxY()) / 2.)
212 if hasattr(psf, 'getFwhm'):
213 psf_fwhm = psf.getFwhm(xc, yc)
214 else:
215 psf_fwhm = psf.computeShape().getDeterminantRadius() * 2.35
217 # Each section of the design doc runs the deblender with different args.
219 kwargs = dict(sigma1=sigma1, verbose=opt.verbose,
220 getTemplateSum=True)
222 basic = kwargs.copy()
223 basic.update(fit_psfs=False,
224 median_smooth_template=False,
225 monotonic_template=False,
226 lstsq_weight_templates=False,
227 assignStrayFlux=False,
228 rampFluxAtEdge=False,
229 patchEdges=False)
231 if opt.sec == 'sdss':
232 # SDSS intro
233 kwargs = basic
234 kwargs.update(lstsq_weight_templates=True)
236 elif opt.sec == 'mono':
237 kwargs = basic
238 kwargs.update(lstsq_weight_templates=True,
239 monotonic_template=True)
240 elif opt.sec == 'median':
241 kwargs = basic
242 kwargs.update(lstsq_weight_templates=True,
243 median_smooth_template=True,
244 monotonic_template=True)
245 elif opt.sec == 'ramp':
246 kwargs = basic
247 kwargs.update(median_smooth_template=True,
248 monotonic_template=True,
249 rampFluxAtEdge=True)
251 elif opt.sec == 'ramp2':
252 kwargs = basic
253 kwargs.update(median_smooth_template=True,
254 monotonic_template=True,
255 rampFluxAtEdge=True,
256 assignStrayFlux=True)
258 elif opt.sec == 'patch':
259 kwargs = basic
260 kwargs.update(median_smooth_template=True,
261 monotonic_template=True,
262 patchEdges=True)
264 else:
265 raise 'Unknown section: "%s"' % opt.sec
267 print('Running deblender with kwargs:', kwargs)
268 res = deblend(fp, mi, psf, psf_fwhm, **kwargs)
269 # print('got result with', [x for x in dir(res) if not x.startswith('__')])
270 # for pk in res.peaks:
271 # print('got peak with', [x for x in dir(pk) if not x.startswith('__')])
272 # print(' deblend as psf?', pk.deblend_as_psf)
274 # Find bounding-box of all templates.
275 tbb = fp.getBBox()
276 for pkres, pk in zip(res.peaks, pks):
277 tbb.include(pkres.template_foot.getBBox())
278 print('Bounding-box of all templates:', tbb)
280 # Sum-of-templates plot
281 tsum = np.zeros((tbb.getHeight(), tbb.getWidth()))
282 tx0, ty0 = tbb.getMinX(), tbb.getMinY()
284 # Sum-of-deblended children plot(s)
285 # "heavy" bbox == template bbox.
286 hsum = np.zeros((tbb.getHeight(), tbb.getWidth()))
287 hsum2 = np.zeros((tbb.getHeight(), tbb.getWidth()))
289 # Sum of templates from the deblender itself
290 plt.clf()
291 t = res.templateSum
292 myimshow(t.getArray(), extent=getExtent(t.getBBox()), **imargs)
293 plt.gray()
294 plt.xticks([])
295 plt.yticks([])
296 savefig(pid, 'tsum1')
298 # Make plots for each deblended child (peak)
300 k = 0
301 for pkres, pk in zip(res.peaks, pks):
303 heavy = pkres.get_flux_portion()
304 if heavy is None:
305 print('Child has no HeavyFootprint -- skipping')
306 continue
308 kk = mapchild(k)
310 w = pkres.template_weight
312 cfp = pkres.template_foot
313 cbb = cfp.getBBox()
314 cext = getExtent(cbb)
316 # Template image
317 tim = pkres.template_mimg.getImage()
318 timext = cext
319 tim = tim.getArray()
321 (x0, x1, y0, y1) = timext
322 print('tim ext', timext)
323 tsum[y0-ty0:y1-ty0, x0-tx0:x1-tx0] += tim
325 # "Heavy" image -- flux assigned to child
326 him = footprintToImage(heavy).getArray()
327 hext = getExtent(heavy.getBBox())
329 (x0, x1, y0, y1) = hext
330 hsum[y0-ty0:y1-ty0, x0-tx0:x1-tx0] += him
332 # "Heavy" without stray flux
333 h2 = pkres.get_flux_portion(strayFlux=False)
334 him2 = footprintToImage(h2).getArray()
335 hext2 = getExtent(h2.getBBox())
336 (x0, x1, y0, y1) = hext2
337 hsum2[y0-ty0:y1-ty0, x0-tx0:x1-tx0] += him2
339 if opt.sec == 'median':
340 try:
341 med = pkres.median_filtered_template
342 except Exception:
343 med = pkres.orig_template
345 for im, nm in [(pkres.orig_template, 'symm'), (med, 'med')]:
346 # print('im:', im)
347 plt.clf()
348 myimshow(im.getArray(), extent=cext, **imargs)
349 plt.gray()
350 plt.xticks([])
351 plt.yticks([])
352 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
353 plt.axis(pext)
354 savefig(pid, nm + '%i' % (kk))
356 # Template
357 plt.clf()
358 myimshow(pkres.template_mimg.getImage().getArray() / w, extent=cext, **imargs)
359 plt.gray()
360 plt.xticks([])
361 plt.yticks([])
362 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
363 plt.axis(pext)
364 savefig(pid, 't%i' % (kk))
366 # Weighted template
367 plt.clf()
368 myimshow(tim, extent=cext, **imargs)
369 plt.gray()
370 plt.xticks([])
371 plt.yticks([])
372 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
373 plt.axis(pext)
374 savefig(pid, 'tw%i' % (kk))
376 # "Heavy"
377 plt.clf()
378 myimshow(him, extent=hext, **imargs)
379 plt.gray()
380 plt.xticks([])
381 plt.yticks([])
382 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
383 plt.axis(pext)
384 savefig(pid, 'h%i' % (kk))
386 # Original symmetric template
387 plt.clf()
388 t = pkres.orig_template
389 foot = pkres.orig_foot
390 myimshow(t.getArray(), extent=getExtent(foot.getBBox()), **imargs)
391 plt.gray()
392 plt.xticks([])
393 plt.yticks([])
394 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
395 plt.axis(pext)
396 savefig(pid, 'o%i' % (kk))
398 if opt.sec == 'patch' and pkres.patched:
399 pass
401 if opt.sec in ['ramp', 'ramp2'] and pkres.has_ramped_template:
403 # Ramped template
404 plt.clf()
405 t = pkres.ramped_template
406 myimshow(t.getArray(), extent=getExtent(t.getBBox()),
407 **imargs)
408 plt.gray()
409 plt.xticks([])
410 plt.yticks([])
411 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
412 plt.axis(pext)
413 savefig(pid, 'r%i' % (kk))
415 # Median-filtered template
416 plt.clf()
417 t = pkres.median_filtered_template
418 myimshow(t.getArray(), extent=getExtent(t.getBBox()),
419 **imargs)
420 plt.gray()
421 plt.xticks([])
422 plt.yticks([])
423 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
424 plt.axis(pext)
425 savefig(pid, 'med%i' % (kk))
427 # Assigned flux
428 plt.clf()
429 t = pkres.portion_mimg.getImage()
430 myimshow(t.getArray(), extent=getExtent(t.getBBox()),
431 **imargs)
432 plt.gray()
433 plt.xticks([])
434 plt.yticks([])
435 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
436 plt.axis(pext)
437 savefig(pid, 'p%i' % (kk))
439 if opt.sec == 'ramp2':
440 # stray flux
441 if pkres.stray_flux is not None:
442 s = pkres.stray_flux
443 strayim = footprintToImage(s).getArray()
444 strayext = getExtent(s.getBBox())
446 plt.clf()
447 myimshow(strayim, extent=strayext, **imargs)
448 plt.gray()
449 plt.xticks([])
450 plt.yticks([])
451 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
452 plt.axis(pext)
453 savefig(pid, 's%i' % (kk))
455 # Assigned flux, omitting stray flux.
456 plt.clf()
457 myimshow(him2, extent=hext2, **imargs)
458 plt.gray()
459 plt.xticks([])
460 plt.yticks([])
461 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
462 plt.axis(pext)
463 savefig(pid, 'hb%i' % (kk))
465 k += 1
467 # sum of templates
468 plt.clf()
469 myimshow(tsum, extent=getExtent(tbb), **imargs)
470 plt.gray()
471 plt.xticks([])
472 plt.yticks([])
473 plt.plot([pk.getIx() for pk in pks], [pk.getIy() for pk in pks], **pksty)
474 plt.axis(pext)
475 savefig(pid, 'tsum')
477 # sum of assigned flux
478 plt.clf()
479 myimshow(hsum, extent=getExtent(tbb), **imargs)
480 plt.gray()
481 plt.xticks([])
482 plt.yticks([])
483 plt.plot([pk.getIx() for pk in pks], [pk.getIy() for pk in pks], **pksty)
484 plt.axis(pext)
485 savefig(pid, 'hsum')
487 plt.clf()
488 myimshow(hsum2, extent=getExtent(tbb), **imargs)
489 plt.gray()
490 plt.xticks([])
491 plt.yticks([])
492 plt.plot([pk.getIx() for pk in pks], [pk.getIy() for pk in pks], **pksty)
493 plt.axis(pext)
494 savefig(pid, 'hsum2')
496 k = 0
497 for pkres, pk in zip(res.peaks, pks):
498 heavy = pkres.get_flux_portion()
499 if heavy is None:
500 continue
502 print('Template footprint:', pkres.template_foot.getBBox())
503 print('Template img:', pkres.template_mimg.getBBox())
504 print('Heavy footprint:', heavy.getBBox())
506 cfp = pkres.template_foot
507 cbb = cfp.getBBox()
508 cext = getExtent(cbb)
509 tim = pkres.template_mimg.getImage().getArray()
510 (x0, x1, y0, y1) = cext
512 frac = tim / tsum[y0-ty0:y1-ty0, x0-tx0:x1-tx0]
514 msk = afwImage.ImageF(cbb.getWidth(), cbb.getHeight())
515 msk.setXY0(cbb.getMinX(), cbb.getMinY())
516 afwDet.setImageFromFootprint(msk, cfp, 1.)
517 msk = msk.getArray()
518 frac[msk == 0.] = np.nan
520 # Fraction of flux assigned to this child.
521 plt.clf()
522 plt.imshow(frac, extent=cext, interpolation='nearest', origin='lower', vmin=0, vmax=1)
523 # plt.plot([x0,x0,x1,x1,x0], [y0,y1,y1,y0,y0], 'k-')
524 plt.gray()
525 plt.xticks([])
526 plt.yticks([])
527 plt.plot([pk.getIx()], [pk.getIy()], **pksty)
528 plt.gca().set_axis_bgcolor((0.9, 0.9, 0.5))
529 plt.axis(pext)
530 savefig(pid, 'f%i' % (mapchild(k)))
532 k += 1
535if __name__ == '__main__':
536 main()