Coverage for metadetect / lsst / vis.py: 8%

164 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-13 01:57 -0800

1import numpy as np 

2from matplotlib import pyplot as mplt 

3from .util import copy_mbexp 

4 

5DEFAULT_STRETCH = 1.25 

6DEFAULT_Q = 7.5 

7SIZE = 16 

8COLOR = 'red' 

9EDGECOLOR = 'white' 

10 

11 

12def show_exp(exp, mess=None, use_mpl=False, sources=None): 

13 """ 

14 show the image in ds9 

15 

16 Parameters 

17 ---------- 

18 exp: Exposure 

19 The image to show 

20 mess: str, optional 

21 A message to use as title to plot 

22 """ 

23 import matplotlib.pyplot as mplt 

24 import lsst.afw.display as afw_display 

25 

26 if use_mpl: 

27 fig, axs = mplt.subplots(ncols=3) 

28 image = exp.image.array 

29 

30 noise = np.sqrt(np.median(exp.variance.array)) 

31 

32 noise = np.sqrt(np.median(exp.variance.array)) 

33 minval = 0.1 * noise 

34 axs[0].imshow(np.log(image.clip(min=minval))) 

35 

36 axs[1].imshow(exp.variance.array) 

37 axs[1].set_title('variance') 

38 

39 axs[2].imshow(exp.mask.array) 

40 axs[2].set_title('mask') 

41 

42 if sources is not None: 

43 from pprint import pprint 

44 bbox = exp.getBBox() 

45 pprint(exp.mask.getMaskPlaneDict()) 

46 axs[0].scatter( 

47 sources['base_SdssCentroid_x'] - bbox.beginX, 

48 sources['base_SdssCentroid_y'] - bbox.beginY, 

49 color='red', 

50 ) 

51 

52 if mess is not None: 

53 fig.suptitle(mess) 

54 

55 mplt.show() 

56 

57 else: 

58 

59 display = afw_display.getDisplay(backend='ds9') 

60 display.mtv(exp) 

61 display.scale('log', 'minmax') 

62 

63 prompt = 'hit enter' 

64 if mess is not None: 

65 prompt = '%s: (%s)' % (mess, prompt) 

66 

67 input(prompt) 

68 

69 

70def show_mbexp( 

71 mbexp, stretch=DEFAULT_STRETCH, q=DEFAULT_Q, mess=None, ax=None, 

72 sources=None, 

73 show=True, 

74): 

75 """ 

76 visialize a MultibandExposure 

77 

78 Parameters 

79 ---------- 

80 mbexp: lsst.afw.image.MultibandExposure 

81 MutibandExposure to visualize. Currently must be at least 

82 three bands. 

83 stretch: float, optional 

84 The stretch parameter for 

85 astropy.visualization.lupton_rgb. import AsinhMapping 

86 q: float, optional 

87 The Q parameter for 

88 astropy.visualization.lupton_rgb. import AsinhMapping 

89 mess: str, optional 

90 A message to use as title to plot 

91 ax: matplotlib plot axis 

92 If sent use this axis for plot rather than creating a 

93 new one 

94 show: bool, optional 

95 If set to True, show on the screen. 

96 

97 Returns 

98 ------- 

99 The axis used for plotting 

100 """ 

101 

102 image = mbexp.image.array 

103 

104 if ax is None: 

105 fig, ax = mplt.subplots() 

106 

107 if image.shape[0] >= 3: 

108 import scarlet 

109 from astropy.visualization.lupton_rgb import AsinhMapping 

110 

111 timage = image[:3, :, :].clip(min=0) 

112 

113 asinh = AsinhMapping( 

114 minimum=0, 

115 stretch=stretch, 

116 Q=q, 

117 ) 

118 

119 img_rgb = scarlet.display.img_to_rgb(timage, norm=asinh) 

120 

121 ax.imshow(img_rgb) 

122 

123 else: 

124 noise = np.sqrt(np.median(mbexp.variance.array)) 

125 if image.shape[0] == 1: 

126 timage = image[0] 

127 else: 

128 timage = image.sum(axis=0) 

129 

130 noise = np.sqrt(np.median(mbexp.variance.array)) 

131 minval = 0.1 * noise 

132 ax.imshow(np.log(timage.clip(min=minval))) 

133 

134 if sources is not None: 

135 x, y = _extract_xy(mbexp, sources) 

136 ax.scatter( 

137 x, y, 

138 s=SIZE, color=COLOR, edgecolor=EDGECOLOR, 

139 ) 

140 

141 if mess is not None: 

142 ax.set_title(mess) 

