code: def agglomerative(
      data: np.ndarray,
      k: int,
      *,
      clusterer: Optional[
          sklearn.cluster.AgglomerativeClustering
      ] = None,
      axis: int = -1,
  ) -> np.ndarray:
      """Bottom-up temporal segmentation.
  
      Use a temporally-constrained agglomerative clustering routine to partition
      ``data`` into ``k`` contiguous segments.
  
      Parameters
      ----------
      data : np.ndarray
          data to cluster
      k : int > 0 [scalar]
          number of segments to produce
      clusterer : sklearn.cluster.AgglomerativeClustering, optional
          An optional AgglomerativeClustering object.
          If `None`, a constrained Ward object is instantiated.
      axis : int
          axis along which to cluster.
          By default, the last axis (-1) is chosen.
  
      Returns
      -------
      boundaries : np.ndarray [shape=(k,)]
          left-boundaries (frame numbers) of detected segments. This
          will always include `0` as the first left-boundary.
  
      See Also
      --------
      sklearn.cluster.AgglomerativeClustering
  
      Examples
      --------
      Cluster by chroma similarity, break into 20 segments
  
      >>> y, sr = librosa.load(librosa.ex('nutcracker'), duration=15)
      >>> chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
      >>> bounds = librosa.segment.agglomerative(chroma, 20)
      >>> bound_times = librosa.frames_to_time(bounds, sr=sr)
      >>> bound_times
      array([ 0.   ,  0.65 ,  1.091,  1.927,  2.438,  2.902,  3.924,
              4.783,  5.294,  5.712,  6.13 ,  7.314,  8.522,  8.916,
              9.66 , 10.844, 11.238, 12.028, 12.492, 14.095])
  
      Plot the segmentation over the chromagram
  
      >>> import matplotlib.pyplot as plt
      >>> import matplotlib.transforms as mpt
      >>> fig, ax = plt.subplots()
      >>> trans = mpt.blended_transform_factory(
      ...             ax.transData, ax.transAxes)
      >>> librosa.display.specshow(chroma, y_axis='chroma', x_axis='time', ax=ax)
      >>> ax.vlines(bound_times, 0, 1, color='linen', linestyle='--',
      ...           linewidth=2, alpha=0.9, label='Segment boundaries',
      ...           transform=trans)
      >>> ax.legend()
      >>> ax.set(title='Power spectrogram')
      """
      # Make sure we have at least two dimensions
      data = np.atleast_2d(data)
  
      # Swap data index to position 0
      data = np.swapaxes(data, axis, 0)
  
      # Flatten the features
      n = data.shape[0]
      data = data.reshape((n, -1), order="F")
  
      if clusterer is None:
          # Connect the temporal connectivity graph
          grid = sklearn.feature_extraction.image.grid_to_graph(
              n_x=n, n_y=1, n_z=1
          )
  
          # Instantiate the clustering object
          clusterer = sklearn.cluster.AgglomerativeClustering(
              n_clusters=k, connectivity=grid, memory=cache.memory
          )
  
      # Fit the model
      clusterer.fit(data)
  
      # Find the change points from the labels
      boundaries = [0]
      boundaries.extend(
          list(
              1 + np.nonzero(np.diff(clusterer.labels_))[0].astype(int)
          )
      )
      return np.asarray(boundaries)
  
imports: from decorator import decorator
  import numpy
  import scipy
  import scipy.signal
  import scipy.ndimage
  import sklearn
  import sklearn.cluster
  import sklearn.feature_extraction
  import sklearn.neighbors
  from ._cache import cache
  from .None import util
  from .filters import diagonal_filter
  from .util.exceptions import ParameterError
  from typing import Any, Callable, Optional, TypeVar, Union, overload
  from typing_extensions import Literal
  from ._typing import _WindowSpec, _FloatLike_co
label_desc: Use image node_id 11 for calling a global function with example usage: agglomerative(data, k) and returns: np