class_docstr: Binning for a dot plot
  
  {usage}
  
  Parameters
  ----------
  {common_parameters}
  bins : int, default=None
      Number of bins. Overridden by binwidth. If `None`{.py},
      a number is computed using the freedman-diaconis method.
  binwidth : float, default=None
      When `method='dotdensity'`{.py}, this specifies the maximum
      binwidth. When `method='histodot'`{.py}, this specifies the
      binwidth. This supercedes the `bins`.
  origin : float, default=None
      When `method='histodot'`{.py}, origin of the first bin.
  width : float, default=0.9
      When `binaxis='y'`{.py}, the spacing of the dotstacks for
      dodging.
  binaxis : Literal["x", "y"], default="x"
      Axis to bin along.
  method : Literal["dotdensity", "histodot"], default="dotdensity"
      Whether to do dot-density binning or fixed widths binning.
  binpositions : Literal["all", "bygroup"], default="bygroup"
      Position of the bins when `method="dotdensity"`{.py}. The value
      - `bygroup` -  positions of the bins for each group are
      determined separately.
      - `all` - positions of the bins are determined with all
      data taken together. This aligns the dots
      stacks across multiple groups.
  drop : bool, default=False
      If `True`{.py}, remove all bins with zero counts.
  right : bool, default=True
      When `method='histodot'`{.py}, :py:`True` means include right
      edge of the bins and if `False`{.py} the left edge is included.
  breaks : FloatArray, default=None
      Bin boundaries for `method='histodot'`{.py}. This supercedes the
      `binwidth` and `bins`.
  
  See Also
  --------
  plotnine.stats.stat_bin
class_docstr_tok: ["Binning","for","a","dot","plot","{","usage","}","Parameters","--","--","--","--","--","{","common_parameters","}","bins",":","int",",","default=None","Number","of","bins",".","Overridden","by","binwidth",".","If","`","None","`","{",".py","}",",","a","number","is","computed","using","the","freedman-diaconis","method",".","binwidth",":","float",",","default=None","When","`","method='dotdensity","'","`","{",".py","}",",","this","specifies","the","maximum","binwidth",".","When","`","method='histodot","'","`","{",".py","}",",","this","specifies","the","binwidth",".","This","supercedes","the","`","bins","`",".","origin",":","float",",","default=None","When","`","method='histodot","'","`","{",".py","}",",","origin","of","the","first","bin",".","width",":","float",",","default=0.9","When","`","binaxis=","'","y","'","`","{",".py","}",",","the","spacing","of","the","dotstacks","for","dodging",".","binaxis",":","Literal","[","``","x","''",",","``","y","''","]",",","default=","''","x","''","Axis","to","bin","along",".","method",":","Literal","[","``","dotdensity","''",",","``","histodot","''","]",",","default=","''","dotdensity","''","Whether","to","do","dot-density","binning","or","fixed","widths","binning",".","binpositions",":","Literal","[","``","all","''",",","``","bygroup","''","]",",","default=","''","bygroup","''","Position","of","the","bins","when","`","method=","''","dotdensity","''","`","{",".py","}",".","The","value","-","`","bygroup","`","-","positions","of","the","bins","for","each","group","are","determined","separately",".","-","`","all","`","-","positions","of","the","bins","are","determined","with","all","data","taken","together",".","This","aligns","the","dots","stacks","across","multiple","groups",".","drop",":","bool",",","default=False","If","`","True","`","{",".py","}",",","remove","all","bins","with","zero","counts",".","right",":","bool",",","default=True","When","`","method='histodot","'","`","{",".py","}",",",":","py",":","`","True","`","means","include","right","edge","of","the","bins","and","if","`","False","`","{",".py","}","the","left","edge","is","included",".","breaks",":","FloatArray",",","default=None","Bin","boundaries","for","`","method='histodot","'","`","{",".py","}",".","This","supercedes","the","`","binwidth","`","and","`","bins","`",".","See","Also","--","--","--","--","plotnine.stats.stat_bin"]
code: def compute_group(cls, data, scales, **params):
      # Check that weights are whole numbers
      # (for dots, weights must be whole)
      weight: pd.Series | None = data.get("weight")  # pyright: ignore
      if weight is not None:
          int_status = [(w * 1.0).is_integer() for w in weight]
          if not all(int_status):
              raise PlotnineError(
                  "Weights for stat_bindot must be nonnegative integers."
              )
  
      if params["binaxis"] == "x":
          rangee = scales.x.dimension((0, 0))
          values = data["x"].to_numpy()
          midline = 0  # Make pyright happy
      else:
          rangee = scales.y.dimension((0, 0))
          values = data["y"].to_numpy()
          # The middle of each group, on the stack axis
          midline = np.mean([data["x"].min(), data["x"].max()])
  
      if params["method"] == "histodot":
          if params["binwidth"] is not None:
              breaks = breaks_from_binwidth(
                  rangee, params["binwidth"], boundary=params["origin"]
              )
          else:
              breaks = breaks_from_bins(
                  rangee, params["bins"], boundary=params["origin"]
              )
  
          closed = "right" if params["right"] else "left"
          data = assign_bins(
              values, breaks, weight, pad=False, closed=closed
          )
          # for consistency
          data.rename(
              columns={"width": "binwidth", "x": "bincenter"},
              inplace=True,
          )
      elif params["method"] == "dotdensity":
          # If bin centers are found by group instead of by all,
          # find the bin centers (If binpositions=="all", then
          # we'll already have bin centers.)
          if params["binpositions"] == "bygroup":
              data = densitybin(
                  x=values,
                  weight=weight,
                  binwidth=params["binwidth"],
                  bins=params["bins"],
                  rangee=rangee,
              )
  
          # Collapse each bin and get a count
          def func(df):
              return pd.DataFrame(
                  {
                      "binwidth": [df["binwidth"].iloc[0]],
                      "bincenter": [df["bincenter"].iloc[0]],
                      "count": [int(df["weight"].sum())],
                  }
              )
  
          # plyr::ddply + plyr::summarize
          data = groupby_apply(data, "bincenter", func)
  
          if data["count"].sum() != 0:
              data.loc[np.isnan(data["count"]), "count"] = 0
              data["ncount"] = data["count"] / data["count"].abs().max()
              if params["drop"]:
                  data = data[data["count"] > 0]
                  data.reset_index(inplace=True, drop=True)
  
      if params["binaxis"] == "x":
          data["x"] = data.pop("bincenter")
          # For x binning, the width of the geoms
          # is same as the width of the bin
          data["width"] = data["binwidth"]
      else:
          data["y"] = data.pop("bincenter")
          # For y binning, set the x midline.
          # This is needed for continuous x axis
          data["x"] = midline
  
      return data
  
file_path: plotnine/plotnine/stats/stat_bindot.py
imports: from __future__ import annotations
  import typing
  from warnings import warn
  import numpy
  import pandas
  from .._utils import groupby_apply
  from ..doctools import document
  from ..exceptions import PlotnineError, PlotnineWarning
  from ..mapping.evaluation import after_stat
  from .binning import assign_bins, breaks_from_bins, breaks_from_binwidth, freedman_diaconis_bins
  from .stat import stat
label_desc: Use image node_id 3 for calling the stat_bindot obj's underlying member method code with example usage: obj.compute_group(cls, data, scales) and returns: data, pd