docs: def get_limits(plottables,
                 xpadding=0,
                 ypadding=0.1,
                 xerror_in_padding=True,
                 yerror_in_padding=True,
                 snap=True,
                 logx=False,
                 logy=False,
                 logx_crop_value=1E-5,
                 logy_crop_value=1E-5,
                 logx_base=10,
                 logy_base=10):
      """
      Get the axes limits that should be used for a 1D histogram, graph, or stack
      of histograms.
  
      Parameters
      ----------
  
      plottables : Hist, Graph, HistStack, or list of such objects
          The object(s) for which visually pleasing plot boundaries are
          requested.
  
      xpadding : float or 2-tuple, optional (default=0)
          The horizontal padding as a fraction of the final plot width.
  
      ypadding : float or 2-tuple, optional (default=0.1)
          The vertical padding as a fraction of the final plot height.
  
      xerror_in_padding : bool, optional (default=True)
          If False then exclude the x error bars from the calculation of the plot
          width.
  
      yerror_in_padding : bool, optional (default=True)
          If False then exclude the y error bars from the calculation of the plot
          height.
  
      snap : bool, optional (default=True)
          Make the minimum or maximum of the vertical range the x-axis depending
          on if the plot maximum and minimum are above or below the x-axis. If
          the plot maximum is above the x-axis while the minimum is below the
          x-axis, then this option will have no effect.
  
      logx : bool, optional (default=False)
          If True, then the x-axis is log scale.
  
      logy : bool, optional (default=False)
          If True, then the y-axis is log scale.
  
      logx_crop_value : float, optional (default=1E-5)
          If an x-axis is using a logarithmic scale then crop all non-positive
          values with this value.
  
      logy_crop_value : float, optional (default=1E-5)
          If the y-axis is using a logarithmic scale then crop all non-positive
          values with this value.
  
      logx_base : float, optional (default=10)
          The base used for the logarithmic scale of the x-axis.
  
      logy_base : float, optional (default=10)
          The base used for the logarithmic scale of the y-axis.
  
      Returns
      -------
  
      xmin, xmax, ymin, ymax : tuple of plot boundaries
          The computed x and y-axis ranges.
  
      """
      try:
          import numpy as np
          use_numpy = True
      except ImportError:
          use_numpy = False
  
      if not isinstance(plottables, (list, tuple)):
          plottables = [plottables]
  
      xmin = float('+inf')
      xmax = float('-inf')
      ymin = float('+inf')
      ymax = float('-inf')
  
      for h in plottables:
  
          if isinstance(h, HistStack):
              h = h.sum
  
          if not isinstance(h, (_Hist, _Graph1DBase)):
              raise TypeError(
                  "unable to determine plot axes ranges "
                  "from object of type `{0}`".format(
                      type(h)))
  
          if use_numpy:
              y_array_min = y_array_max = np.array(list(h.y()))
              if yerror_in_padding:
                  y_array_min = y_array_min - np.array(list(h.yerrl()))
                  y_array_max = y_array_max + np.array(list(h.yerrh()))
              _ymin = y_array_min.min()
              _ymax = y_array_max.max()
          else:
              y_array_min = y_array_max = list(h.y())
              if yerror_in_padding:
                  y_array_min = multisub(y_array_min, list(h.yerrl()))
                  y_array_max = multiadd(y_array_max, list(h.yerrh()))
              _ymin = min(y_array_min)
              _ymax = max(y_array_max)
  
          if isinstance(h, _Graph1DBase):
              if use_numpy:
                  x_array_min = x_array_max = np.array(list(h.x()))
                  if xerror_in_padding:
                      x_array_min = x_array_min - np.array(list(h.xerrl()))
                      x_array_max = x_array_max + np.array(list(h.xerrh()))
                  _xmin = x_array_min.min()
                  _xmax = x_array_max.max()
              else:
                  x_array_min = x_array_max = list(h.x())
                  if xerror_in_padding:
                      x_array_min = multisub(x_array_min, list(h.xerrl()))
                      x_array_max = multiadd(x_array_max, list(h.xerrh()))
                  _xmin = min(x_array_min)
                  _xmax = max(x_array_max)
          else:
              _xmin = h.xedgesl(1)
              _xmax = h.xedgesh(h.nbins(0))
  
          if logy:
              _ymin = max(logy_crop_value, _ymin)
              _ymax = max(logy_crop_value, _ymax)
          if logx:
              _xmin = max(logx_crop_value, _xmin)
              _xmax = max(logx_crop_value, _xmax)
  
          if _xmin < xmin:
              xmin = _xmin
          if _xmax > xmax:
              xmax = _xmax
          if _ymin < ymin:
              ymin = _ymin
          if _ymax > ymax:
              ymax = _ymax
  
      if isinstance(xpadding, (list, tuple)):
          if len(xpadding) != 2:
              raise ValueError("xpadding must be of length 2")
          xpadding_left = xpadding[0]
          xpadding_right = xpadding[1]
      else:
          xpadding_left = xpadding_right = xpadding
  
      if isinstance(ypadding, (list, tuple)):
          if len(ypadding) != 2:
              raise ValueError("ypadding must be of length 2")
          ypadding_top = ypadding[0]
          ypadding_bottom = ypadding[1]
      else:
          ypadding_top = ypadding_bottom = ypadding
  
      if logx:
          x0, x3 = _limits_helper(
              log(xmin, logx_base), log(xmax, logx_base),
              xpadding_left, xpadding_right)
          xmin = logx_base ** x0
          xmax = logx_base ** x3
      else:
          xmin, xmax = _limits_helper(
              xmin, xmax, xpadding_left, xpadding_right)
  
      if logy:
          y0, y3 = _limits_helper(
              log(ymin, logy_base), log(ymax, logy_base),
              ypadding_bottom, ypadding_top, snap=False)
          ymin = logy_base ** y0
          ymax = logy_base ** y3
      else:
          ymin, ymax = _limits_helper(
              ymin, ymax, ypadding_bottom, ypadding_top, snap=snap)
  
      return xmin, xmax, ymin, ymax