143 

144 if show: 

145 mplt.show() 

146 

147 return ax 

148 

149 

150def _extract_xy(mbexp, sources): 

151 if isinstance(sources, np.ndarray): 

152 y = sources['row'] - sources['row0'] 

153 x = sources['col'] - sources['col0'] 

154 else: 

155 bbox = mbexp.getBBox() 

156 x0 = bbox.getBeginX() 

157 y0 = bbox.getBeginY() 

158 x = [] 

159 y = [] 

160 for source in sources[mbexp.bands[0]]: 

161 peak = source.getFootprint().getPeaks()[0] 

162 cen = peak.getCentroid() 

163 x.append(cen.getX() - x0) 

164 y.append(cen.getY() - y0) 

165 

166 return x, y 

167 

168 

169def compare_mbexp( 

170 mbexp, model, sources=None, stretch=DEFAULT_STRETCH, q=DEFAULT_Q, 

171): 

172 """ 

173 compare two MultibandExposure with residuals 

174 

175 Parameters 

176 ---------- 

177 mbexp: lsst.afw.image.MultibandExposure 

178 MutibandExposure to visualize. Currently must be at least 

179 three bands. 

180 model: lsst.afw.image.MultibandExposure 

181 MutibandExposure to visualize. Currently must be at least 

182 three bands. 

183 stretch: float, optional 

184 The stretch parameter for 

185 astropy.visualization.lupton_rgb. import AsinhMapping 

186 q: float, optional 

187 The Q parameter for 

188 astropy.visualization.lupton_rgb. import AsinhMapping 

189 """ 

190 

191 if isinstance(model, list): 

192 mold = model 

193 model = copy_mbexp(mbexp) 

194 for iband, band in enumerate(model.bands): 

195 model[band].image.array[:, :] = mold[iband] 

196 

197 fig, axs = mplt.subplots(nrows=2, ncols=2, figsize=(12, 12)) 

198 show_mbexp( 

199 mbexp, stretch=stretch, q=q, mess='data', ax=axs[0, 0], show=False, 

200 sources=sources, 

201 ) 

202 show_mbexp( 

203 model, stretch=stretch, q=q, mess='model', ax=axs[0, 1], show=False, 

204 sources=sources, 

205 ) 

206 axs[1, 1].axis('off') 

207 

208 c = copy_mbexp(mbexp) 

209 c.image.array -= model.image.array 

210 show_mbexp( 

211 c, stretch=stretch, q=q, mess='data - model', ax=axs[1, 0], show=False, 

212 sources=sources, 

213 ) 

214 mplt.show() 

215 

216 

217def show_three_mbexp( 

218 mbexp_list, 

219 labels=None, 

220 stretch=DEFAULT_STRETCH, q=DEFAULT_Q, mess=None, ax=None, 

221): 

222 """ 

223 show three different MultibandExposure 

224 

225 Parameters 

226 ---------- 

227 mbexp_list: [lsst.afw.image.MultibandExposure] 

228 List of MutibandExposure to visualize. Currently must be at least 

229 three bands. 

230 labels: list, optional 

231 Listof labels for a legend 

232 stretch: float, optional 

233 The stretch parameter for 

234 astropy.visualization.lupton_rgb. import AsinhMapping 

235 q: float, optional 

236 The Q parameter for 

237 astropy.visualization.lupton_rgb. import AsinhMapping 

238 ax: matplotlib plot axis 

239 If sent use this axis for plot rather than creating a 

240 new one 

241 mess: str, optional 

242 A message to use as title to plot 

243 """ 

244 

245 assert len(mbexp_list) == 3 

246 if labels is None: 

247 labels = ['image 1', 'image 2', 'image 3'] 

248 assert len(labels) == 3 

249 

250 fig, axs = mplt.subplots(nrows=2, ncols=2, figsize=(12, 12)) 

251 show_mbexp( 

252 mbexp_list[0], stretch=stretch, q=q, ax=axs[0, 0], show=False, 

253 mess=labels[0], 

254 ) 

255 show_mbexp( 

256 mbexp_list[1], stretch=stretch, q=q, ax=axs[0, 1], show=False, 

257 mess=labels[1], 

258 ) 

259 show_mbexp( 

260 mbexp_list[2], stretch=stretch, q=q, ax=axs[1, 0], show=False, 

261 mess=labels[2], 

262 ) 

263 axs[1, 1].axis('off') 

264 

265 mplt.show() 

266 

267 

268def show_mbexp_demo(mbexp): 

