import%20marimo%0A%0A__generated_with%20%3D%20%220.15.2%22%0Aapp%20%3D%20marimo.App(width%3D%22columns%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22We%20provide%20an%20example%20of%20optimal%20detection%20(as%20defined%20in%20%5BMercier%20et%20al.%2C%202015%5D(%5Bhttps%3A%2F%2Fui.adsabs.harvard.edu%2Fabs%2F2015ApJ...805...15M%2Fabstract%5D(https%3A%2F%2Fui.adsabs.harvard.edu%2Fabs%2F2025arXiv250613881M%2Fabstract)))%20using%20one%20of%20the%20galaxies%20studied%20in%20the%20paper.%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20%20%20astropy.visualization.mpl_normalize%20import%20simple_norm%0A%20%20%20%20from%20%20%20astropy.cosmology%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20import%20FlatLambdaCDM%0A%0A%20%20%20%20import%20marimo%20%20%20%20%20%20%20%20%20%20%20%20as%20mo%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20astropy.io.fits%20%20%20as%20fits%0A%20%20%20%20import%20numpy%20%20%20%20%20%20%20%20%20%20%20%20%20as%20np%0A%20%20%20%20import%20pathlib%0A%20%20%20%20import%20finder%0A%0A%20%20%20%20plt.style.use('default')%0A%0A%20%20%20%20path%20%3D%20pathlib.Path('data')%0A%20%20%20%20return%20FlatLambdaCDM%2C%20finder%2C%20fits%2C%20mo%2C%20np%2C%20path%2C%20plt%2C%20simple_norm%0A%0A%0A%40app.cell%0Adef%20_(fits%2C%20path)%3A%0A%20%20%20%20idd%20%20%20%20%20%20%3D%2056%0A%20%20%20%20redshift%20%3D%201.6833%0A%0A%20%20%20%20%23%20Open%20image%0A%20%20%20%20with%20fits.open(path%20%2F%20'images'%20%2F%20f'%7Bidd%7D_f444w.fits')%20as%20hdul%3A%0A%20%20%20%20%20%20%20%20image%20%3D%20hdul%5B0%5D.data%0A%0A%20%20%20%20%23%20Open%20model%0A%20%20%20%20with%20fits.open(path%20%2F%20'models'%20%2F%20f'%7Bidd%7D_f444w.fits')%20as%20hdul%3A%0A%20%20%20%20%20%20%20%20model%20%3D%20hdul%5B0%5D.data%0A%0A%20%20%20%20%23%20Open%20segmentation%20map%0A%20%20%20%20with%20fits.open(path%20%2F%20'segmentation'%20%2F%20f'%7Bidd%7D.fits')%20as%20hdul%3A%0A%20%20%20%20%20%20%20%20segmap%20%3D%20hdul%5B0%5D.data%0A%20%20%20%20return%20image%2C%20model%2C%20redshift%2C%20segmap%0A%0A%0A%40app.cell%0Adef%20_(plt)%3A%0A%20%20%20%20def%20show_im(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20ax_loc%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20im%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20seg%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20cmap%20%20%20%20%20%20%20%3D%20'plasma'%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20norm%20%20%20%20%20%20%20%3D%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20title%20%20%20%20%20%20%3D%20''%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mask_bulge%20%3D%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colors%20%20%20%20%20%3D%20'k'%0A%20%20%20%20%20%20%20%20)%3A%0A%0A%20%20%20%20%20%20%20%20%23%20Showing%20the%20galaxy%0A%20%20%20%20%20%20%20%20ax%20%3D%20f.add_subplot(ax_loc)%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20plt.imshow(%0A%20%20%20%20%20%20%20%20%20%20%20%20im%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20origin%20%3D%20'lower'%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20cmap%20%20%20%3D%20cmap%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20norm%20%20%20%3D%20norm%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20plt.contour(seg%2C%20origin%3D'lower'%2C%20colors%3Dcolors)%0A%0A%20%20%20%20%20%20%20%20if%20mask_bulge%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20plt.contour(mask_bulge%2C%20origin%3D'lower'%2C%20colors%3Dcolors%2C%20linestyles%3D'--')%0A%0A%20%20%20%20%20%20%20%20ax.set_title(title)%0A%0A%20%20%20%20%20%20%20%20return%20ax%0A%20%20%20%20return%20(show_im%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%20Visualising%20the%20image%2C%20model%2C%20and%20residuals%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(image%2C%20model%2C%20plt%2C%20segmap%2C%20show_im%2C%20simple_norm)%3A%0A%20%20%20%20f%20%20%20%3D%20plt.figure(figsize%3D(15%2C%205))%0A%20%20%20%20axs%20%3D%20%5B%5D%0A%0A%20%20%20%20%23%20Showing%20the%20galaxy%2C%20model%2C%20and%20residuals%0A%20%20%20%20norm%20%3D%20simple_norm(image%2C%20stretch%3D'sqrt'%2C%20percent%3D99.9)%0A%0A%20%20%20%20axs.append(show_im(f%2C%20131%2C%20image%2C%20%20%20%20%20%20%20%20%20segmap%2C%20norm%20%3D%20norm%2C%20title%3D'Cutout'))%0A%20%20%20%20axs.append(show_im(f%2C%20132%2C%20model%2C%20%20%20%20%20%20%20%20%20segmap%2C%20norm%20%3D%20norm%2C%20title%3D'Model'))%0A%20%20%20%20axs.append(show_im(f%2C%20133%2C%20image%20-%20model%2C%20segmap%2C%20norm%20%3D%20norm%2C%20title%3D'Residuals'))%0A%0A%20%20%20%20for%20ax%20in%20axs%3A%0A%20%20%20%20%20%20%20%20ax.tick_params(direction%3D'in'%2C%20right%3DTrue%2C%20top%3DTrue%2C%20labelleft%3DFalse%2C%20labelbottom%3DFalse)%0A%0A%20%20%20%20plt.show()%0A%20%20%20%20return%20(norm%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%20Compute%20the%20local%20%242%5Csigma%24%20flux%20threhsold%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(finder%2C%20image%2C%20model%2C%20segmap)%3A%0A%20%20%20%20thr%20%3D%20finder.bg_threshold_n_sigma(%0A%20%20%20%20%20%20%20%20image%2C%0A%20%20%20%20%20%20%20%20model%2C%0A%20%20%20%20%20%20%20%20segmap%20%3D%3D%200%2C%0A%20%20%20%20%20%20%20%20n_sigma%20%3D%202%0A%20%20%20%20)%0A%0A%20%20%20%20print(thr)%0A%20%20%20%20return%20(thr%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%20Produce%20a%20%241%5C%2C%5Crm%20kpc%24%20mask%20to%20hide%20the%20bulge%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(FlatLambdaCDM%2C%20finder%2C%20image%2C%20np%2C%20redshift)%3A%0A%20%20%20%20center%20%20%20%20%20%3D%20np.array(image.shape)%20%2F%2F%202%0A%0A%20%20%20%20mask_bulge%20%3D%20finder.generate_bulge_mask(%0A%20%20%20%20%20%20%20%20center%5B0%5D%2C%20center%5B1%5D%2C%20redshift%2C%0A%20%20%20%20%20%20%20%20image.shape%2C%0A%20%20%20%20%20%20%20%20FlatLambdaCDM(70%2C%200.3)%2C%0A%20%20%20%20%20%20%20%20radius_kpc%20%3D%201%2C%0A%20%20%20%20%20%20%20%20pix_size%20%20%20%3D%200.03%0A%20%20%20%20)%0A%20%20%20%20return%20center%2C%20mask_bulge%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%20Perform%20the%20optimal%20detection%20in%20the%20residuals%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(center%2C%20finder%2C%20image%2C%20mask_bulge%2C%20segmap)%3A%0A%20%20%20%20%23%20Recover%20the%20value%20in%20the%20segmentation%20map%20corresponding%20to%20the%20galaxy%0A%20%20%20%20gal_val%20%3D%20segmap%5Bcenter%5B0%5D%2C%20center%5B1%5D%5D%0A%0A%20%20%20%20%23%20Setup%20the%20substructure%20finder%0A%20%20%20%20cf%20%3D%20finder.ClumpFinder(%0A%20%20%20%20%20%20%20%20image%2C%0A%20%20%20%20%20%20%20%20mask%20%3D%20segmap%20%3D%3D%20gal_val%2C%0A%20%20%20%20%20%20%20%20mask_bg%20%20%20%20%3D%20segmap%20%3D%3D%200%2C%0A%20%20%20%20%20%20%20%20mask_bulge%20%3D%20mask_bulge%0A%20%20%20%20)%0A%20%20%20%20return%20(cf%2C)%0A%0A%0A%40app.cell%0Adef%20_(cf%2C%20model%2C%20thr)%3A%0A%20%20%20%20%23%20Run%20the%20substructure%20finder%0A%20%20%20%20sub_segmap%20%3D%20cf.detect(model%2C%20thr%2C%2020)%0A%20%20%20%20return%20(sub_segmap%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20Note%20that%2C%20by%20default%20the%20algorithm%20detects%20positive%20and%20negative%20substructures.%20In%20the%20paper%2C%20we%20only%20considered%20positive%20ones%2C%20that%20is%20over-densities%20with%20respect%20to%20the%20model.%20%0A%20%20%20%20In%20what%20follows%2C%20we%20discard%20negative%20substructures.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(sub_segmap)%3A%0A%20%20%20%20sub_segmap%5Bsub_segmap%20%3C%200%5D%20%3D%200%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(image%2C%20mask_bulge%2C%20mo%2C%20model%2C%20norm%2C%20plt%2C%20segmap%2C%20show_im%2C%20sub_segmap)%3A%0A%20%20%20%20f2%20%20%20%3D%20plt.figure(figsize%3D(8%2C%208))%0A%20%20%20%20axs2%20%3D%20%5B%5D%0A%0A%20%20%20%20%23%20For%20each%20plot%2C%20we%20add%20the%20bulge%20mask%0A%20%20%20%20axs2.append(show_im(f2%2C%20221%2C%20image%2C%20%20%20%20%20%20%20%20%20segmap%2C%20norm%20%3D%20norm%2C%20title%3D'Cutout'%2C%20mask_bulge%20%3D%20mask_bulge%2C%20colors%3D'w'))%0A%20%20%20%20axs2.append(show_im(f2%2C%20222%2C%20model%2C%20%20%20%20%20%20%20%20%20segmap%2C%20norm%20%3D%20norm%2C%20title%3D'Model'%2C%20mask_bulge%20%3D%20mask_bulge%2C%20colors%3D'w'))%0A%20%20%20%20axs2.append(show_im(f2%2C%20223%2C%20image%20-%20model%2C%20segmap%2C%20norm%20%3D%20norm%2C%20title%3D'Residuals'%2C%20mask_bulge%20%3D%20mask_bulge%2C%20colors%3D'w'))%0A%20%20%20%20axs2.append(show_im(f2%2C%20224%2C%20sub_segmap%2C%20%20%20%20segmap%2C%20cmap%20%3D%20'gnuplot2'%2C%20title%3D'Substructures'%2C%20mask_bulge%20%3D%20mask_bulge%2C%20colors%3D'w'))%0A%0A%20%20%20%20for%20ax2%20in%20axs2%3A%0A%20%20%20%20%20%20%20%20ax2.tick_params(direction%3D'in'%2C%20right%3DTrue%2C%20top%3DTrue%2C%20labelleft%3DFalse%2C%20labelbottom%3DFalse)%0A%0A%20%20%20%20mo.vstack(%5Bf2%5D)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
8798232bb987d6008057de147e8c07de2ce0768ebb5ebd8443d7d4acc58b5d41