class_docstr: Base class for objects underlying *plot functions.
class_docstr_tok: ["Base","class","for","objects","underlying","*","plot","functions","."]
docstr: Associate the plotter with an Axes manager and initialize its units.
  
  Parameters
  ----------
  obj : :class:`matplotlib.axes.Axes` or :class:'FacetGrid`
      Structural object that we will eventually plot onto.
  allowed_types : str or list of str
      If provided, raise when either the x or y variable does not have
      one of the declared seaborn types.
  log_scale : bool, number, or pair of bools or numbers
      If not False, set the axes to use log scaling, with the given
      base or defaulting to 10. If a tuple, interpreted as separate
      arguments for the x and y axes.
docstr_tok: ["Associate","the","plotter","with","an","Axes","manager","and","initialize","its","units",".","Parameters","--","--","--","--","--","obj",":",":","class",":","`","matplotlib.axes.Axes","`","or",":","class",":","'FacetGrid","`","Structural","object","that","we","will","eventually","plot","onto",".","allowed_types",":","str","or","list","of","str","If","provided",",","raise","when","either","the","x","or","y","variable","does","not","have","one","of","the","declared","seaborn","types",".","log_scale",":","bool",",","number",",","or","pair","of","bools","or","numbers","If","not","False",",","set","the","axes","to","use","log","scaling",",","with","the","given","base","or","defaulting","to","10",".","If","a","tuple",",","interpreted","as","separate","arguments","for","the","x","and","y","axes","."]
code: def _attach(
      self,
      obj,
      allowed_types=None,
      log_scale=None,
  ):
      """Associate the plotter with an Axes manager and initialize its units.
  
      Parameters
      ----------
      obj : :class:`matplotlib.axes.Axes` or :class:'FacetGrid`
          Structural object that we will eventually plot onto.
      allowed_types : str or list of str
          If provided, raise when either the x or y variable does not have
          one of the declared seaborn types.
      log_scale : bool, number, or pair of bools or numbers
          If not False, set the axes to use log scaling, with the given
          base or defaulting to 10. If a tuple, interpreted as separate
          arguments for the x and y axes.
  
      """
      from .axisgrid import FacetGrid
  
      if isinstance(obj, FacetGrid):
          self.ax = None
          self.facets = obj
          ax_list = obj.axes.flatten()
          if obj.col_names is not None:
              self.var_levels["col"] = obj.col_names
          if obj.row_names is not None:
              self.var_levels["row"] = obj.row_names
      else:
          self.ax = obj
          self.facets = None
          ax_list = [obj]
  
      # Identify which "axis" variables we have defined
      axis_variables = set("xy").intersection(self.variables)
  
      # -- Verify the types of our x and y variables here.
      # This doesn't really make complete sense being here here, but it's a fine
      # place for it, given  the current system.
      # (Note that for some plots, there might be more complicated restrictions)
      # e.g. the categorical plots have their own check that as specific to the
      # non-categorical axis.
      if allowed_types is None:
          allowed_types = ["numeric", "datetime", "categorical"]
      elif isinstance(allowed_types, str):
          allowed_types = [allowed_types]
  
      for var in axis_variables:
          var_type = self.var_types[var]
          if var_type not in allowed_types:
              err = (
                  f"The {var} variable is {var_type}, but one of "
                  f"{allowed_types} is required"
              )
              raise TypeError(err)
  
      # -- Get axis objects for each row in plot_data for type conversions and scaling
  
      facet_dim = {"x": "col", "y": "row"}
  
      self.converters = {}
      for var in axis_variables:
          other_var = {"x": "y", "y": "x"}[var]
  
          converter = pd.Series(
              index=self.plot_data.index, name=var, dtype=object
          )
          share_state = getattr(self.facets, f"_share{var}", True)
  
          # Simplest cases are that we have a single axes, all axes are shared,
          # or sharing is only on the orthogonal facet dimension. In these cases,
          # all datapoints get converted the same way, so use the first axis
          if share_state is True or share_state == facet_dim[other_var]:
              converter.loc[:] = getattr(ax_list[0], f"{var}axis")
  
          else:
              # Next simplest case is when no axes are shared, and we can
              # use the axis objects within each facet
              if share_state is False:
                  for axes_vars, axes_data in self.iter_data():
                      ax = self._get_axes(axes_vars)
                      converter.loc[axes_data.index] = getattr(
                          ax, f"{var}axis"
                      )
  
              # In the more complicated case, the axes are shared within each
              # "file" of the facetgrid. In that case, we need to subset the data
              # for that file and assign it the first axis in the slice of the grid
              else:
                  names = getattr(self.facets, f"{share_state}_names")
                  for i, level in enumerate(names):
                      idx = (i, 0) if share_state == "row" else (0, i)
                      axis = getattr(
                          self.facets.axes[idx], f"{var}axis"
                      )
                      converter.loc[
                          self.plot_data[share_state] == level
                      ] = axis
  
          # Store the converter vector, which we use elsewhere (e.g comp_data)
          self.converters[var] = converter
  
          # Now actually update the matplotlib objects to do the conversion we want
          grouped = self.plot_data[var].groupby(
              self.converters[var], sort=False
          )
          for converter, seed_data in grouped:
              if self.var_types[var] == "categorical":
                  if self._var_ordered[var]:
                      order = self.var_levels[var]
                  else:
                      order = None
                  seed_data = categorical_order(seed_data, order)
              converter.update_units(seed_data)
  
      # -- Set numerical axis scales
  
      # First unpack the log_scale argument
      if log_scale is None:
          scalex = scaley = False
      else:
          # Allow single value or x, y tuple
          try:
              scalex, scaley = log_scale
          except TypeError:
              scalex = (
                  log_scale
                  if self.var_types.get("x") == "numeric"
                  else False
              )
              scaley = (
                  log_scale
                  if self.var_types.get("y") == "numeric"
                  else False
              )
  
      # Now use it
      for axis, scale in zip("xy", (scalex, scaley)):
          if scale:
              for ax in ax_list:
                  set_scale = getattr(ax, f"set_{axis}scale")
                  if scale is True:
                      set_scale("log", nonpositive="mask")
                  else:
                      set_scale("log", base=scale, nonpositive="mask")
  
      # For categorical y, we want the "first" level to be at the top of the axis
      if self.var_types.get("y", None) == "categorical":
          for ax in ax_list:
              ax.yaxis.set_inverted(True)
  
imports: from __future__ import annotations
  import warnings
  import itertools
  from copy import copy
  from collections import UserString
  from collections.abc import Iterable, Sequence, Mapping
  from numbers import Number
  from datetime import datetime
  import numpy
  import pandas
  import matplotlib
  from seaborn._core.data import PlotData
  from seaborn.palettes import QUAL_PALETTES, color_palette
  from seaborn.utils import _check_argument, _version_predates, desaturate, locator_to_legend_entries, get_color_cycle, remove_na
label_desc: Use image node_id 12 for calling the VectorPlotter obj's underlying member method code with example usage: obj._attach(obj, allowed_types, log_scale) without return types