diff --git a/plotnine/stats/stat.py b/plotnine/stats/stat.py index 13ac32939..9855c7141 100644 --- a/plotnine/stats/stat.py +++ b/plotnine/stats/stat.py @@ -57,6 +57,15 @@ class stat(ABC, metaclass=Register): DEFAULT_PARAMS: dict[str, Any] = {} """Required parameters for the stat""" + DROPPED_AES: list[str] = [] + """ + Aesthetics that may be dropped during processing. + + These are typically common aesthetics that a particular stat does not use. + If a value is mapped to any of these aesthetics, the stat may discard them + silently (without issuing a warning). + """ + CREATES: set[str] = set() """ Stats may modify existing columns or create extra @@ -315,7 +324,9 @@ def compute_panel(self, data: pd.DataFrame, scales: pos_scales): stats.append(group_result) stats = pd.concat(stats, axis=0, ignore_index=True) - dropped = data.columns.difference(stats.columns).to_list() + dropped = data.columns.difference( + stats.columns.union(self.DROPPED_AES) + ).to_list() if dropped: warn(DROPPED_TPL.format(dropped=dropped)) # Note: If the data coming in has columns with non-unique diff --git a/plotnine/stats/stat_bin.py b/plotnine/stats/stat_bin.py index 9d8ee0ec2..866314473 100644 --- a/plotnine/stats/stat_bin.py +++ b/plotnine/stats/stat_bin.py @@ -87,6 +87,7 @@ class stat_bin(stat): } DEFAULT_AES = {"y": after_stat("count"), "weight": None} CREATES = {"width", "count", "density", "ncount", "ndensity", "ngroup"} + DROPPED_AES = ["weight"] def setup_params(self, data): params = self.params diff --git a/plotnine/stats/stat_bin_2d.py b/plotnine/stats/stat_bin_2d.py index 63fee8c99..1fc4b7240 100644 --- a/plotnine/stats/stat_bin_2d.py +++ b/plotnine/stats/stat_bin_2d.py @@ -66,6 +66,7 @@ class stat_bin_2d(stat): } DEFAULT_AES = {"fill": after_stat("count"), "weight": None} CREATES = {"xmin", "xmax", "ymin", "ymax", "count", "density"} + DROPPED_AES = ["weight"] def setup_params(self, data): params = self.params diff --git a/plotnine/stats/stat_bindot.py b/plotnine/stats/stat_bindot.py index 9539e20af..5f98a3957 100644 --- a/plotnine/stats/stat_bindot.py +++ b/plotnine/stats/stat_bindot.py @@ -103,6 +103,7 @@ class stat_bindot(stat): } DEFAULT_AES = {"y": after_stat("count")} CREATES = {"width", "count", "density", "ncount", "ndensity"} + DROPPED_AES = ["weight", "bin", "bincenter"] def setup_params(self, data): params = self.params diff --git a/plotnine/stats/stat_boxplot.py b/plotnine/stats/stat_boxplot.py index 87baa79cb..750eb83e1 100644 --- a/plotnine/stats/stat_boxplot.py +++ b/plotnine/stats/stat_boxplot.py @@ -80,6 +80,7 @@ class stat_boxplot(stat): "relvarwidth", "n", } + DROPPED_AES: list[str] = ["x", "y", "weight"] def setup_data(self, data): if "x" not in data: diff --git a/plotnine/stats/stat_count.py b/plotnine/stats/stat_count.py index bf2b3470e..3aab2d4a3 100644 --- a/plotnine/stats/stat_count.py +++ b/plotnine/stats/stat_count.py @@ -47,6 +47,7 @@ class stat_count(stat): } DEFAULT_AES = {"y": after_stat("count")} CREATES = {"count", "prop"} + DROPPED_AES = ["weight"] def setup_params(self, data): if self.params["width"] is None: diff --git a/plotnine/stats/stat_density.py b/plotnine/stats/stat_density.py index b3bce5efd..aac7b189b 100644 --- a/plotnine/stats/stat_density.py +++ b/plotnine/stats/stat_density.py @@ -123,6 +123,7 @@ class stat_density(stat): } DEFAULT_AES = {"y": after_stat("density")} CREATES = {"density", "count", "scaled", "n"} + DROPPED_AES = ["weight"] def setup_params(self, data): params = self.params diff --git a/plotnine/stats/stat_ecdf.py b/plotnine/stats/stat_ecdf.py index 013b382e4..12bb17172 100644 --- a/plotnine/stats/stat_ecdf.py +++ b/plotnine/stats/stat_ecdf.py @@ -43,6 +43,7 @@ class stat_ecdf(stat): DEFAULT_PARAMS = {"geom": "step", "n": None, "pad": True} DEFAULT_AES = {"y": after_stat("ecdf")} CREATES = {"ecdf"} + DROPPED_AES = ["weight"] def compute_group(self, data, scales): from statsmodels.distributions.empirical_distribution import ECDF diff --git a/plotnine/stats/stat_ellipse.py b/plotnine/stats/stat_ellipse.py index 9c182d5b3..ed0a83283 100644 --- a/plotnine/stats/stat_ellipse.py +++ b/plotnine/stats/stat_ellipse.py @@ -50,6 +50,7 @@ class stat_ellipse(stat): "level": 0.95, "segments": 51, } + DROPPED_AES = ["weight"] def compute_group(self, data, scales): import scipy.stats as stats diff --git a/plotnine/stats/stat_qq_line.py b/plotnine/stats/stat_qq_line.py index a9ad2a1f6..8471a2e56 100644 --- a/plotnine/stats/stat_qq_line.py +++ b/plotnine/stats/stat_qq_line.py @@ -62,6 +62,7 @@ class stat_qq_line(stat): "fullrange": False, } CREATES = {"x", "y"} + DROPPED_AES = ["sample"] def setup_params(self, data): if len(self.params["line_p"]) != 2: diff --git a/plotnine/stats/stat_quantile.py b/plotnine/stats/stat_quantile.py index 3ce65347d..65458d62d 100644 --- a/plotnine/stats/stat_quantile.py +++ b/plotnine/stats/stat_quantile.py @@ -55,6 +55,7 @@ class stat_quantile(stat): "method_args": {}, } CREATES = {"quantile", "group"} + DROPPED_AES = ["weight"] def setup_params(self, data): params = self.params diff --git a/plotnine/stats/stat_smooth.py b/plotnine/stats/stat_smooth.py index c180db949..0f2ced843 100644 --- a/plotnine/stats/stat_smooth.py +++ b/plotnine/stats/stat_smooth.py @@ -153,6 +153,7 @@ def my_smoother(data, xseq, params): "method_args": {}, } CREATES = {"se", "ymin", "ymax"} + DROPPED_AES = ["weight"] def setup_data(self, data): """ diff --git a/plotnine/stats/stat_ydensity.py b/plotnine/stats/stat_ydensity.py index 8b4efdf3d..35b5ea3ac 100644 --- a/plotnine/stats/stat_ydensity.py +++ b/plotnine/stats/stat_ydensity.py @@ -101,6 +101,7 @@ class stat_ydensity(stat): } DEFAULT_AES = {"weight": None} CREATES = {"width", "violinwidth"} + DROPPED_AES = ["weight"] def setup_data(self, data): if "x" not in data: