code: def _plot_connectivity_circle(
      con,
      node_names,
      indices=None,
      n_lines=None,
      node_angles=None,
      node_width=None,
      node_height=None,
      node_colors=None,
      facecolor="black",
      textcolor="white",
      node_edgecolor="black",
      linewidth=1.5,
      colormap="hot",
      vmin=None,
      vmax=None,
      colorbar=True,
      title=None,
      colorbar_size=None,
      colorbar_pos=None,
      fontsize_title=12,
      fontsize_names=8,
      fontsize_colorbar=8,
      padding=6.0,
      ax=None,
      interactive=True,
      node_linewidth=2.0,
      show=True,
  ):
      import matplotlib.patches as m_patches
      import matplotlib.path as m_path
      import matplotlib.pyplot as plt
      from matplotlib.projections.polar import PolarAxes
  
      _validate_type(ax, (None, PolarAxes))
  
      n_nodes = len(node_names)
  
      if node_angles is not None:
          if len(node_angles) != n_nodes:
              raise ValueError(
                  "node_angles has to be the same length "
                  "as node_names"
              )
          # convert it to radians
          node_angles = node_angles * np.pi / 180
      else:
          # uniform layout on unit circle
          node_angles = np.linspace(
              0, 2 * np.pi, n_nodes, endpoint=False
          )
  
      if node_width is None:
          # widths correspond to the minimum angle between two nodes
          dist_mat = node_angles[None, :] - node_angles[:, None]
          dist_mat[np.diag_indices(n_nodes)] = 1e9
          node_width = np.min(np.abs(dist_mat))
      else:
          node_width = node_width * np.pi / 180
  
      if node_height is None:
          node_height = 1.0
  
      if node_colors is not None:
          if len(node_colors) < n_nodes:
              node_colors = cycle(node_colors)
      else:
          # assign colors using colormap
          try:
              spectral = plt.cm.spectral
          except AttributeError:
              spectral = plt.cm.Spectral
          node_colors = [
              spectral(i / float(n_nodes)) for i in range(n_nodes)
          ]
  
      # handle 1D and 2D connectivity information
      if con.ndim == 1:
          if indices is None:
              raise ValueError(
                  "indices has to be provided if con.ndim == 1"
              )
      elif con.ndim == 2:
          if con.shape[0] != n_nodes or con.shape[1] != n_nodes:
              raise ValueError("con has to be 1D or a square matrix")
          # we use the lower-triangular part
          indices = np.tril_indices(n_nodes, -1)
          con = con[indices]
      else:
          raise ValueError("con has to be 1D or a square matrix")
  
      # get the colormap
      colormap = _get_cmap(colormap)
  
      # Use a polar axes
      if ax is None:
          fig = plt.figure(
              figsize=(8, 8), facecolor=facecolor, layout="constrained"
          )
          ax = fig.add_subplot(polar=True)
      else:
          fig = ax.figure
      ax.set_facecolor(facecolor)
  
      # No ticks, we'll put our own
      ax.set_xticks([])
      ax.set_yticks([])
  
      # Set y axes limit, add additional space if requested
      ax.set_ylim(0, 10 + padding)
  
      # Remove the black axes border which may obscure the labels
      ax.spines["polar"].set_visible(False)
  
      # Draw lines between connected nodes, only draw the strongest connections
      if n_lines is not None and len(con) > n_lines:
          con_thresh = np.sort(np.abs(con).ravel())[-n_lines]
      else:
          con_thresh = 0.0
  
      # get the connections which we are drawing and sort by connection strength
      # this will allow us to draw the strongest connections first
      con_abs = np.abs(con)
      con_draw_idx = np.where(con_abs >= con_thresh)[0]
  
      con = con[con_draw_idx]
      con_abs = con_abs[con_draw_idx]
      indices = [ind[con_draw_idx] for ind in indices]
  
      # now sort them
      sort_idx = np.argsort(con_abs)
      del con_abs
      con = con[sort_idx]
      indices = [ind[sort_idx] for ind in indices]
  
      # Get vmin vmax for color scaling
      if vmin is None:
          vmin = np.min(con[np.abs(con) >= con_thresh])
      if vmax is None:
          vmax = np.max(con)
      vrange = vmax - vmin
  
      # We want to add some "noise" to the start and end position of the
      # edges: We modulate the noise with the number of connections of the
      # node and the connection strength, such that the strongest connections
      # are closer to the node center
      nodes_n_con = np.zeros((n_nodes), dtype=np.int64)
      for i, j in zip(indices[0], indices[1]):
          nodes_n_con[i] += 1
          nodes_n_con[j] += 1
  
      # initialize random number generator so plot is reproducible
      rng = np.random.mtrand.RandomState(0)
  
      n_con = len(indices[0])
      noise_max = 0.25 * node_width
      start_noise = rng.uniform(-noise_max, noise_max, n_con)
      end_noise = rng.uniform(-noise_max, noise_max, n_con)
  
      nodes_n_con_seen = np.zeros_like(nodes_n_con)
      for i, (start, end) in enumerate(zip(indices[0], indices[1])):
          nodes_n_con_seen[start] += 1
          nodes_n_con_seen[end] += 1
  
          start_noise[i] *= (
              nodes_n_con[start] - nodes_n_con_seen[start]
          ) / float(nodes_n_con[start])
          end_noise[i] *= (
              nodes_n_con[end] - nodes_n_con_seen[end]
          ) / float(nodes_n_con[end])
  
      # scale connectivity for colormap (vmin<=>0, vmax<=>1)
      con_val_scaled = (con - vmin) / vrange
  
      # Finally, we draw the connections
      for pos, (i, j) in enumerate(zip(indices[0], indices[1])):
          # Start point
          t0, r0 = node_angles[i], 10
  
          # End point
          t1, r1 = node_angles[j], 10
  
          # Some noise in start and end point
          t0 += start_noise[pos]
          t1 += end_noise[pos]
  
          verts = [(t0, r0), (t0, 5), (t1, 5), (t1, r1)]
          codes = [
              m_path.Path.MOVETO,
              m_path.Path.CURVE4,
              m_path.Path.CURVE4,
              m_path.Path.LINETO,
          ]
          path = m_path.Path(verts, codes)
  
          color = colormap(con_val_scaled[pos])
  
          # Actual line
          patch = m_patches.PathPatch(
              path,
              fill=False,
              edgecolor=color,
              linewidth=linewidth,
              alpha=1.0,
          )
          ax.add_patch(patch)
  
      # Draw ring with colored nodes
      height = np.ones(n_nodes) * node_height
      bars = ax.bar(
          node_angles,
          height,
          width=node_width,
          bottom=9,
          edgecolor=node_edgecolor,
          lw=node_linewidth,
          facecolor=".9",
          align="center",
      )
  
      for bar, color in zip(bars, node_colors):
          bar.set_facecolor(color)
  
      # Draw node labels
      angles_deg = 180 * node_angles / np.pi
      for name, angle_rad, angle_deg in zip(
          node_names, node_angles, angles_deg
      ):
          if angle_deg >= 270:
              ha = "left"
          else:
              # Flip the label, so text is always upright
              angle_deg += 180
              ha = "right"
  
          ax.text(
              angle_rad,
              9.4 + node_height,
              name,
              size=fontsize_names,
              rotation=angle_deg,
              rotation_mode="anchor",
              horizontalalignment=ha,
              verticalalignment="center",
              color=textcolor,
          )
  
      if title is not None:
          ax.set_title(title, color=textcolor, fontsize=fontsize_title)
  
      if colorbar:
          sm = plt.cm.ScalarMappable(
              cmap=colormap, norm=plt.Normalize(vmin, vmax)
          )
          sm.set_array(np.linspace(vmin, vmax))
          colorbar_kwargs = dict()
          if colorbar_size is not None:
              colorbar_kwargs.update(shrink=colorbar_size)
          if colorbar_pos is not None:
              colorbar_kwargs.update(anchor=colorbar_pos)
          cb = fig.colorbar(sm, ax=ax, **colorbar_kwargs)
          cb_yticks = plt.getp(cb.ax.axes, "yticklabels")
          cb.ax.tick_params(labelsize=fontsize_colorbar)
          plt.setp(cb_yticks, color=textcolor)
  
      # Add callback for interaction
      if interactive:
          callback = partial(
              _plot_connectivity_circle_onpick,
              fig=fig,
              ax=ax,
              indices=indices,
              n_nodes=n_nodes,
              node_angles=node_angles,
          )
  
          fig.canvas.mpl_connect("button_press_event", callback)
  
      plt_show(show)
      return fig, ax
  
file_path: mne-python/mne/viz/circle.py
imports: from functools import partial
  from itertools import cycle
  import numpy
  from ..utils import _validate_type
  from .utils import _get_cmap, plt_show
label_desc: Use image node_id 3 for calling a global function with example usage: _plot_connectivity_circle(con, node_names, indices, n_lines, node_angles, node_width, node_height, node_colors, facecolor, textcolor, node_edgecolor, linewidth, colormap, vmin, vmax, colorbar, title, colorbar_size, colorbar_pos, fontsize_title, fontsize_names, fontsize_colorbar, padding, ax, interactive, node_linewidth, show) and returns: fig,  ax