206.1. Deblender outputs#
206.1. Deblender Outputs¶
For the Rubin Science Platform at data.lsst.cloud.
Data Release: DP1
Container Size: Large
LSST Science Pipelines version: Weekly v29.2.0
Last verified to run: 2025-10-22
Repository: github.com/lsst/tutorial-notebooks
Learning objective: This notebook demonstrates the meaning and basic use of deblender data products cataloged in the Object
table.
LSST data products: Object
table, deep_coadd
Packages: lsst.rsp
, lsst.daf.butler
, lsst.geom
, lsst.afw.display
Credit: Originally developed by Christina Williams and the Rubin Community Science team. This notebook is partly based on DP0.2 notebook 10 on deblender data products, and benefited from helpful discussions with Fred Moolekamp. The deblender packages are based on Melchior et al. 2018, and the Scarlet software written by Peter Melchior and Fred Moolekamp. Further documentation on Scarlet is available at that site.
Get Support: Everyone is encouraged to ask questions or raise issues in the Support Category of the Rubin Community Forum. Rubin staff will respond to all questions posted there.
1. Introduction¶
This notebook is an introduction to the data products in the Object
table that are associated with the deblending process.
In order to build its source catalog and measure photometry of objects in images, the LSST Science Pipeline uses the multi-wavelength deblending algorithm Scarlet (Melchior et al. 2018) to identify independent detected components within source blends and separate the flux from independent objects.
A "parent" source is identified as a region of connected pixels above a given signal-to-noise ratio (S/N) in the deepCoadd
image.
These regions are called footprints.
Each footprint may have one or more peaks, which the deblender uses to
infer the number and positions of objects blended in each footprint.
The deblended sub-peaks are referred to as "children" of the parent in the properties saved by the deblender in the Object
table.
The Scarlet deblender separates the flux among components by modeling the flux and shape of each source making up the blend.
This tutorial will identify a heavily blended parent object with many
children and explore how to interpret the deblender-related
measurements in the Object
table. It will also demonstrate how to use deblender-related columns in the Object
table to identify unique deblended child sources, and
provide an example of how to access metadata that is available for each
deblended source (e.g. the deblended footprints and pixel-weight maps).
Note: There have been updates to the deblending implementation since DP1 so expect the API to be slightly different (improved) in future data releases, including having more information available to understand how blended an object is with its neighbors and useful cuts to remove potentially more difficult blends from analysis.
References:
- An introduction to all of the available deblending flags, and the processes that produce the deblender data products discussed in this tutorial can be found in this overview of the deblending flags.
- A general discussion of blending impacts to LSST can be found in this article titled "The challenge of blending in large sky surveys" by Melchior et al. 2021.
- Some more in-depth presentations on the deblending implementation in the LSST Science Pipelines are available from recorded talks during the Rubin Project and Community Workshop 2022's session on "Deblending Plans and Challenges".
Related tutorials: A notebook demonstrating how to work with blend footprints is available as 206.2 Deblender footprints.
1.1. Import packages¶
The matplotlib (and especially sublibrary matplotlib.pyplot
), numpy, and astropy libraries are widely used Python libraries for plotting, scientific computing, and astronomical data analysis.
The lsst.rsp
package provides access to the Table Access Protocol (TAP) service for queries to the DP0 catalogs.
The lsst.afw.display
library provides access to image visualization routines and the lsst.daf.butler
library is used to access data products via the butler.
import numpy as np
import matplotlib.pyplot as plt
from lsst.daf.butler import Butler
from lsst.rsp import get_tap_service
import lsst.geom as geom
import lsst.afw.display as afwDisplay
1.2. Define functions and parameters¶
The following cutout_coadd
function enables the visualization of deblended products by making a cutout.
def cutout_coadd(butler, ra, dec, band='r', datasetType='deepCoadd',
skymap=None, cutoutSideLength=51, **kwargs):
"""
Produce a cutout from a coadd at the given ra, dec position.
Adapted from DC2 tutorial notebook by Michael Wood-Vasey.
Parameters
----------
butler: lsst.daf.persistence.Butler
Helper object providing access to a data repository
ra: float
Right ascension of the center of the cutout, in degrees
dec: float
Declination of the center of the cutout, in degrees
band: string
Filter of the image to load
datasetType: string ['deepCoadd']
Which type of coadd to load. Doesn't support 'calexp'
skymap: lsst.afw.skyMap.SkyMap [optional]
Pass in to avoid the Butler read. Useful if you have lots of them.
cutoutSideLength: float [optional]
Size of the cutout region in pixels.
Returns
-------
MaskedImage
"""
radec = geom.SpherePoint(ra, dec, geom.degrees)
cutoutSize = geom.ExtentI(cutoutSideLength, cutoutSideLength)
if skymap is None:
skymap = butler.get("skyMap")
tractInfo = skymap.findTract(radec)
patchInfo = tractInfo.findPatch(radec)
xy = geom.PointI(tractInfo.getWcs().skyToPixel(radec))
bbox = geom.BoxI(xy - cutoutSize // 2, cutoutSize)
print("bbox = ", bbox, "xy = ", xy, "cutoutSize = ", cutoutSize)
patch = tractInfo.getSequentialPatchIndex(patchInfo)
tract = tractInfo.getId()
parameters = {'bbox': bbox}
query = """band.name = '{}' AND patch = {} AND tract = {}
""".format('i', patch, tract)
print(query)
dataset_refs = butler.query_datasets("deep_coadd", where=query)
cutout_image = butler.get(dataset_refs[0], parameters=parameters)
return cutout_image
Set the backend for afwDisplay to matplotlib.
afwDisplay.setDefaultBackend('matplotlib')
Get an instance of the TAP service, and assert that it exists.
service = get_tap_service("tap")
assert service is not None
Instantiate the butler.
butler = Butler('dp1', collections="LSSTComCam/DP1")
assert butler is not None
2. The deblender data products¶
The object catalog contains a number of columns that can be used to identify and characterize blended objects in the deepCoadd
images. Prior to deblending, blends are identified (referred to as
parents), and are then deblended into child objects by the LSST
deblender package, Scarlet Lite. Only the children are ultimately stored
in the Object
table; the parent objects are excluded. Of
course, isolated single sources that do not require deblending are also
stored in the Object
table and are not considered parent sources.
In this tutorial we will focus on the deblending data products for objects stored in the Object
table.
The following describes key parameters in the Object
table: 1) boolean flags that are set by the deblender, Scarlet Lite; 2)
measurements or properties of deblended sources that can be used to
characterize (de)blended sources; 3) blendedness metrics performed after
the deblender completes; 4) obsolete keywords still present in the Object
table.
Scarlet blend flags:
detect_fromBlend
(boolean): If True, this source is deblended from a parent with more than one child.
detect_isIsolated
(boolean): If True, this source was not part of a blend.
Scarlet Lite blend measurements:
parentObjectId
(long): Unique ID of parent source.
footprintArea
(int): Number of pixels in the deblended object's detection "footprint", in the "reference band".
<f>_deblend_fluxOverlap
(dbl): The total flux from neighboring objects that overlaps with this sources footprint in the deconvolved space. See also <f>_deblend_fluxOverlapFraction
Fraction of flux from neighbors / source flux in the deconvolved footprint.
Blendedness parameters:
<f>_blendedness
(dbl): For each filter (f = u, g,
r, i, z, or y), a measure of how much the flux is affected by neighbors,
(1 - child_flux/parent_flux). The measurement is in the observed, not
point spread function (PSF)-deconvolved space. Operates on the absolute
value of the pixels to try to obtain a de-noised value. These are not
performed by the deblender (Scarlet Lite) but rather from a blendedness
algorithm (see section 4.9.11 of Bosch et al. 2018, PASJ, 70, S5 for details).
<f>_deblend_blendedness
(dbl): Blendedness in filter
<f>_blendedness_flag
(boolean): Flag set for any failure in the blendedness algorithm.
Obsolete or non-informative parameters:
deblend_failed
(boolean): Deblender failed to deblend
this source. Note that in DP1, only child objects that were successfully
deblended will appear in the Object
table. Thus, parent
objects which failed to deblend are not included, and this flag is
always 0. In future data releases, a parent catalog may exist with
informative keywords for the deblender's performance.
In addition to deblend_failed
, the following columns from DP0.2 have now been deprecated, although still appear in the Object
table (artifacts from when the parents were included in the same catalog). This includes deblend_nChild
,
which was a property of parents but does not contain useful information
in DP1 because the parent blends themselves are now excluded from the Object
table. Similarly, deblend_nPeaks
,
which used to contain the number of peaks a parent object has in DP0.2,
still appears in DP1, but always contains the value 1 because only
child objects are in the Object
table.
2.1. Identify blended objects¶
As with all explorative TAP queries searching for examples, it is essential to first start with a small area while developing queries (to confirm the query is good), and then iteratively increase the area as needed (because the full query could take hours without any spatial constraint on the search). This is because the tables are indexed by Right Ascension and declination coordinates (R.A., Dec) and queries with constraints only on measurement columns (such as deblending-related parameters) are inefficient. In other words, Qserv (the backend hosting the TAP-accessible tables) is "spatially sharded".
Set the location for the query to be in the center of the Extended Chandra Deep Field South (ECDFS) field.
ra = 53.2
dec = -28.1
Query for objects in a small region of ECDFS for exploration of the deblender data products stored in the Object
table.
query = "SELECT objectId, coord_ra, coord_dec, x, y, tract, patch, " + \
"refExtendedness, detect_fromBlend, detect_isIsolated, " + \
"parentObjectId, deblend_failed, i_deblend_fluxOverlapFraction, " + \
"footprintArea, i_blendedness, i_deblend_blendedness, i_blendedness_flag " + \
"FROM dp1.Object " + \
"WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec ), " + \
"CIRCLE('ICRS', " + str(ra) + ", " + str(dec) + ", .1)) = 1 "
Run the TAP query.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('Job phase is', job.phase)
Job phase is COMPLETED
Store the resulting objects and columns from the Object
table to a table called results.
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
2.2. Identify isolated objects¶
A sample of objects that are not near any neighbors, and therefore were not deblended, can be identified using the detect_isIsolated
keyword. Similarly, a set of objects that were identified as part of a blend can be identified using the detect_fromBlend
keyword.
whiso = np.where(results['detect_isIsolated'] == 1)[0]
whblend = np.where(results['detect_fromBlend'] == 1)[0]
Generate a cutout of the i-band deep_coadd
imaging that
overlaps the queried objects, centered at (RA, Dec) = 53.11, -28.07
degrees, with a cutout edge size of 200 pixels.
cutout = cutout_coadd(butler, 53.11, -28.07,
band='i', datasetType='deepCoadd',
cutoutSideLength=200)
bbox = (minimum=(14543, 5011), maximum=(14742, 5210)) xy = (14643, 5111) cutoutSize = (200, 200) band.name = 'i' AND patch = 14 AND tract = 5063
Display the cutout with isolated objects identified by red circles
and objects that were identified from blends identified as cyan plus
signs. To ensure that afwDisplay
will make the low surface
brightness connecting the blends together visible, set the scale to
linear, set the min and max pixel values to be relatively low and also
indicate with units=Absolute that these should be in actual count units.
fig = plt.figure(figsize=(6, 6))
display = afwDisplay.Display(frame=fig)
display.scale('linear', min=0.1, max=10, unit='Absolute')
display.mtv(cutout.image)
with display.Buffering():
for ci in range(len(whiso)):
display.dot('o', results['x'][whiso][ci], results['y'][whiso][ci],
size=10, ctype=afwDisplay.RED)
for ci in range(len(whblend)):
display.dot('+', results['x'][whblend][ci], results['y'][whblend][ci],
size=8, ctype=afwDisplay.CYAN)
plt.gca().axis('off')
display.show_colorbar(False)
plt.show()
Figure 1: The cutout image displayed in greyscale, with cyan + marking objects that are blended in the
deep_coadd
, red circles marking objects that are isolated (and is not part of a blend).
3. Explore blended objects¶
Use the TAP service to find a group of objects that were heavily blended and part of the same parent object.
3.1. Blend with several children¶
First, identify a set of unique parentObjectIds
, and the number of objects that are deblended from those parentObjectId
s, (stored as counts
). Then, select as an example a blend that was made up of 15 children.
To identify the most blended object in the query, replace the second code line with:
most_common_index_in_unique = np.argmax(counts)
unique_IDs, counts = np.unique(results['parentObjectId'], return_counts=True)
most_common_index_in_unique = np.where(counts == 15)[0]
most_common_value = unique_IDs[most_common_index_in_unique[0]]
whparent = np.where(results['parentObjectId'] == most_common_value)[0]
max_parentId = results['parentObjectId'][whparent][0]
Use TAP to retrieve all children for the selected parent.
query = "SELECT objectId, coord_ra, coord_dec, x, y, parentObjectId, i_blendedness_flag, " + \
"i_cModelFlux/i_cModelFluxErr AS i_S2N, footprintArea, i_deblend_blendedness, " + \
"i_blendedness, deblend_failed, i_deblend_fluxOverlap, i_deblend_fluxOverlapFraction " + \
"FROM dp1.Object " + \
"WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec ), " + \
"CIRCLE('ICRS', " + str(ra) + ", " + str(dec) + ", .1)) = 1 " + \
"AND parentObjectId = " + str(max_parentId)
Run the TAP query.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('Job phase is', job.phase)
Job phase is COMPLETED
Store the query results in a table called children.
assert job.phase == 'COMPLETED'
children = job.fetch_result().to_table()
children
objectId | coord_ra | coord_dec | x | y | parentObjectId | i_blendedness_flag | i_S2N | footprintArea | i_deblend_blendedness | i_blendedness | deblend_failed | i_deblend_fluxOverlap | i_deblend_fluxOverlapFraction |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
deg | deg | pix | pix | pix | |||||||||
int64 | float64 | float64 | float64 | float64 | int64 | bool | float64 | int32 | float32 | float32 | bool | float32 | float32 |
611254316728073284 | 53.294864915499765 | -28.126076964734423 | 11707.922594133186 | 4098.302973641447 | 611254316728059699 | False | 7.096778393068185 | 1127 | 0.0 | 0.0466138 | False | 0.0 | 0.0 |
611254316728073280 | 53.30000004299527 | -28.127485719212654 | 11626.443568882292 | 4072.8016766671863 | 611254316728059699 | False | 7.809782722792145 | 597 | 0.0 | 0.0271333 | False | 0.0 | 0.0 |
611254316728073281 | 53.29739851633408 | -28.127993986892044 | 11667.758939611198 | 4063.7235506255665 | 611254316728059699 | True | -0.019130034522410754 | 454 | 0.0 | -- | False | 0.0 | 0.0 |
611254316728073282 | 53.296165745419366 | -28.128734914905575 | 11687.351831657825 | 4050.4189893817747 | 611254316728059699 | False | 7.423539277962396 | 1162 | 0.0246679 | 0.266039 | False | 3.46231 | 0.0168952 |
611254316728073283 | 53.29660129461913 | -28.125536808717257 | 11680.340399977047 | 4107.979685606347 | 611254316728059699 | False | 7.419048613431707 | 881 | 0.0 | 0.0227583 | False | 0.0 | 0.0 |
611254316728073279 | 53.295658871229705 | -28.125294285218384 | 11695.29454317496 | 4112.371287173421 | 611254316728059699 | True | -0.06455831873487836 | 422 | 0.0 | -- | False | 0.0 | 0.0 |
611254316728073285 | 53.2967491477205 | -28.129172760001698 | 11678.103579404262 | 4042.5209388886897 | 611254316728059699 | True | 6.25844073372527 | 993 | 0.0102184 | 0.103867 | False | 38.0434 | 0.196383 |
611254316728073286 | 53.29294969335254 | -28.12786049935853 | 11738.380787078966 | 4066.2472628100695 | 611254316728059699 | False | 5.4996531838805645 | 388 | 0.0 | 0.057179 | False | 0.0 | 0.0 |
611254316728073287 | 53.29414955777493 | -28.126644370416713 | 11719.296237432669 | 4088.1078306569243 | 611254316728059699 | False | 3.561928011397123 | 608 | 0.0 | 0.618377 | False | 0.0 | 0.0 |
611254316728073273 | 53.29566789404083 | -28.127286563178075 | 11695.211494752568 | 4076.505898078906 | 611254316728059699 | False | 983.0246787788672 | 3793 | 0.00166738 | 0.00233513 | False | 2336.91 | 0.059042 |
611254316728073274 | 53.29411430010412 | -28.127641516595084 | 11719.885868289113 | 4070.158073828561 | 611254316728059699 | False | 180.3119748899455 | 2401 | 0.048463 | 0.0133469 | False | 5735.77 | 0.996521 |
611254316728073275 | 53.299318362969274 | -28.127070560818673 | 11637.252647255584 | 4080.2942815238393 | 611254316728059699 | False | 29.476632628687174 | 898 | 0.0 | 0.00107619 | False | 0.0 | 0.0 |
611254316728073276 | 53.29821288343833 | -28.12659024085694 | 11654.787788395472 | 4088.971541652779 | 611254316728059699 | False | 13.644255885327834 | 848 | 0.0 | 0.000571488 | False | 0.0 | 0.0 |
611254316728073277 | 53.29420641670363 | -28.12891471823645 | 11718.46169470667 | 4047.235296448674 | 611254316728059699 | False | 11.529717469086624 | 904 | 0.0 | 0.00755404 | False | 0.0 | 0.0 |
611254316728073278 | 53.29670099675805 | -28.128213784960245 | 11678.83885814897 | 4059.7858143524772 | 611254316728059699 | False | 9.164728767215426 | 1381 | 0.0115476 | 0.0656418 | False | 33.8051 | 0.16126 |
The table above confirms that the children returned by the query were
deblended from the same parent source, since they all show the same parentObjectId
.
A single source is identified with high i_deblend_fluxOverlapFraction
(i.e. flux contribution from neighbors) of almost 62%. Note however
that in this case, the deblender indicates that the deblended flux is
uncontaminated in the PSF-decovolved space, i_deblend_blendedness
= 0, and the blendedness flag returns False, indicating this object was
successfully deblended. However, these blendedness metrics before and
after deblending can assist in quality assessment.
Below, identify this child with heavy blendedness of 50%.
whheavy = np.where(children['i_blendedness'] > 0.5)[0]
children[whheavy]
objectId | coord_ra | coord_dec | x | y | parentObjectId | i_blendedness_flag | i_S2N | footprintArea | i_deblend_blendedness | i_blendedness | deblend_failed | i_deblend_fluxOverlap | i_deblend_fluxOverlapFraction |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
deg | deg | pix | pix | pix | |||||||||
int64 | float64 | float64 | float64 | float64 | int64 | bool | float64 | int32 | float32 | float32 | bool | float32 | float32 |
611254316728073287 | 53.29414955777493 | -28.126644370416713 | 11719.296237432669 | 4088.1078306569243 | 611254316728059699 | False | 3.561928011397123 | 608 | 0.0 | 0.618377 | False | 0.0 | 0.0 |
Next, visualize these test cases along with the other child sources of this parentObjectId
. Use the cutout_coadd
function to obtain a cutout image to visualize the blend. Set the size of the cutout to be 2x the square root of the footprintArea
.
cutout = cutout_coadd(butler, children['coord_ra'][0],
children['coord_dec'][0],
band='i', datasetType='deepCoadd',
cutoutSideLength=2.0
* np.sqrt(np.sum(children['footprintArea'])))
bbox = (minimum=(11579, 3969), maximum=(11837, 4227)) xy = (11708, 4098) cutoutSize = (259, 259) band.name = 'i' AND patch = 13 AND tract = 5063
Display the deepCoadd
cutout made for this parent, with
all deblended children identified with red circles. Identify the
children for which the blendedness metric (before deblending) was 50%
with a cyan circle.
fig = plt.figure(figsize=(6, 6))
display = afwDisplay.Display(frame=fig)
display.scale('linear', min=0.1, max=10, unit='Absolute')
display.mtv(cutout.image)
with display.Buffering():
for ci in range(len(children)):
display.dot('o', children['x'][ci], children['y'][ci],
size=10, ctype=afwDisplay.RED)
for ci in range(len(whheavy)):
display.dot('o', children['x'][whheavy][ci], children['y'][whheavy][ci],
size=8, ctype=afwDisplay.CYAN)
plt.gca().axis('off')
display.show_colorbar(False)
plt.show()
Figure 2: The cutout image displayed in greyscale, with red circles marking the deblended children, cyan circles indicating any children whose contamination from neighbors prior to deblending is high (>50% of flux from a neighbor).
4. Heavy blends¶
It is useful to be able to quantify how much flux in the blended source is attributed to a neighbor. Mandelbaum et al. 2018
quantitatively explored the criteria for acceptable blendedness as a
metric of deblender performance. In this section, explore examples where
sources are heavily contaminated (<f>_blendedness
>50%) by the flux of neighbors, and then compare to the deblended contamination fraction <f>_deblend_blendedness
.
Below, identify which child objects are above this high threshold of PSF-convolved blending, and see what fraction of objects in the catalog meet this criteria.
whheavy = np.where(results['i_blendedness'] > 0.5)[0]
print('Fraction of objects that are heavily blended is', len(whheavy)/len(results))
results[whheavy]
Fraction of objects that are heavily blended is 0.05161951296398455
objectId | coord_ra | coord_dec | x | y | tract | patch | refExtendedness | detect_fromBlend | detect_isIsolated | parentObjectId | deblend_failed | i_deblend_fluxOverlapFraction | footprintArea | i_blendedness | i_deblend_blendedness | i_blendedness_flag |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
deg | deg | pix | pix | pix | ||||||||||||
int64 | float64 | float64 | float64 | float64 | int64 | int64 | float32 | bool | bool | int64 | bool | float32 | int32 | float32 | float32 | bool |
611254385447554247 | 53.119850049117744 | -28.051975483125325 | 14486.0 | 5435.0 | 5063 | 14 | -- | True | False | 611254385447538062 | False | 0.66276 | 524 | 0.516076 | 0.033251 | True |
611254385447554149 | 53.26707422689095 | -28.052525983120294 | 12147.19488817705 | 5423.057028110923 | 5063 | 14 | 1.0 | True | False | 611254385447538011 | False | 0.0 | 646 | 0.659665 | 0.0 | True |
611254385447554100 | 53.11494062961147 | -28.05414302365997 | 14564.0 | 5396.0 | 5063 | 14 | -- | True | False | 611254385447537986 | False | 0.0 | 547 | 0.677394 | 0.0 | True |
611254385447554110 | 53.12217959030314 | -28.05341923831319 | 14449.0 | 5409.0 | 5063 | 14 | -- | True | False | 611254385447537990 | False | 0.00730981 | 746 | 0.839532 | 0.000447392 | True |
611254385447554213 | 53.18551883210311 | -28.05276228387117 | 13442.791494017694 | 5420.278680042868 | 5063 | 14 | 1.0 | True | False | 611254385447538035 | False | 0.0 | 897 | 0.682092 | 0.0 | True |
611254385447554107 | 53.12181583464017 | -28.05216568916782 | 14454.772337652805 | 5431.567466914587 | 5063 | 14 | 1.0 | True | False | 611254385447537990 | False | 0.0 | 627 | 0.544059 | 0.0 | True |
611254385447554211 | 53.18449852208436 | -28.051902637100135 | 13458.9880245452 | 5435.766632426703 | 5063 | 14 | 1.0 | True | False | 611254385447538035 | False | 0.0 | 528 | 1.0 | 0.0 | True |
611254385447554805 | 53.2622516340637 | -28.020704670509932 | 12223.0 | 5996.0 | 5063 | 14 | -- | True | False | 611254385447538197 | False | 0.103061 | 1853 | 0.64032 | 0.00168151 | True |
611254385447554837 | 53.259709153133514 | -28.021629104567182 | 12263.424918675286 | 5979.416326628661 | 5063 | 14 | 0.0 | True | False | 611254385447538197 | False | 0.483975 | 1321 | 0.851791 | 0.0196931 | True |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
611254385447552406 | 53.13923919667152 | -28.073251863620435 | 14178.14221769388 | 5051.8846379722145 | 5063 | 14 | 1.0 | True | False | 611254385447537542 | False | 0.0 | 730 | 0.642831 | 0.0 | False |
611254385447552283 | 53.166290265122754 | -28.063606369646777 | 13748.380048357492 | 5225.289368678812 | 5063 | 14 | 1.0 | True | False | 611254385447537530 | False | 0.0 | 762 | 0.763668 | 0.0 | True |
611254385447552322 | 53.165407612669085 | -28.06412493425716 | 13762.406312760688 | 5215.963375123078 | 5063 | 14 | -- | True | False | 611254385447537530 | False | 0.503917 | 3075 | 0.602695 | 0.0487601 | True |
611254385447552533 | 53.10150455225182 | -28.070266762970615 | 14777.474868149957 | 5105.782963569278 | 5063 | 14 | 0.0 | True | False | 611254385447537604 | False | 0.0 | 543 | 1.0 | 0.0 | True |
611254385447552582 | 53.14907820440253 | -28.069837771559264 | 14021.838873568724 | 5113.271342707839 | 5063 | 14 | 1.0 | True | False | 611254385447537632 | False | 0.39208 | 626 | 0.615249 | 0.00921541 | True |
611254385447552473 | 53.11102953587668 | -28.072315260226656 | 14626.192599131047 | 5068.8833580167775 | 5063 | 14 | 1.0 | True | False | 611254385447537585 | False | 0.0 | 376 | 0.607354 | 0.0 | True |
611254385447552449 | 53.09375744811367 | -28.0725858012339 | 14900.52740424963 | 5064.046597712321 | 5063 | 14 | 0.0 | True | False | 611254385447537565 | False | 0.0 | 311 | 1.0 | 0.0 | True |
611254385447552488 | 53.247432176772186 | -28.072149835301676 | 12459.685567715162 | 5070.229972516796 | 5063 | 14 | 0.0 | True | False | 611254385447537597 | False | 1.71397 | 607 | 0.699938 | 0.111303 | True |
611254454167027841 | 53.087105917175 | -28.099354253839042 | 15006.172415517243 | 4582.170027669604 | 5063 | 15 | -- | True | False | 611254454167013588 | False | 0.0 | 1012 | 0.648493 | 0.0 | True |
fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,
width_ratios=[0.8, 0.2], figsize=(10, 6))
ax.plot(results['i_blendedness'][whheavy], results['i_deblend_blendedness'][whheavy],
'+', alpha=0.5, label='i_blendedness_flag = False')
ax2.hist((results['i_deblend_blendedness'][whheavy]), orientation="horizontal",
bins=np.linspace(0, 1.1, 11), align='left',
histtype="step", color='blue', stacked=True, fill=False, label=None)
ax.legend()
ax.set_ylim([-0.1, 1.1])
ax2.set_ylim([-0.1, 1.1])
ax.set_xlabel('i_blendedness')
ax.set_ylabel('i_deblend_blendedness')
ax2.set_xlabel('Number of objects')
plt.show()
Figure 3: This figure shows the
blendedness
metric (fraction of flux contributed by neighbors) before deblending vs thedeblend_blendedness
metric that identifies the fraction of flux contamination after deblending, for heavily blended objects (>50% flux from one or more neighbors). The right panel shows a histogram of thedeblend_blendedness
, indicating that the deblender is successful at separating flux, such thatdeblend_blendedness
= 0, in the overwhelming majority of objects.
Below, take a closer look at the objects for which the deblender did not effectively separate the flux from neighbors.
wh = np.where((results['i_blendedness'][whheavy] == 1)
& (results['i_deblend_blendedness'][whheavy] == 1))[0]
results[whheavy][wh]
objectId | coord_ra | coord_dec | x | y | tract | patch | refExtendedness | detect_fromBlend | detect_isIsolated | parentObjectId | deblend_failed | i_deblend_fluxOverlapFraction | footprintArea | i_blendedness | i_deblend_blendedness | i_blendedness_flag |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
deg | deg | pix | pix | pix | ||||||||||||
int64 | float64 | float64 | float64 | float64 | int64 | int64 | float32 | bool | bool | int64 | bool | float32 | int32 | float32 | float32 | bool |
611254385447544541 | 53.20949616587542 | -28.172079076941582 | 13064.0 | 3272.0 | 5063 | 14 | -- | True | False | 611254385447534971 | False | 3.03895e+19 | 800 | 1.0 | 1.0 | True |
611254385447544333 | 53.15827111350926 | -28.184446622615013 | 13877.0 | 3050.0 | 5063 | 14 | -- | True | False | 611254385447534885 | False | 4.39223e+21 | 1078 | 1.0 | 1.0 | True |
611254385447549206 | 53.18980321551127 | -28.119724512611672 | 13375.723811530852 | 4214.783959504233 | 5063 | 14 | 0.0 | True | False | 611254385447536499 | False | 1.13236e+20 | 381 | 1.0 | 1.0 | True |
611254385447549812 | 53.12049510141591 | -28.11173172929737 | 14476.038394057774 | 4359.281431858267 | 5063 | 14 | 0.0 | True | False | 611254385447536655 | False | 2.25389e+20 | 825 | 1.0 | 1.0 | True |
611254385447551337 | 53.08850219033574 | -28.09403090209418 | 14984.0 | 4678.0 | 5063 | 14 | -- | True | False | 611254385447537140 | False | 1.46538e+21 | 715 | 1.0 | 1.0 | True |
611254385447553259 | 53.14641831409112 | -28.059632707558045 | 14064.0 | 5297.0 | 5063 | 14 | -- | True | False | 611254385447537876 | False | 1.92496e+20 | 590 | 1.0 | 1.0 | True |
611254385447552110 | 53.17513260519447 | -28.079017674217436 | 13608.120706299507 | 4947.76417469945 | 5063 | 14 | 0.0 | True | False | 611254385447537432 | False | 2.26052e+20 | 509 | 1.0 | 1.0 | True |
Note that by selecting objects where the i_blendedness
and i_deblend_blendedness
metrics are high, the i_deblend_fluxOverlapFraction
is also high. Below, pick one of the above objects which has a high value of i_deblend_fluxOverlapFraction
as an example.
max_parentId = results['parentObjectId'][whheavy][wh][3]
print(max_parentId)
611254385447536655
Define a TAP query that will return all children with the same parentObjectId
as the above source.
query = "SELECT objectId, coord_ra, coord_dec, x, y, parentObjectId, i_blendedness_flag, " + \
"i_cModelFlux/i_cModelFluxErr AS i_S2N, footprintArea, i_deblend_blendedness, " + \
"i_blendedness, deblend_failed, i_deblend_fluxOverlapFraction " + \
"FROM dp1.Object " + \
"WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec ), " + \
"CIRCLE('ICRS', " + str(ra) + ", " + str(dec) + ", .1)) = 1 " + \
"AND parentObjectId = " + str(max_parentId)
Run the TAP query.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('Job phase is', job.phase)
Job phase is COMPLETED
Save the results to a table named bigblend
.
assert job.phase == 'COMPLETED'
bigblend = job.fetch_result().to_table()
bigblend
objectId | coord_ra | coord_dec | x | y | parentObjectId | i_blendedness_flag | i_S2N | footprintArea | i_deblend_blendedness | i_blendedness | deblend_failed | i_deblend_fluxOverlapFraction |
---|---|---|---|---|---|---|---|---|---|---|---|---|
deg | deg | pix | pix | pix | ||||||||
int64 | float64 | float64 | float64 | float64 | int64 | bool | float64 | int32 | float32 | float32 | bool | float32 |
611254385447549797 | 53.1288427976875 | -28.10480712598396 | 14343.457205267834 | 4483.896967629499 | 611254385447536655 | False | 215.44854614877488 | 1163 | 0.0 | 0.00350331 | False | 0.0 |
611254385447549796 | 53.11888362555566 | -28.107791439571333 | 14501.6065137152 | 4430.220912669169 | 611254385447536655 | False | 250.63591035174784 | 2025 | 3.21865e-06 | 0.000266227 | False | 0.000313662 |
611254385447549795 | 53.11611224989274 | -28.113955866474047 | 14545.635880058906 | 4319.260279373383 | 611254385447536655 | False | 322.89613376597396 | 3663 | 0.0793223 | 0.0341204 | False | 0.506552 |
611254385447549794 | 53.11700075484309 | -28.1079685721846 | 14531.503430249773 | 4427.03966030183 | 611254385447536655 | False | 291.69423067404375 | 1563 | 6.4373e-06 | 0.0004873 | False | 0.00192911 |
611254385447549793 | 53.1180600864281 | -28.109246128997558 | 14514.68908284418 | 4404.037068458728 | 611254385447536655 | False | 348.8334477051298 | 3984 | 3.23057e-05 | 9.18724e-06 | False | 0.00858761 |
611254385447549792 | 53.11158995129432 | -28.097739682971145 | 14617.380160351358 | 4611.197577154995 | 611254385447536655 | False | 506.0188839436898 | 3151 | 0.000519693 | 0.000509103 | False | 0.0593205 |
611254385447549791 | 53.12623991171105 | -28.103492711561 | 14384.77949530281 | 4507.572471862002 | 611254385447536655 | False | 757.3897367079634 | 3508 | 0.000226974 | 0.000384537 | False | 0.00732551 |
611254385447549790 | 53.12814080136739 | -28.103523183723958 | 14354.596220940137 | 4507.014080406694 | 611254385447536655 | False | 1352.8618903658546 | 4672 | 6.71744e-05 | 6.82606e-05 | False | 0.0349882 |
611254385447549789 | 53.11828000026783 | -28.112432694459184 | 14511.211557368695 | 4346.671920236903 | 611254385447536655 | False | 2091.330592818051 | 8486 | 0.00108224 | 5.54428e-06 | False | 0.0687492 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
611254385447549832 | 53.125084219842584 | -28.101914774087426 | 14403.12165942666 | 4535.984030352416 | 611254385447536655 | False | 20.910674548838095 | 1365 | 0.0 | 0.0259139 | False | 0.0 |
611254385447549831 | 53.113438156916516 | -28.095569206991563 | 14588.02356178145 | 4650.264074694331 | 611254385447536655 | False | 22.907193688433754 | 1065 | 0.0 | 0.0286494 | False | 0.0 |
611254385447549830 | 53.12218227063278 | -28.111791938258616 | 14449.250843199985 | 4358.190112733937 | 611254385447536655 | False | 34.48630226669729 | 3145 | 0.0340317 | 0.179712 | False | 0.385945 |
611254385447549829 | 53.1318061296595 | -28.106943745200972 | 14296.41795031805 | 4445.417256691017 | 611254385447536655 | False | 22.45457143896183 | 1127 | 0.0 | 0.0013955 | False | 0.0 |
611254385447549828 | 53.11686873975791 | -28.100558805740587 | 14533.568026965002 | 4560.429811437709 | 611254385447536655 | False | 23.334000662629794 | 851 | 0.0 | 0.00102294 | False | 0.0 |
611254385447549827 | 53.11699399268731 | -28.10543098758147 | 14531.599954931451 | 4472.72099149102 | 611254385447536655 | False | 25.66002105212157 | 916 | 0.0 | 0.00145569 | False | 0.0 |
611254385447549826 | 53.12571971486296 | -28.11439955931827 | 14393.099916741849 | 4311.231098268632 | 611254385447536655 | False | 27.86640540363285 | 1213 | 0.00416863 | 0.0188595 | False | 0.0386981 |
611254385447549825 | 53.11654664325399 | -28.110218231774027 | 14538.723255255323 | 4386.5432456915005 | 611254385447536655 | False | 36.848724531259194 | 1432 | 0.00419945 | 0.0242835 | False | 0.0636848 |
611254385447549824 | 53.12443454460638 | -28.101495927169392 | 14413.435494369105 | 4543.527206441226 | 611254385447536655 | False | 28.603272655627084 | 941 | 0.0 | 0.00712143 | False | 0.0 |
Use the cutout_coadd function to request an image cutout of this
blend, and identify any objects which still have 1% of flux contributed
by a neighbor after the deblending process (i_deblend_blendedness
> 0.01).
cutout = cutout_coadd(butler, bigblend['coord_ra'][0],
bigblend['coord_dec'][0],
band='i', datasetType='deepCoadd',
cutoutSideLength=2.0 * np.sqrt(np.sum(bigblend['footprintArea'])))
whheavy = np.where(bigblend['i_deblend_blendedness'] > 0.01)[0]
bbox = (minimum=(13941, 4082), maximum=(14744, 4885)) xy = (14343, 4484) cutoutSize = (804, 804) band.name = 'i' AND patch = 14 AND tract = 5063
fig = plt.figure(figsize=(6, 6))
display = afwDisplay.Display(frame=fig)
display.scale('linear', min=0.01, max=5, unit='Absolute')
display.mtv(cutout.image)
with display.Buffering():
for ci in range(len(bigblend)):
display.dot('o', bigblend['x'][ci], bigblend['y'][ci],
size=10, ctype=afwDisplay.RED)
for ci in range(len(whheavy)):
display.dot('o', bigblend['x'][whheavy][ci], bigblend['y'][whheavy][ci],
size=9, ctype=afwDisplay.CYAN)
plt.gca().axis('off')
display.show_colorbar(False)
plt.show()
Figure 4: This figure shows a heavily blended parent for which deblended objects have a fraction of flux contributed by neighbors (red circles). Cyan circles indicate objects whose
deblend_blendedness
metric is not 0, and remains > 1% contamination even after deblending. They are typically faint objects near the outskirts of the biggest and brightest objects where contamination might be high.
5. Exercises for the learner¶
Use the deblender data products and blend metrics in the Object
table to identify what fraction of sources in ECDFS are contaminated by
neighbor flux at the 5% level in the observed frame? What fraction have
5% flux contamination in the PSF-deconvolved (i.e. deblended) frame?