The dendrogram algorithm segments data into nested structures. Each structure is given a unique integer identifier. The following routines help to navigate these indices.

The leafward mergers of structure `i` are all the nodes in the
sub-tree rooted at `i`. Each leafward merger passes through
structure `i` when traveling to the root. Alternatively, any node
that is visited on a trip from `i` to a leaf is a leafward merger of
`i`.

To find the IDs of the leafward mergers of structure 60 (Note that 60 is included in the output):

```
print, leafward_mergers(60, (*ptr).clusters)
60 15 56 55 20 22 53 52 25 51
27 30 50 49 26 29 33
```

To find the two immediate substructures that merge to form structure 60, use the `/parents` keyword:

```
IDL> print, leafward_mergers(60, (*ptr).clusters, /parents)
56 15
```

Rootward mergers are the opposite of leafward mergers. They represent superstructures, or trees that a given node is nested inside.

Rootward mergers of 60:

```
IDL> print, rootward_mergers(60, (*ptr).clusters)
60 61
```

The structure that structure 60 eventually merges with:

```
IDL> print, merger_partner(60, (*ptr).clusters)
59
```

The structure that defines the merger of structure 59 and 60:

```
IDL> partner = merger_partner(60, (*ptr).clusters, merge = m)
IDL> print, m
61
```

Use the substruct function to extract which pixels belong to each dendrogram structure.

Find the indices (in the flattened x/y/v/t arrays) of the pixels belonging to structure 60:

```
IDL> ind = substruct(60, ptr)
IDL> help, ind
<Expression> LONG = Array[3195]
IDL> intensities = (*ptr).t[ind]
IDL> xpos = (*ptr).x[ind]
IDL> ypos = (*ptr).y[ind]
```

Find only the pixels that belong to structure 60, but none of its substructures (i.e., a slice of the onion):

```
IDL> help, substruct(60, ptr, /single)
<Expression> LONG = Array[262]
```

Warning

In the IDL dendrogram implmentation, the x,y,v values **do not**
always correspond to the pixel locations in the original data (they
are occasionally offset by a few pixels). While this is not the
case for C++-generated dendrograms, you shouldn’t rely on using the
x/y/v values to index into the original data. Instead, use
`cube_indices = (*ptr).cubeindex[ind]`. This gives the (1D)
indices into the original data

Here’s an example of how **not** to index into the original cube (see warning above):

```
IDL> print, im[xpos[0:3], ypos[0:3], zpos[0:3]]
7.48933 8.81364 10.1202 6.45180
IDL> print, intensities[0:3]
6.66389 6.71393 6.73340 6.74873 ;- DOES NOT MATCH!
```

And the proper way:

```
IDL> ci = (*ptr).cubeindex[ind]
IDL> print im[ci[0:3]]
6.66389 6.71393 6.73340 6.74873
IDL> print, intensities[0:3]
6.66389 6.71393 6.73340 6.74873 ;- matches.
```

Get a set of (x,y) points to plot a dendrogram:

```
IDL> root = dendro_root(ptr) ;- grabs the ID of the dendrogram base
IDL> xy = dplot_xy(ptr, root) ;- draw from the root
IDL> plot, xy[0,*], xy[1,*]
```

The height of each vertical line is the intensity value at which the two branches above it merge. The height of each leaf is the peak intensity of that leaf. The x ordering is arbitrary (see next section).

You can re-sort the dendrogram using `dendro_sort`. For example, to sort the dendrogram structure such that the left subtree of any node has an integrated intensity less than the right subtree:

```
IDL> dendro_sort, ptr, /inten
IDL> xy = dplot_xy(ptr, root)
IDL> plot, xy[0,*], xy[1,*]
```

`dendro_sort` also supports sorting based on the height of the tallest leaf in each subtree (i.e. the peak intensity of each substructure) via the `/height` option.

`dendro_sort` accepts a keyword, `key`, to support user-defined
orderings. This should be an array, whose size is the number of
structures in the dendrogram. The dendrogram will be sorted such that
the left subtree of any node will have an associated key value less
than the right subtree. For example, to re-implement the functionality
of the `/height` keyword:

```
function height_key(ptr)
nst = n_elements((*ptr).height)
result = fltarr(nst)
for i = 0, nst - 1 do begin
result[i] = max( (*ptr).t[substruct(i, ptr)], /nan)
return, result
IDL> keys = height_key(ptr)
IDL> dendro_sort, ptr, key = keys
```

The low-level routines described in the *Dendrogram Indexes* section
can be used to extract and measure properties of each substructure.

The dendro_catalog function measures some common information:

```
IDL> catalog = dendro_catalog(ptr)
IDL> help, catalog, /struct
** Structure <2dc78d8>, 16 tags, length=64, data length=64, refs=1:
X FLOAT 109.922
Y FLOAT 7.59273
V FLOAT 0.00000
SIG_MAJ FLOAT 8.83641
SIG_MIN FLOAT 2.96764
SIG_V FLOAT 0.00000
SIG_R FLOAT 5.12087
AREA_MASK FLOAT 265.000
PERIMETER_MASK FLOAT 93.8909
FLUX FLOAT 639.349
PEAK_INTEN FLOAT 5.92300
VOL FLOAT 265.000
VIRIAL FLOAT 0.00000
SHOULDER_HEIGHT FLOAT 3.88697
VOL_LEFT FLOAT NaN
VOL_RIGHT FLOAT NaN
```

The function creates an array of structures, one for each dendrogram structure. The fields of this structure are:

x: Intensity-weighted mean x positiony: Intensity-weighted mean y positionv: Intensity-weighted mean v positionsig_maj: Semimajor axis of an ellipsoid approximation to the structure’s projection in the x/y planesig_min: Semiminor axis of ellispe described abovesig_v: RMS dispersion in velocitysig_r: sqrt(sig_maj * sig_min)area_mask: Number of pixels of the structure’s 2D projectionperimeter_mask: Perimeter of this projectionflux: Sum of intensities for all pixels inside the structurepeak_inten: Maximum intensity inside the structurevol: Number of pixels inside the structurevirial: Virial parameter (see note below)shoulder_height: Height of the vertical line connecting this structure to its merger in a dendrogram plotvol_left: Volume of left subtreevol_right: Volume of right subtree

Tip

dendro_catalog works in pixel units by default. The optional
`len_scale` defines the linear scale of each pixel. If present,
it will convert `sig_maj`, `sig_min`, and `sig_r` into
physical units. `vel_scale` gives the velocity width of each
channel, and will convert `sig_v` into physical
units. `flux2mass` is a multiplicative factor to convert summed
intensity into mass. It is used by `virial` (see next tip)

Tip

The virial parameter is defined as `5 eta R v^2 / (G M)`, where
`eta = 1.91` (see Rosolowsky et al. 2008). M is calculated by
multiplying the `flux` field by the optional `flux2mass`
keyword, and `G` is given in CGS units. Thus, to get sensible
units for this field, use `len_scale` to convert from pixels to
cm, `vel_scale` to convert from velocity pixels to cm/s, and
`flux2mass` to convert to g.

This routine depends on functions in the Beaumont IDL library.