269 """ 

270 Show a few stretches, q values. Useful for choosing the stretch 

271 you would like 

272 

273 Parameters 

274 ---------- 

275 mbexp: lsst.afw.image.MultibandExposure 

276 MutibandExposure to visualize. Currently must be at least 

277 three bands. 

278 """ 

279 from astropy.visualization.lupton_rgb import AsinhMapping 

280 import scarlet 

281 

282 image = mbexp.image.array 

283 

284 # TODO repeat bands as needed 

285 assert image.shape[0] >= 3, 'need at least 3 exposure for color' 

286 

287 # stretches = [0.1, 0.5, 1.0] 

288 # qvals = [10, 20, 30] # noqa 

289 stretches = [0.75, 1, 1.25] 

290 qvals = [5, 7.5, 10] # noqa 

291 

292 fig, axs = mplt.subplots(len(stretches), len(qvals), figsize=(12, 12)) 

293 for ist, stretch in enumerate(stretches): 

294 for iq, q in enumerate(Qvals): # noqa 

295 asinh = AsinhMapping( 

296 minimum=0, 

297 stretch=stretch, Q=q, 

298 ) 

299 img_rgb = scarlet.display.img_to_rgb(image, norm=asinh) 

300 axs[ist, iq].imshow(img_rgb) 

301 axs[ist, iq].set_title(f'Stretch {stretch}, Q {q}') 

302 

303 mplt.show() 

304 

305 

306def show_multi_mbobs(mbobs): 

307 """ 

308 Show images from a ngmix.MultiBandObsList 

309 

310 Parameters 

311 ---------- 

312 mbobs: ngmix.MultiBandObsList 

313 The data 

314 """ 

315 import matplotlib.pyplot as mplt 

316 

317 nband = len(mbobs) 

318 

319 types = ['image', 'weight', 'bmask'] 

320 ntypes = len(types) 

321 fig, axs = mplt.subplots(nrows=ntypes, ncols=nband) 

322 

323 for iband, obslist in enumerate(mbobs): 

324 

325 obs = obslist[0] 

326 

327 for itype, type in enumerate(types): 

328 

329 im = getattr(obs, type) 

330 

331 axs[iband, itype].imshow(im) 

332 axs[iband, itype].set_title(f'band {iband} {type}') 

333 

334 mplt.show() 

335 

336 

337def show_multi_mbexp(mbexp, sources=None): 

338 """ 

339 Show images from a ngmix.MultiBandObsList 

340 

341 Parameters 

342 ---------- 

343 mbexp: lsst.afw.image.MultibandExposure 

344 The data 

345 """ 

346 import matplotlib.pyplot as mplt 

347 

348 nband = len(mbexp) 

349 

350 ncols = 3 

351 fig, axs = mplt.subplots(nrows=nband, ncols=ncols, squeeze=False) 

352 

353 if sources is not None: 

354 x, y = _extract_xy(mbexp, sources) 

355 

356 for iband, band in enumerate(mbexp.bands): 

357 exp = mbexp[band] 

358 

359 noise = np.sqrt(np.median(exp.variance.array)) 

360 minval = 0.1 * noise 

361 axs[iband, 0].imshow(np.log(exp.image.array.clip(min=minval))) 

362 axs[iband, 0].set_title(f'band {iband} image') 

363 

364 axs[iband, 1].imshow(exp.variance.array) 

365 axs[iband, 1].set_title(f'band {iband} var') 

366 

367 axs[iband, 2].imshow(exp.mask.array) 

368 axs[iband, 2].set_title(f'band {iband} mask') 

369 

370 if sources is not None: 

371 for col in range(ncols): 

372 axs[iband, col].scatter( 

373 x, y, 

374 s=SIZE, color=COLOR, edgecolor=EDGECOLOR, 

375 ) 

376 

377 mplt.show() 

378 

379 

380def show_image_and_mask(mbexp, band=0): 

381 """ 

382 Show images from a ngmix.MultiBandObsList 

383 

384 Parameters 

385 ---------- 

386 mbexp: lsst.afw.image.MultibandExposure 

387 The data 

388 """ 

389 import matplotlib.pyplot as mplt 

390 

391 fig, axs = mplt.subplots(ncols=2) 

392 axs[0].axis('off') 

393 axs[1].axis('off') 

394 

395 bname = mbexp.bands[band] 

396 exp = mbexp[bname] 

397 

398 noise = np.sqrt(np.median(exp.variance.array)) 

399 minval = 0.1 * noise 

400 axs[0].imshow(np.log(exp.image.array.clip(min=minval))) 

401 axs[1].imshow(exp.mask.array) 

402 mplt.show()