def __call__( self, data: DataFrame, groupby: GroupBy, orient: str, scales: dict[str, Scale], ) -> DataFrame: var = {"x": "y", "y": "x"}.get(orient) res = (groupby.agg(data, { var: self.func }).dropna().reset_index(drop=True)) return res
def __call__(self, data: DataFrame, groupby: GroupBy, orient: str) -> DataFrame: grouping_vars = [v for v in groupby.order if v in data] groups = groupby.agg(data, {"width": "max"}) if self.empty == "fill": groups = groups.dropna() def groupby_pos(s): grouper = [groups[v] for v in [orient, "col", "row"] if v in data] return s.groupby(grouper, sort=False, observed=True) def scale_widths(w): # TODO what value to fill missing widths??? Hard problem... # TODO short circuit this if outer widths has no variance? empty = 0 if self.empty == "fill" else w.mean() filled = w.fillna(empty) scale = filled.max() norm = filled.sum() if self.empty == "keep": w = filled return w / norm * scale def widths_to_offsets(w): return w.shift(1).fillna(0).cumsum() + (w - w.sum()) / 2 new_widths = groupby_pos(groups["width"]).transform(scale_widths) offsets = groupby_pos(new_widths).transform(widths_to_offsets) if self.gap: new_widths *= 1 - self.gap groups["_dodged"] = groups[orient] + offsets groups["width"] = new_widths out = (data.drop("width", axis=1).merge( groups, on=grouping_vars, how="left").drop(orient, axis=1).rename(columns={"_dodged": orient})) return out