Hide keyboard shortcuts

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 

8 

9from .utils import footprintToImage, getExtent, get_sigma1, getFamilies, plotDeblendFamily, readCatalog 

10from .suprime import getSuprimeDataref 

11 

12 

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 ''' 

19 

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') 

27 

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') 

46 

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.') 

59 

60 opt, args = parser.parse_args() 

61 

62 # Logging 

63 if opt.verbose: 

64 lsst.log.setLevel('', lsst.log.DEBUG) 

65 else: 

66 lsst.log.setLevel('', lsst.log.INFO) 

67 

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' 

76 

77 if opt.pat: 

78 plotpattern = opt.pat 

79 else: 

80 plotpattern = opt.prefix + '%(pid)04i-%(name)s' + opt.suffix 

81 

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)) 

86 

87 def mapchild(i): 

88 if opt.order is None: 

89 return i 

90 return invorder[i] 

91 

92 def savefig(pid, figname): 

93 fn = plotpattern % dict(pid=pid, name=figname) 

94 plt.savefig(fn) 

95 

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) 

103 

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) 

112 

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) 

122 

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') 

127 

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() 

136 

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() 

145 

146 sigma1 = get_sigma1(mi) 

147 

148 fams = getFamilies(cat) 

149 print(len(fams), 'deblend families') 

150 

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) 

159 

160 def nlmap(X): 

161 return np.arcsinh(X / (3.*sigma1)) 

162 

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) 

174 

175 # Make plots for each deblend family. 

176 

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()) 

181 

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) 

189 

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') 

196 

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') 

207 

208 from lsst.meas.deblender.baseline import deblend 

209 

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 

216 

217 # Each section of the design doc runs the deblender with different args. 

218 

219 kwargs = dict(sigma1=sigma1, verbose=opt.verbose, 

220 getTemplateSum=True) 

221 

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) 

230 

231 if opt.sec == 'sdss': 

232 # SDSS intro 

233 kwargs = basic 

234 kwargs.update(lstsq_weight_templates=True) 

235 

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) 

250 

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) 

257 

258 elif opt.sec == 'patch': 

259 kwargs = basic 

260 kwargs.update(median_smooth_template=True, 

261 monotonic_template=True, 

262 patchEdges=True) 

263 

264 else: 

265 raise 'Unknown section: "%s"' % opt.sec 

266 

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) 

273 

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) 

279 

280 # Sum-of-templates plot 

281 tsum = np.zeros((tbb.getHeight(), tbb.getWidth())) 

282 tx0, ty0 = tbb.getMinX(), tbb.getMinY() 

283 

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())) 

288 

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') 

297 

298 # Make plots for each deblended child (peak) 

299 

300 k = 0 

301 for pkres, pk in zip(res.peaks, pks): 

302 

303 heavy = pkres.get_flux_portion() 

304 if heavy is None: 

305 print('Child has no HeavyFootprint -- skipping') 

306 continue 

307 

308 kk = mapchild(k) 

309 

310 w = pkres.template_weight 

311 

312 cfp = pkres.template_foot 

313 cbb = cfp.getBBox() 

314 cext = getExtent(cbb) 

315 

316 # Template image 

317 tim = pkres.template_mimg.getImage() 

318 timext = cext 

319 tim = tim.getArray() 

320 

321 (x0, x1, y0, y1) = timext 

322 print('tim ext', timext) 

323 tsum[y0-ty0:y1-ty0, x0-tx0:x1-tx0] += tim 

324 

325 # "Heavy" image -- flux assigned to child 

326 him = footprintToImage(heavy).getArray() 

327 hext = getExtent(heavy.getBBox()) 

328 

329 (x0, x1, y0, y1) = hext 

330 hsum[y0-ty0:y1-ty0, x0-tx0:x1-tx0] += him 

331 

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 

338 

339 if opt.sec == 'median': 

340 try: 

341 med = pkres.median_filtered_template 

342 except Exception: 

343 med = pkres.orig_template 

344 

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)) 

355 

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)) 

365 

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)) 

375 

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)) 

385 

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)) 

397 

398 if opt.sec == 'patch' and pkres.patched: 

399 pass 

400 

401 if opt.sec in ['ramp', 'ramp2'] and pkres.has_ramped_template: 

402 

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)) 

414 

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)) 

426 

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)) 

438 

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()) 

445 

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)) 

454 

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)) 

464 

465 k += 1 

466 

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') 

476 

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') 

486 

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') 

495 

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 

501 

502 print('Template footprint:', pkres.template_foot.getBBox()) 

503 print('Template img:', pkres.template_mimg.getBBox()) 

504 print('Heavy footprint:', heavy.getBBox()) 

505 

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 

511 

512 frac = tim / tsum[y0-ty0:y1-ty0, x0-tx0:x1-tx0] 

513 

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 

519 

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))) 

531 

532 k += 1 

533 

534 

535if __name__ == '__main__': 

536 main()