Advanced topics¶
Specifying a custom structure merging strategy¶
By default, the decision about whether a leaf remains independent (i.e.,
whether it remains a leaf or its pixels get incorporated into another branch)
when merged is made based on the min_delta
and min_npix
parameters, but
in some cases, you may want to use more specialized criteria. For example, you
may want only leaves overlapping with a certain position, or you may want
leaves with a certain spatial or velocity extent, or a minimum peak value, to
be considered independent structures.
In order to accomodate this, the
compute()
method can optionally take
an is_independent
argument which should be a function with the following
call signature:
def is_independent(structure, index=None, value=None):
...
where structure
is the Structure
object
that is being considered, and index
and value
are the pixel index and
value of the pixel that is linking the structure to the rest of the tree. These
last two values are only set when calling the is_independent
function
during the tree computation, but the is_independent
function is also used
at the end of the computation to prune leaves that are not attached to the
tree, and in this case index
and value
are not set.
The following example compares the dendrogram obtained with and without a
custom is_independent
function:
import matplotlib.pyplot as plt
from astropy.io import fits
from astrodendro import Dendrogram
image = fits.getdata('PerA_Extn2MASS_F_Gal.fits')
fig = plt.figure(figsize=(15,5))
# Default merging strategy
d1 = Dendrogram.compute(image, min_value=2.0)
p1 = d1.plotter()
ax1 = fig.add_subplot(1, 3, 1)
p1.plot_tree(ax1, color='black')
ax1.hlines(3.5, *ax1.get_xlim(), color='b', linestyle='--')
ax1.set_xlabel("Structure")
ax1.set_ylabel("Flux")
ax1.set_title("Default merging")
# Require minimum peak value
# this is equivalent to
# custom_independent = astrodendro.pruning.min_peak(3.5)
def custom_independent(structure, index=None, value=None):
peak_index, peak_value = structure.get_peak()
return peak_value > 3.5
d2 = Dendrogram.compute(image, min_value=2.0,
is_independent=custom_independent)
p2 = d2.plotter()
ax2 = fig.add_subplot(1, 3, 2)
p2.plot_tree(ax2, color='black')
ax2.hlines(3.5, *ax2.get_xlim(), color='b', linestyle='--')
ax2.set_xlabel("Structure")
ax2.set_ylabel("Flux")
ax2.set_title("Custom merging")
# For comparison, this is what changing the min_value does:
d3 = Dendrogram.compute(image, min_value=3.5)
p3 = d3.plotter()
ax3 = fig.add_subplot(1, 3, 3)
p3.plot_tree(ax3, color='black')
ax3.hlines(3.5, *ax3.get_xlim(), color='b', linestyle='--')
ax3.set_xlabel("Structure")
ax3.set_ylabel("Flux")
ax3.set_title("min_value=3.5 merging")
ax3.set_ylim(*ax2.get_ylim())

Several pre-implemented functions suitable for use as is_independent
tests
are provided in astrodendro.pruning
. In addition, the
astrodendro.pruning.all_true()
function can be used to combine several
criteria. For example, the following code builds a dendrogram where each leaf
contains a pixel whose value >=20, and whose pixels sum to >= 100:
from astrodendro.pruning import all_true, min_peak, min_sum
custom_independent = all_true((min_peak(20), min_sum(100)))
Dendrogram.compute(image, is_independent=custom_independent)
Handling custom adjacency logic¶
By default, neighbours to a given pixel are considered to be the adjacent pixels in the array. However, not all data are like this. For example, all-sky cartesian maps are periodic along the X axis.
You can specify custom neighbour logic by providing a neighbours
function
to Dendrogram.compute()
. For example, the periodic_neighbours()
utility will wrap neighbours across array edges. To correctly compute dendrograms for all-sky Cartesian maps:
periodic_axis = 1 # data wraps along longitude axis
Dendrogram.compute(data, neighbours=periodic_neighbours(periodic_axis))