class_docstr: Class that handles hierarchical ROIs
  
  Parameters
  ----------
  k : int
    Number of ROI in the SubDomains object
  label : array of shape (domain.size), dtype=np.int_
    An array use to define which voxel belongs to which ROI.
    The label values greater than -1 correspond to subregions
    labelling. The labels are recomputed so as to be consecutive
    integers.
    The labels should not be accessed outside this class. One has to
    use the API mapping methods instead.
  features : dict {str: list of object, length=self.k}
    Describe the voxels features, grouped by ROI
  roi_features : dict {str: array-like, shape=(self.k, roi_feature_dim)
    Describe the ROI features. A special feature, `id`, is read-only and
    is used to give an unique identifier for region, which is persistent
    through the MROI objects manipulations. On should access the different
    ROI's features using ids.
  parents : np.ndarray, shape(self.k)
    self.parents[i] is the index of the parent of the i-th ROI.
  
  TODO: have the parents as a list of id rather than a list of indices.
class_docstr_tok: ["Class","that","handles","hierarchical","ROIs","Parameters","--","--","--","--","--","k",":","int","Number","of","ROI","in","the","SubDomains","object","label",":","array","of","shape","(","domain.size",")",",","dtype=np.int_","An","array","use","to","define","which","voxel","belongs","to","which","ROI",".","The","label","values","greater","than","-1","correspond","to","subregions","labelling",".","The","labels","are","recomputed","so","as","to","be","consecutive","integers",".","The","labels","should","not","be","accessed","outside","this","class",".","One","has","to","use","the","API","mapping","methods","instead",".","features",":","dict","{","str",":","list","of","object",",","length=self.k","}","Describe","the","voxels","features",",","grouped","by","ROI","roi_features",":","dict","{","str",":","array-like",",","shape=","(","self.k",",","roi_feature_dim",")","Describe","the","ROI","features",".","A","special","feature",",","`","id","`",",","is","read-only","and","is","used","to","give","an","unique","identifier","for","region",",","which","is","persistent","through","the","MROI","objects","manipulations",".","On","should","access","the","different","ROI","'s","features","using","ids",".","parents",":","np.ndarray",",","shape","(","self.k",")","self.parents","[","i","]","is","the","index","of","the","parent","of","the","i-th","ROI",".","TODO",":","have","the","parents","as","a","list","of","id","rather","than","a","list","of","indices","."]
docstr: Remove the items with only one son by including them in their son
  
  Parameters
  ----------
  methods indicates the way possible features are dealt with
  (not implemented yet)
  
  Notes
  -----
  Caveat: if roi_features have been defined, they will be removed
docstr_tok: ["Remove","the","items","with","only","one","son","by","including","them","in","their","son","Parameters","--","--","--","--","--","methods","indicates","the","way","possible","features","are","dealt","with","(","not","implemented","yet",")","Notes","--","--","-","Caveat",":","if","roi_features","have","been","defined",",","they","will","be","removed"]
code: def merge_descending(self, pull_features=None):
      """Remove the items with only one son by including them in their son
  
      Parameters
      ----------
      methods indicates the way possible features are dealt with
      (not implemented yet)
  
      Notes
      -----
      Caveat: if roi_features have been defined, they will be removed
      """
      if pull_features is None:
          pull_features = []
  
      if self.k == 0:
          return
  
      # relabel maps old labels to new labels
      relabel = np.arange(self.k)
  
      # merge nodes, one at a time
      id_list = self.get_id()[::-1]
  
      for p_id in id_list:
          p_pos = self.select_id(p_id)
          p_children = np.nonzero(self.parents == p_pos)[0]
  
          if p_pos in p_children:
              # remove current node from its children list
              p_children = p_children[p_children != p_pos]
  
          if p_children.size == 1:
              # merge node if it has only one child
              c_pos = p_children[0]
              c_id = self.get_id()[c_pos]
              mask_pos = np.ones(self.k, np.bool_)
              mask_pos[p_pos] = False
  
              # set new parents
              self.parents[c_pos] = self.parents[p_pos]
              if self.parents[c_pos] == p_pos:
                  self.parents[c_pos] = c_pos
              self.parents = self.parents[mask_pos]
              self.parents[self.parents > p_pos] -= 1
              # merge labels
              relabel[relabel == p_pos] = relabel[c_pos]
              self.k -= 1
  
              # compute new features
              for fid in list(self.features):
                  # replace feature
                  # (without the API since self is in an inconsistent state)
                  dj = self.get_feature(fid)
                  dj[c_pos] = np.hstack(
                      (
                          dj[self.select_id(c_id)],
                          dj[self.select_id(p_id)],
                      )
                  )
                  del dj[p_pos]
                  self.features[fid] = dj
  
              # compute new roi features
              for fid in list(self.roi_features):
                  dj = self.get_roi_feature(fid)
                  if fid in pull_features:
                      # modify only if `pull` requested
                      dj[c_pos] = dj[p_pos]
                  self.roi_features[fid] = dj[mask_pos]
  
      # update HROI structure
      self.label[self.label > -1] = relabel[self.label[self.label > -1]]
      self.recompute_labels()
  
imports: import numpy
  from nipy.algorithms.graph.field import field_from_coo_matrix_and_data
  from nipy.algorithms.graph.forest import Forest
  from nipy.algorithms.graph.graph import WeightedGraph
  from .mroi import SubDomains
label_desc: Use image node_id 8 for calling the HierarchicalROI obj's underlying member method code with example usage: obj.merge_descending(pull_features) without return types