class_docstr: Mixin to provide labelling capability to `.ContourSet`.
class_docstr_tok: ["Mixin","to","provide","labelling","capability","to","`",".ContourSet","`","."]
docstr: Prepare for insertion of a label at index *idx* of *path*.
  
  Parameters
  ----------
  path : Path
      The path where the label will be inserted, in data space.
  idx : int
      The vertex index after which the label will be inserted.
  screen_pos : (float, float)
      The position where the label will be inserted, in screen space.
  lw : float
      The label width, in screen space.
  spacing : float
      Extra spacing around the label, in screen space.
  
  Returns
  -------
  path : Path
      The path, broken so that the label can be drawn over it.
  angle : float
      The rotation of the label.
  
  Notes
  -----
  Both tasks are done together to avoid calculating path lengths multiple times,
  which is relatively costly.
  
  The method used here involves computing the path length along the contour in
  pixel coordinates and then looking (label width / 2) away from central point to
  determine rotation and then to break contour if desired.  The extra spacing is
  taken into account when breaking the path, but not when computing the angle.
docstr_tok: ["Prepare","for","insertion","of","a","label","at","index","*","idx","*","of","*","path","*",".","Parameters","--","--","--","--","--","path",":","Path","The","path","where","the","label","will","be","inserted",",","in","data","space",".","idx",":","int","The","vertex","index","after","which","the","label","will","be","inserted",".","screen_pos",":","(","float",",","float",")","The","position","where","the","label","will","be","inserted",",","in","screen","space",".","lw",":","float","The","label","width",",","in","screen","space",".","spacing",":","float","Extra","spacing","around","the","label",",","in","screen","space",".","Returns","--","--","--","-","path",":","Path","The","path",",","broken","so","that","the","label","can","be","drawn","over","it",".","angle",":","float","The","rotation","of","the","label",".","Notes","--","--","-","Both","tasks","are","done","together","to","avoid","calculating","path","lengths","multiple","times",",","which","is","relatively","costly",".","The","method","used","here","involves","computing","the","path","length","along","the","contour","in","pixel","coordinates","and","then","looking","(","label","width","\/","2",")","away","from","central","point","to","determine","rotation","and","then","to","break","contour","if","desired",".","The","extra","spacing","is","taken","into","account","when","breaking","the","path",",","but","not","when","computing","the","angle","."]
code: def _split_path_and_get_label_rotation(
      self, path, idx, screen_pos, lw, spacing=5
  ):
      """
      Prepare for insertion of a label at index *idx* of *path*.
  
      Parameters
      ----------
      path : Path
          The path where the label will be inserted, in data space.
      idx : int
          The vertex index after which the label will be inserted.
      screen_pos : (float, float)
          The position where the label will be inserted, in screen space.
      lw : float
          The label width, in screen space.
      spacing : float
          Extra spacing around the label, in screen space.
  
      Returns
      -------
      path : Path
          The path, broken so that the label can be drawn over it.
      angle : float
          The rotation of the label.
  
      Notes
      -----
      Both tasks are done together to avoid calculating path lengths multiple times,
      which is relatively costly.
  
      The method used here involves computing the path length along the contour in
      pixel coordinates and then looking (label width / 2) away from central point to
      determine rotation and then to break contour if desired.  The extra spacing is
      taken into account when breaking the path, but not when computing the angle.
      """
      if hasattr(self, "_old_style_split_collections"):
          vis = False
          for coll in self._old_style_split_collections:
              vis |= coll.get_visible()
              coll.remove()
          self.set_visible(vis)
          del self._old_style_split_collections  # Invalidate them.
  
      xys = path.vertices
      codes = path.codes
  
      # Insert a vertex at idx/pos (converting back to data space), if there isn't yet
      # a vertex there.  With infinite precision one could also always insert the
      # extra vertex (it will get masked out by the label below anyways), but floating
      # point inaccuracies (the point can have undergone a data->screen->data
      # transform loop) can slightly shift the point and e.g. shift the angle computed
      # below from exactly zero to nonzero.
      pos = self.get_transform().inverted().transform(screen_pos)
      if not np.allclose(pos, xys[idx]):
          xys = np.insert(xys, idx, pos, axis=0)
          codes = np.insert(codes, idx, Path.LINETO)
  
      # Find the connected component where the label will be inserted.  Note that a
      # path always starts with a MOVETO, and we consider there's an implicit
      # MOVETO (closing the last path) at the end.
      movetos = (codes == Path.MOVETO).nonzero()[0]
      start = movetos[movetos <= idx][-1]
      try:
          stop = movetos[movetos > idx][0]
      except IndexError:
          stop = len(codes)
  
      # Restrict ourselves to the connected component.
      cc_xys = xys[start:stop]
      idx -= start
  
      # If the path is closed, rotate it s.t. it starts at the label.
      is_closed_path = codes[stop - 1] == Path.CLOSEPOLY
      if is_closed_path:
          cc_xys = np.concatenate([cc_xys[idx:-1], cc_xys[: idx + 1]])
          idx = 0
  
      # Like np.interp, but additionally vectorized over fp.
      def interp_vec(x, xp, fp):
          return [np.interp(x, xp, col) for col in fp.T]
  
      # Use cumulative path lengths ("cpl") as curvilinear coordinate along contour.
      screen_xys = self.get_transform().transform(cc_xys)
      path_cpls = np.insert(
          np.cumsum(np.hypot(*np.diff(screen_xys, axis=0).T)), 0, 0
      )
      path_cpls -= path_cpls[idx]
  
      # Use linear interpolation to get end coordinates of label.
      target_cpls = np.array([-lw / 2, lw / 2])
      if is_closed_path:  # For closed paths, target from the other end.
          target_cpls[0] += path_cpls[-1] - path_cpls[0]
      (sx0, sx1), (sy0, sy1) = interp_vec(
          target_cpls, path_cpls, screen_xys
      )
      angle = np.rad2deg(
          np.arctan2(sy1 - sy0, sx1 - sx0)
      )  # Screen space.
      if self.rightside_up:  # Fix angle so text is never upside-down
          angle = (angle + 90) % 180 - 90
  
      target_cpls += [-spacing, +spacing]  # Expand range by spacing.
  
      # Get indices near points of interest; use -1 as out of bounds marker.
      i0, i1 = np.interp(
          target_cpls,
          path_cpls,
          range(len(path_cpls)),
          left=-1,
          right=-1,
      )
      i0 = math.floor(i0)
      i1 = math.ceil(i1)
      (x0, x1), (y0, y1) = interp_vec(target_cpls, path_cpls, cc_xys)
  
      # Actually break contours (dropping zero-len parts).
      new_xy_blocks = []
      new_code_blocks = []
      if is_closed_path:
          if i0 != -1 and i1 != -1:
              # This is probably wrong in the case that the entire contour would
              # be discarded, but ensures that a valid path is returned and is
              # consistent with behavior of mpl <3.8
              points = cc_xys[i1 : i0 + 1]
              new_xy_blocks.extend([[(x1, y1)], points, [(x0, y0)]])
              nlines = len(points) + 1
              new_code_blocks.extend(
                  [[Path.MOVETO], [Path.LINETO] * nlines]
              )
      else:
          if i0 != -1:
              new_xy_blocks.extend([cc_xys[: i0 + 1], [(x0, y0)]])
              new_code_blocks.extend(
                  [[Path.MOVETO], [Path.LINETO] * (i0 + 1)]
              )
          if i1 != -1:
              new_xy_blocks.extend([[(x1, y1)], cc_xys[i1:]])
              new_code_blocks.extend(
                  [[Path.MOVETO], [Path.LINETO] * (len(cc_xys) - i1)]
              )
  
      # Back to the full path.
      xys = np.concatenate([xys[:start], *new_xy_blocks, xys[stop:]])
      codes = np.concatenate(
          [codes[:start], *new_code_blocks, codes[stop:]]
      )
  
      return angle, Path(xys, codes)
  
imports: from contextlib import ExitStack
  import functools
  import math
  from numbers import Integral
  import numpy
  from numpy import ma
  import matplotlib
  from matplotlib import _api, _docstring
  from matplotlib.backend_bases import MouseButton
  from matplotlib.lines import Line2D
  from matplotlib.path import Path
  from matplotlib.text import Text
  import matplotlib.ticker
  import matplotlib.cm
  import matplotlib.colors
  import matplotlib.collections
  import matplotlib.font_manager
  import matplotlib.cbook
  import matplotlib.patches
  import matplotlib.transforms
label_desc: Use image node_id 7 for calling the ContourLabeler obj's underlying member method code with example usage: obj._split_path_and_get_label_rotation(path, idx, screen_pos, lw, spacing) and returns: angle,  Path, unknown