plotnine 0.15.0.dev3__py3-none-any.whl → 0.15.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plotnine/__init__.py +2 -0
- plotnine/_mpl/layout_manager/_engine.py +1 -1
- plotnine/_mpl/layout_manager/_layout_items.py +126 -41
- plotnine/_mpl/layout_manager/_layout_tree.py +712 -314
- plotnine/_mpl/layout_manager/_spaces.py +305 -101
- plotnine/_mpl/patches.py +70 -34
- plotnine/_mpl/text.py +144 -63
- plotnine/_mpl/utils.py +1 -1
- plotnine/_utils/__init__.py +50 -107
- plotnine/_utils/context.py +78 -2
- plotnine/_utils/ipython.py +35 -51
- plotnine/_utils/quarto.py +26 -0
- plotnine/_utils/yippie.py +115 -0
- plotnine/composition/__init__.py +11 -0
- plotnine/composition/_beside.py +55 -0
- plotnine/composition/_compose.py +471 -0
- plotnine/composition/_plot_spacer.py +60 -0
- plotnine/composition/_stack.py +55 -0
- plotnine/coords/coord.py +3 -3
- plotnine/data/__init__.py +31 -0
- plotnine/data/anscombe-quartet.csv +45 -0
- plotnine/doctools.py +4 -4
- plotnine/facets/facet.py +4 -4
- plotnine/facets/strips.py +17 -28
- plotnine/geoms/annotate.py +13 -13
- plotnine/geoms/annotation_logticks.py +7 -8
- plotnine/geoms/annotation_stripes.py +6 -6
- plotnine/geoms/geom.py +60 -27
- plotnine/geoms/geom_abline.py +3 -2
- plotnine/geoms/geom_area.py +2 -2
- plotnine/geoms/geom_bar.py +1 -0
- plotnine/geoms/geom_bin_2d.py +6 -2
- plotnine/geoms/geom_blank.py +0 -3
- plotnine/geoms/geom_boxplot.py +8 -4
- plotnine/geoms/geom_col.py +2 -2
- plotnine/geoms/geom_count.py +6 -2
- plotnine/geoms/geom_crossbar.py +3 -3
- plotnine/geoms/geom_density_2d.py +6 -2
- plotnine/geoms/geom_dotplot.py +2 -2
- plotnine/geoms/geom_errorbar.py +2 -2
- plotnine/geoms/geom_errorbarh.py +2 -2
- plotnine/geoms/geom_histogram.py +1 -1
- plotnine/geoms/geom_hline.py +3 -2
- plotnine/geoms/geom_linerange.py +2 -2
- plotnine/geoms/geom_map.py +5 -5
- plotnine/geoms/geom_path.py +11 -12
- plotnine/geoms/geom_point.py +4 -5
- plotnine/geoms/geom_pointdensity.py +4 -0
- plotnine/geoms/geom_pointrange.py +3 -5
- plotnine/geoms/geom_polygon.py +2 -3
- plotnine/geoms/geom_qq.py +4 -0
- plotnine/geoms/geom_qq_line.py +4 -0
- plotnine/geoms/geom_quantile.py +4 -0
- plotnine/geoms/geom_raster.py +4 -5
- plotnine/geoms/geom_rect.py +3 -4
- plotnine/geoms/geom_ribbon.py +7 -7
- plotnine/geoms/geom_rug.py +1 -1
- plotnine/geoms/geom_segment.py +2 -2
- plotnine/geoms/geom_sina.py +3 -3
- plotnine/geoms/geom_smooth.py +7 -3
- plotnine/geoms/geom_step.py +2 -2
- plotnine/geoms/geom_text.py +2 -3
- plotnine/geoms/geom_violin.py +8 -5
- plotnine/geoms/geom_vline.py +3 -2
- plotnine/ggplot.py +64 -85
- plotnine/guides/guide.py +7 -10
- plotnine/guides/guide_colorbar.py +3 -3
- plotnine/guides/guide_legend.py +3 -3
- plotnine/guides/guides.py +6 -6
- plotnine/helpers.py +49 -0
- plotnine/iapi.py +28 -5
- plotnine/labels.py +3 -3
- plotnine/layer.py +36 -19
- plotnine/mapping/_atomic.py +178 -0
- plotnine/mapping/_env.py +13 -2
- plotnine/mapping/_eval_environment.py +1 -1
- plotnine/mapping/aes.py +85 -49
- plotnine/scales/__init__.py +2 -0
- plotnine/scales/limits.py +7 -7
- plotnine/scales/scale.py +3 -3
- plotnine/scales/scale_color.py +82 -18
- plotnine/scales/scale_continuous.py +6 -4
- plotnine/scales/scale_datetime.py +28 -14
- plotnine/scales/scale_discrete.py +1 -1
- plotnine/scales/scale_identity.py +21 -2
- plotnine/scales/scale_manual.py +8 -2
- plotnine/scales/scale_xy.py +2 -2
- plotnine/stats/binning.py +4 -1
- plotnine/stats/smoothers.py +23 -36
- plotnine/stats/stat.py +20 -32
- plotnine/stats/stat_bin.py +6 -5
- plotnine/stats/stat_bin_2d.py +11 -9
- plotnine/stats/stat_bindot.py +13 -16
- plotnine/stats/stat_boxplot.py +6 -6
- plotnine/stats/stat_count.py +6 -9
- plotnine/stats/stat_density.py +7 -10
- plotnine/stats/stat_density_2d.py +12 -8
- plotnine/stats/stat_ecdf.py +7 -6
- plotnine/stats/stat_ellipse.py +9 -6
- plotnine/stats/stat_function.py +10 -8
- plotnine/stats/stat_hull.py +6 -3
- plotnine/stats/stat_identity.py +5 -2
- plotnine/stats/stat_pointdensity.py +5 -7
- plotnine/stats/stat_qq.py +46 -20
- plotnine/stats/stat_qq_line.py +16 -11
- plotnine/stats/stat_quantile.py +15 -9
- plotnine/stats/stat_sina.py +13 -15
- plotnine/stats/stat_smooth.py +8 -10
- plotnine/stats/stat_sum.py +5 -2
- plotnine/stats/stat_summary.py +7 -10
- plotnine/stats/stat_summary_bin.py +11 -14
- plotnine/stats/stat_unique.py +5 -2
- plotnine/stats/stat_ydensity.py +8 -11
- plotnine/themes/elements/__init__.py +2 -1
- plotnine/themes/elements/element_line.py +17 -9
- plotnine/themes/elements/margin.py +64 -1
- plotnine/themes/theme.py +9 -1
- plotnine/themes/theme_538.py +0 -1
- plotnine/themes/theme_bw.py +0 -1
- plotnine/themes/theme_dark.py +0 -1
- plotnine/themes/theme_gray.py +6 -5
- plotnine/themes/theme_light.py +1 -1
- plotnine/themes/theme_matplotlib.py +5 -5
- plotnine/themes/theme_seaborn.py +7 -4
- plotnine/themes/theme_void.py +9 -8
- plotnine/themes/theme_xkcd.py +0 -1
- plotnine/themes/themeable.py +109 -31
- plotnine/typing.py +17 -6
- plotnine/watermark.py +3 -3
- {plotnine-0.15.0.dev3.dist-info → plotnine-0.15.2.dist-info}/METADATA +13 -6
- plotnine-0.15.2.dist-info/RECORD +221 -0
- {plotnine-0.15.0.dev3.dist-info → plotnine-0.15.2.dist-info}/WHEEL +1 -1
- plotnine/plot_composition/__init__.py +0 -10
- plotnine/plot_composition/_compose.py +0 -436
- plotnine/plot_composition/_spacer.py +0 -32
- plotnine-0.15.0.dev3.dist-info/RECORD +0 -215
- /plotnine/{plot_composition → composition}/_plotspec.py +0 -0
- {plotnine-0.15.0.dev3.dist-info → plotnine-0.15.2.dist-info}/licenses/LICENSE +0 -0
- {plotnine-0.15.0.dev3.dist-info → plotnine-0.15.2.dist-info}/top_level.txt +0 -0
plotnine/stats/stat.py
CHANGED
|
@@ -64,7 +64,7 @@ class stat(ABC, metaclass=Register):
|
|
|
64
64
|
|
|
65
65
|
# Plot namespace, it gets its value when the plot is being
|
|
66
66
|
# built.
|
|
67
|
-
environment: Environment
|
|
67
|
+
environment: Environment
|
|
68
68
|
|
|
69
69
|
def __init__(
|
|
70
70
|
self,
|
|
@@ -195,9 +195,9 @@ class stat(ABC, metaclass=Register):
|
|
|
195
195
|
|
|
196
196
|
return data
|
|
197
197
|
|
|
198
|
-
def setup_params(self, data: pd.DataFrame)
|
|
198
|
+
def setup_params(self, data: pd.DataFrame):
|
|
199
199
|
"""
|
|
200
|
-
Override this to verify or adjust parameters
|
|
200
|
+
Override this to verify and/or adjust parameters
|
|
201
201
|
|
|
202
202
|
Parameters
|
|
203
203
|
----------
|
|
@@ -209,7 +209,6 @@ class stat(ABC, metaclass=Register):
|
|
|
209
209
|
out :
|
|
210
210
|
Parameters used by the stats.
|
|
211
211
|
"""
|
|
212
|
-
return self.params
|
|
213
212
|
|
|
214
213
|
def setup_data(self, data: pd.DataFrame) -> pd.DataFrame:
|
|
215
214
|
"""
|
|
@@ -227,9 +226,7 @@ class stat(ABC, metaclass=Register):
|
|
|
227
226
|
"""
|
|
228
227
|
return data
|
|
229
228
|
|
|
230
|
-
def finish_layer(
|
|
231
|
-
self, data: pd.DataFrame, params: dict[str, Any]
|
|
232
|
-
) -> pd.DataFrame:
|
|
229
|
+
def finish_layer(self, data: pd.DataFrame) -> pd.DataFrame:
|
|
233
230
|
"""
|
|
234
231
|
Modify data after the aesthetics have been mapped
|
|
235
232
|
|
|
@@ -257,9 +254,8 @@ class stat(ABC, metaclass=Register):
|
|
|
257
254
|
"""
|
|
258
255
|
return data
|
|
259
256
|
|
|
260
|
-
@classmethod
|
|
261
257
|
def compute_layer(
|
|
262
|
-
|
|
258
|
+
self, data: pd.DataFrame, layout: Layout
|
|
263
259
|
) -> pd.DataFrame:
|
|
264
260
|
"""
|
|
265
261
|
Calculate statistics for this layers
|
|
@@ -275,22 +271,20 @@ class stat(ABC, metaclass=Register):
|
|
|
275
271
|
----------
|
|
276
272
|
data :
|
|
277
273
|
Data points for all objects in a layer.
|
|
278
|
-
params :
|
|
279
|
-
Stat parameters
|
|
280
274
|
layout :
|
|
281
275
|
Panel layout information
|
|
282
276
|
"""
|
|
283
277
|
check_required_aesthetics(
|
|
284
|
-
|
|
285
|
-
list(data.columns) + list(params.keys()),
|
|
286
|
-
|
|
278
|
+
self.REQUIRED_AES,
|
|
279
|
+
list(data.columns) + list(self.params.keys()),
|
|
280
|
+
self.__class__.__name__,
|
|
287
281
|
)
|
|
288
282
|
|
|
289
283
|
data = remove_missing(
|
|
290
284
|
data,
|
|
291
|
-
na_rm=params.get("na_rm", False),
|
|
292
|
-
vars=list(
|
|
293
|
-
name=
|
|
285
|
+
na_rm=self.params.get("na_rm", False),
|
|
286
|
+
vars=list(self.REQUIRED_AES | self.NON_MISSING_AES),
|
|
287
|
+
name=self.__class__.__name__,
|
|
294
288
|
finite=True,
|
|
295
289
|
)
|
|
296
290
|
|
|
@@ -304,14 +298,11 @@ class stat(ABC, metaclass=Register):
|
|
|
304
298
|
if len(pdata) == 0:
|
|
305
299
|
return pdata
|
|
306
300
|
pscales = layout.get_scales(pdata["PANEL"].iloc[0])
|
|
307
|
-
return
|
|
301
|
+
return self.compute_panel(pdata, pscales)
|
|
308
302
|
|
|
309
303
|
return groupby_apply(data, "PANEL", fn)
|
|
310
304
|
|
|
311
|
-
|
|
312
|
-
def compute_panel(
|
|
313
|
-
cls, data: pd.DataFrame, scales: pos_scales, **params: Any
|
|
314
|
-
):
|
|
305
|
+
def compute_panel(self, data: pd.DataFrame, scales: pos_scales):
|
|
315
306
|
"""
|
|
316
307
|
Calculate the statistics for all the groups
|
|
317
308
|
|
|
@@ -341,14 +332,12 @@ class stat(ABC, metaclass=Register):
|
|
|
341
332
|
|
|
342
333
|
stats = []
|
|
343
334
|
for _, old in data.groupby("group"):
|
|
344
|
-
new =
|
|
335
|
+
new = self.compute_group(old, scales)
|
|
345
336
|
new.reset_index(drop=True, inplace=True)
|
|
346
337
|
unique = uniquecols(old)
|
|
347
338
|
missing = unique.columns.difference(new.columns)
|
|
348
339
|
idx = [0] * len(new)
|
|
349
|
-
u = unique.loc[idx, missing].reset_index(
|
|
350
|
-
drop=True
|
|
351
|
-
)
|
|
340
|
+
u = unique.loc[idx, missing].reset_index(drop=True)
|
|
352
341
|
# concat can have problems with empty dataframes that
|
|
353
342
|
# have an index
|
|
354
343
|
if u.empty and len(u):
|
|
@@ -365,9 +354,8 @@ class stat(ABC, metaclass=Register):
|
|
|
365
354
|
# it completely.
|
|
366
355
|
return stats
|
|
367
356
|
|
|
368
|
-
@classmethod
|
|
369
357
|
def compute_group(
|
|
370
|
-
|
|
358
|
+
self, data: pd.DataFrame, scales: pos_scales
|
|
371
359
|
) -> pd.DataFrame:
|
|
372
360
|
"""
|
|
373
361
|
Calculate statistics for the group
|
|
@@ -390,9 +378,9 @@ class stat(ABC, metaclass=Register):
|
|
|
390
378
|
Parameters
|
|
391
379
|
"""
|
|
392
380
|
msg = "{} should implement this method."
|
|
393
|
-
raise NotImplementedError(msg.format(
|
|
381
|
+
raise NotImplementedError(msg.format(self.__class__.__name__))
|
|
394
382
|
|
|
395
|
-
def __radd__(self,
|
|
383
|
+
def __radd__(self, other: ggplot) -> ggplot:
|
|
396
384
|
"""
|
|
397
385
|
Add layer representing stat object on the right
|
|
398
386
|
|
|
@@ -406,8 +394,8 @@ class stat(ABC, metaclass=Register):
|
|
|
406
394
|
out :
|
|
407
395
|
ggplot object with added layer
|
|
408
396
|
"""
|
|
409
|
-
|
|
410
|
-
return
|
|
397
|
+
other += self.to_layer() # Add layer
|
|
398
|
+
return other
|
|
411
399
|
|
|
412
400
|
def to_layer(self) -> layer:
|
|
413
401
|
"""
|
plotnine/stats/stat_bin.py
CHANGED
|
@@ -53,6 +53,10 @@ class stat_bin(stat):
|
|
|
53
53
|
pad : bool, default=False
|
|
54
54
|
If `True`{.py}, adds empty bins at either side of x.
|
|
55
55
|
This ensures that frequency polygons touch 0.
|
|
56
|
+
|
|
57
|
+
See Also
|
|
58
|
+
--------
|
|
59
|
+
plotnine.histogram : The default `geom` for this `stat`.
|
|
56
60
|
"""
|
|
57
61
|
|
|
58
62
|
_aesthetics_doc = """
|
|
@@ -100,7 +104,6 @@ class stat_bin(stat):
|
|
|
100
104
|
and params["binwidth"] is None
|
|
101
105
|
and params["bins"] is None
|
|
102
106
|
):
|
|
103
|
-
params = params.copy()
|
|
104
107
|
params["bins"] = freedman_diaconis_bins(data["x"])
|
|
105
108
|
msg = (
|
|
106
109
|
"'stat_bin()' using 'bins = {}'. "
|
|
@@ -108,10 +111,8 @@ class stat_bin(stat):
|
|
|
108
111
|
)
|
|
109
112
|
warn(msg.format(params["bins"]), PlotnineWarning)
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
@classmethod
|
|
114
|
-
def compute_group(cls, data, scales, **params):
|
|
114
|
+
def compute_group(self, data, scales):
|
|
115
|
+
params = self.params
|
|
115
116
|
if params["breaks"] is not None:
|
|
116
117
|
breaks = np.asarray(params["breaks"])
|
|
117
118
|
if hasattr(scales.x, "transform"):
|
plotnine/stats/stat_bin_2d.py
CHANGED
|
@@ -35,6 +35,10 @@ class stat_bin_2d(stat):
|
|
|
35
35
|
the stories in your data.
|
|
36
36
|
drop : bool, default=False
|
|
37
37
|
If `True`{.py}, removes all cells with zero counts.
|
|
38
|
+
|
|
39
|
+
See Also
|
|
40
|
+
--------
|
|
41
|
+
plotnine.geom_rect : The default `geom` for this `stat`.
|
|
38
42
|
"""
|
|
39
43
|
|
|
40
44
|
_aesthetics_doc = """
|
|
@@ -66,18 +70,16 @@ class stat_bin_2d(stat):
|
|
|
66
70
|
CREATES = {"xmin", "xmax", "ymin", "ymax", "count", "density"}
|
|
67
71
|
|
|
68
72
|
def setup_params(self, data):
|
|
69
|
-
params = self.params
|
|
73
|
+
params = self.params
|
|
70
74
|
params["bins"] = dual_param(params["bins"])
|
|
71
75
|
params["breaks"] = dual_param(params["breaks"])
|
|
72
76
|
params["binwidth"] = dual_param(params["binwidth"])
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
binwidth = params["binwidth"]
|
|
80
|
-
drop = params["drop"]
|
|
77
|
+
|
|
78
|
+
def compute_group(self, data, scales):
|
|
79
|
+
bins = self.params["bins"]
|
|
80
|
+
breaks = self.params["breaks"]
|
|
81
|
+
binwidth = self.params["binwidth"]
|
|
82
|
+
drop = self.params["drop"]
|
|
81
83
|
weight = data.get("weight")
|
|
82
84
|
|
|
83
85
|
if weight is None:
|
plotnine/stats/stat_bindot.py
CHANGED
|
@@ -68,6 +68,7 @@ class stat_bindot(stat):
|
|
|
68
68
|
|
|
69
69
|
See Also
|
|
70
70
|
--------
|
|
71
|
+
plotnine.geom_dotplot : The default `geom` for this `stat`.
|
|
71
72
|
plotnine.stat_bin
|
|
72
73
|
"""
|
|
73
74
|
|
|
@@ -113,18 +114,16 @@ class stat_bindot(stat):
|
|
|
113
114
|
and params["binwidth"] is None
|
|
114
115
|
and params["bins"] is None
|
|
115
116
|
):
|
|
116
|
-
|
|
117
|
-
params["bins"] =
|
|
118
|
-
|
|
119
|
-
"'
|
|
120
|
-
"Pick better value with 'binwidth'
|
|
117
|
+
bins = freedman_diaconis_bins(data["x"])
|
|
118
|
+
params["bins"] = bins
|
|
119
|
+
warn(
|
|
120
|
+
f"'stat_bindot' is using '{bins=}'. "
|
|
121
|
+
"Pick better value with 'binwidth'",
|
|
122
|
+
PlotnineWarning,
|
|
121
123
|
)
|
|
122
|
-
warn(msg.format(params["bins"]), PlotnineWarning)
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
@classmethod
|
|
127
|
-
def compute_panel(cls, data, scales, **params):
|
|
125
|
+
def compute_panel(self, data, scales):
|
|
126
|
+
params = self.params
|
|
128
127
|
if (
|
|
129
128
|
params["method"] == "dotdensity"
|
|
130
129
|
and params["binpositions"] == "all"
|
|
@@ -160,10 +159,10 @@ class stat_bindot(stat):
|
|
|
160
159
|
data["binwidth"] = newdata["binwidth"]
|
|
161
160
|
data["weight"] = newdata["weight"]
|
|
162
161
|
data["bincenter"] = newdata["bincenter"]
|
|
163
|
-
return super(
|
|
162
|
+
return super().compute_panel(data, scales)
|
|
164
163
|
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
def compute_group(self, data, scales):
|
|
165
|
+
params = self.params
|
|
167
166
|
# Check that weights are whole numbers
|
|
168
167
|
# (for dots, weights must be whole)
|
|
169
168
|
weight = data.get("weight")
|
|
@@ -281,9 +280,7 @@ def densitybin(
|
|
|
281
280
|
if all(pd.isna(x)):
|
|
282
281
|
return pd.DataFrame()
|
|
283
282
|
|
|
284
|
-
if weight is None
|
|
285
|
-
weight = np.ones(len(x))
|
|
286
|
-
weight = np.asarray(weight)
|
|
283
|
+
weight = np.ones(len(x)) if weight is None else np.array(list(weight))
|
|
287
284
|
weight[np.isnan(weight)] = 0
|
|
288
285
|
|
|
289
286
|
if rangee is None:
|
plotnine/stats/stat_boxplot.py
CHANGED
|
@@ -22,7 +22,7 @@ class stat_boxplot(stat):
|
|
|
22
22
|
|
|
23
23
|
See Also
|
|
24
24
|
--------
|
|
25
|
-
plotnine.geom_boxplot
|
|
25
|
+
plotnine.geom_boxplot: The default `geom` for this `stat`.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
28
|
_aesthetics_doc = """
|
|
@@ -91,10 +91,8 @@ class stat_boxplot(stat):
|
|
|
91
91
|
if self.params["width"] is None:
|
|
92
92
|
x = data.get("x", 0)
|
|
93
93
|
self.params["width"] = resolution(x, False) * 0.75
|
|
94
|
-
return self.params
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
def compute_group(cls, data, scales, **params):
|
|
95
|
+
def compute_group(self, data, scales):
|
|
98
96
|
n = len(data)
|
|
99
97
|
y = data["y"].to_numpy()
|
|
100
98
|
if "weight" in data:
|
|
@@ -103,12 +101,14 @@ class stat_boxplot(stat):
|
|
|
103
101
|
else:
|
|
104
102
|
weights = None
|
|
105
103
|
total_weight = len(y)
|
|
106
|
-
res = weighted_boxplot_stats(
|
|
104
|
+
res = weighted_boxplot_stats(
|
|
105
|
+
y, weights=weights, whis=self.params["coef"]
|
|
106
|
+
)
|
|
107
107
|
|
|
108
108
|
if len(np.unique(data["x"])) > 1:
|
|
109
109
|
width = np.ptp(data["x"]) * 0.9
|
|
110
110
|
else:
|
|
111
|
-
width = params["width"]
|
|
111
|
+
width = self.params["width"]
|
|
112
112
|
|
|
113
113
|
if isinstance(data["x"].dtype, pd.CategoricalDtype):
|
|
114
114
|
x = data["x"].iloc[0]
|
plotnine/stats/stat_count.py
CHANGED
|
@@ -23,6 +23,7 @@ class stat_count(stat):
|
|
|
23
23
|
|
|
24
24
|
See Also
|
|
25
25
|
--------
|
|
26
|
+
plotnine.geom_histogram : The default `geom` for this `stat`.
|
|
26
27
|
plotnine.stat_bin
|
|
27
28
|
"""
|
|
28
29
|
|
|
@@ -49,21 +50,17 @@ class stat_count(stat):
|
|
|
49
50
|
CREATES = {"count", "prop"}
|
|
50
51
|
|
|
51
52
|
def setup_params(self, data):
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
params["width"] = resolution(data["x"], False) * 0.9
|
|
53
|
+
if self.params["width"] is None:
|
|
54
|
+
self.params["width"] = resolution(data["x"], False) * 0.9
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@classmethod
|
|
59
|
-
def compute_group(cls, data, scales, **params):
|
|
56
|
+
def compute_group(self, data, scales):
|
|
60
57
|
x = data["x"]
|
|
61
|
-
if ("y" in data) or ("y" in params):
|
|
58
|
+
if ("y" in data) or ("y" in self.params):
|
|
62
59
|
msg = "stat_count() must not be used with a y aesthetic"
|
|
63
60
|
raise PlotnineError(msg)
|
|
64
61
|
|
|
65
62
|
weight = data.get("weight", [1] * len(x))
|
|
66
|
-
width = params["width"]
|
|
63
|
+
width = self.params["width"]
|
|
67
64
|
xdata_long = pd.DataFrame({"x": x, "weight": weight})
|
|
68
65
|
# weighted frequency count
|
|
69
66
|
count = xdata_long.pivot_table("weight", index=["x"], aggfunc="sum")[
|
plotnine/stats/stat_density.py
CHANGED
|
@@ -85,7 +85,7 @@ class stat_density(stat):
|
|
|
85
85
|
|
|
86
86
|
See Also
|
|
87
87
|
--------
|
|
88
|
-
plotnine.geom_density
|
|
88
|
+
plotnine.geom_density : The default `geom` for this `stat`.
|
|
89
89
|
statsmodels.nonparametric.kde.KDEUnivariate
|
|
90
90
|
statsmodels.nonparametric.kde.KDEUnivariate.fit
|
|
91
91
|
"""
|
|
@@ -102,9 +102,9 @@ class stat_density(stat):
|
|
|
102
102
|
# useful for stacked density plots
|
|
103
103
|
|
|
104
104
|
'scaled' # density estimate, scaled to maximum of 1
|
|
105
|
+
'n' # Number of observations at a position
|
|
105
106
|
```
|
|
106
107
|
|
|
107
|
-
'n' # Number of observations at a position
|
|
108
108
|
|
|
109
109
|
"""
|
|
110
110
|
REQUIRED_AES = {"x"}
|
|
@@ -126,7 +126,7 @@ class stat_density(stat):
|
|
|
126
126
|
CREATES = {"density", "count", "scaled", "n"}
|
|
127
127
|
|
|
128
128
|
def setup_params(self, data):
|
|
129
|
-
params = self.params
|
|
129
|
+
params = self.params
|
|
130
130
|
lookup = {
|
|
131
131
|
"biweight": "biw",
|
|
132
132
|
"cosine": "cos",
|
|
@@ -148,21 +148,18 @@ class stat_density(stat):
|
|
|
148
148
|
)
|
|
149
149
|
raise PlotnineError(msg)
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
@classmethod
|
|
154
|
-
def compute_group(cls, data, scales, **params):
|
|
151
|
+
def compute_group(self, data, scales):
|
|
155
152
|
weight = data.get("weight")
|
|
156
153
|
|
|
157
|
-
if params["trim"]:
|
|
154
|
+
if self.params["trim"]:
|
|
158
155
|
range_x = data["x"].min(), data["x"].max()
|
|
159
156
|
else:
|
|
160
157
|
range_x = scales.x.dimension()
|
|
161
158
|
|
|
162
|
-
return compute_density(data["x"], weight, range_x,
|
|
159
|
+
return compute_density(data["x"], weight, range_x, self.params)
|
|
163
160
|
|
|
164
161
|
|
|
165
|
-
def compute_density(x, weight, range,
|
|
162
|
+
def compute_density(x, weight, range, params):
|
|
166
163
|
"""
|
|
167
164
|
Compute density
|
|
168
165
|
"""
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
1
5
|
import numpy as np
|
|
2
6
|
import pandas as pd
|
|
3
7
|
|
|
4
|
-
from ..doctools import document
|
|
5
8
|
from .density import get_var_type, kde
|
|
6
9
|
from .stat import stat
|
|
7
10
|
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from plotnine.typing import FloatArrayLike
|
|
13
|
+
|
|
8
14
|
|
|
9
|
-
@document
|
|
10
15
|
class stat_density_2d(stat):
|
|
11
16
|
"""
|
|
12
17
|
Compute 2D kernel density estimation
|
|
@@ -32,6 +37,7 @@ class stat_density_2d(stat):
|
|
|
32
37
|
|
|
33
38
|
See Also
|
|
34
39
|
--------
|
|
40
|
+
plotnine.geom_density_2d : The default `geom` for this `stat`.
|
|
35
41
|
statsmodels.nonparametric.kernel_density.KDEMultivariate
|
|
36
42
|
scipy.stats.gaussian_kde
|
|
37
43
|
sklearn.neighbors.KernelDensity
|
|
@@ -66,7 +72,7 @@ class stat_density_2d(stat):
|
|
|
66
72
|
CREATES = {"y"}
|
|
67
73
|
|
|
68
74
|
def setup_params(self, data):
|
|
69
|
-
params = self.params
|
|
75
|
+
params = self.params
|
|
70
76
|
if params["kde_params"] is None:
|
|
71
77
|
params["kde_params"] = {}
|
|
72
78
|
|
|
@@ -78,10 +84,8 @@ class stat_density_2d(stat):
|
|
|
78
84
|
y_type = get_var_type(data["y"])
|
|
79
85
|
kde_params["var_type"] = f"{x_type}{y_type}"
|
|
80
86
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
@classmethod
|
|
84
|
-
def compute_group(cls, data, scales, **params):
|
|
87
|
+
def compute_group(self, data, scales):
|
|
88
|
+
params = self.params
|
|
85
89
|
package = params["package"]
|
|
86
90
|
kde_params = params["kde_params"]
|
|
87
91
|
|
|
@@ -118,7 +122,7 @@ class stat_density_2d(stat):
|
|
|
118
122
|
return data
|
|
119
123
|
|
|
120
124
|
|
|
121
|
-
def contour_lines(X, Y, Z, levels):
|
|
125
|
+
def contour_lines(X, Y, Z, levels: int | FloatArrayLike):
|
|
122
126
|
"""
|
|
123
127
|
Calculate contour lines
|
|
124
128
|
"""
|
plotnine/stats/stat_ecdf.py
CHANGED
|
@@ -25,7 +25,7 @@ class stat_ecdf(stat):
|
|
|
25
25
|
|
|
26
26
|
See Also
|
|
27
27
|
--------
|
|
28
|
-
plotnine.geom_step
|
|
28
|
+
plotnine.geom_step : The default `geom` for this `stat`.
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
31
|
_aesthetics_doc = """
|
|
@@ -50,17 +50,18 @@ class stat_ecdf(stat):
|
|
|
50
50
|
DEFAULT_AES = {"y": after_stat("ecdf")}
|
|
51
51
|
CREATES = {"ecdf"}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
def compute_group(cls, data, scales, **params):
|
|
53
|
+
def compute_group(self, data, scales):
|
|
55
54
|
from statsmodels.distributions.empirical_distribution import ECDF
|
|
56
55
|
|
|
56
|
+
n, pad = self.params["n"], self.params["pad"]
|
|
57
|
+
|
|
57
58
|
# If n is None, use raw values; otherwise interpolate
|
|
58
|
-
if
|
|
59
|
+
if n is None:
|
|
59
60
|
x = np.unique(data["x"])
|
|
60
61
|
else:
|
|
61
|
-
x = np.linspace(data["x"].min(), data["x"].max(),
|
|
62
|
+
x = np.linspace(data["x"].min(), data["x"].max(), n)
|
|
62
63
|
|
|
63
|
-
if
|
|
64
|
+
if pad:
|
|
64
65
|
x = np.hstack([-np.inf, x, np.inf])
|
|
65
66
|
|
|
66
67
|
ecdf = ECDF(data["x"].to_numpy())(x)
|
plotnine/stats/stat_ellipse.py
CHANGED
|
@@ -37,6 +37,10 @@ class stat_ellipse(stat):
|
|
|
37
37
|
The confidence level at which to draw the ellipse.
|
|
38
38
|
segments : int, default=51
|
|
39
39
|
Number of segments to be used in drawing the ellipse.
|
|
40
|
+
|
|
41
|
+
See Also
|
|
42
|
+
--------
|
|
43
|
+
plotnine.geom_path : The default `geom` for this `stat`.
|
|
40
44
|
"""
|
|
41
45
|
|
|
42
46
|
REQUIRED_AES = {"x", "y"}
|
|
@@ -49,14 +53,13 @@ class stat_ellipse(stat):
|
|
|
49
53
|
"segments": 51,
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
def compute_group(cls, data, scales, **params):
|
|
56
|
+
def compute_group(self, data, scales):
|
|
54
57
|
import scipy.stats as stats
|
|
55
58
|
from scipy import linalg
|
|
56
59
|
|
|
57
|
-
level = params["level"]
|
|
58
|
-
segments = params["segments"]
|
|
59
|
-
type_ = params["type"]
|
|
60
|
+
level = self.params["level"]
|
|
61
|
+
segments = self.params["segments"]
|
|
62
|
+
type_ = self.params["type"]
|
|
60
63
|
|
|
61
64
|
dfn = 2
|
|
62
65
|
dfd = len(data) - 1
|
|
@@ -203,7 +206,7 @@ def cov_trob(
|
|
|
203
206
|
wt = wt[wt > 0]
|
|
204
207
|
n, _ = x.shape
|
|
205
208
|
|
|
206
|
-
wt = wt[:, np.newaxis]
|
|
209
|
+
wt = wt[:, np.newaxis] # pyright: ignore[reportCallIssue,reportArgumentType,reportOptionalSubscript]
|
|
207
210
|
|
|
208
211
|
# loc
|
|
209
212
|
use_loc = False
|
plotnine/stats/stat_function.py
CHANGED
|
@@ -37,6 +37,10 @@ class stat_function(stat):
|
|
|
37
37
|
then the `xlim` must be provided.
|
|
38
38
|
args : Optional[tuple[Any] | dict[str, Any]], default=None
|
|
39
39
|
Arguments to pass to `fun`.
|
|
40
|
+
|
|
41
|
+
See Also
|
|
42
|
+
--------
|
|
43
|
+
plotnine.geom_path : The default `geom` for this `stat`.
|
|
40
44
|
"""
|
|
41
45
|
|
|
42
46
|
_aesthetics_doc = """
|
|
@@ -82,14 +86,12 @@ class stat_function(stat):
|
|
|
82
86
|
"stat_function requires parameter 'fun' to be "
|
|
83
87
|
"a function or any other callable object"
|
|
84
88
|
)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
args = params["args"]
|
|
92
|
-
xlim = params["xlim"]
|
|
89
|
+
|
|
90
|
+
def compute_group(self, data, scales):
|
|
91
|
+
old_fun: Callable[..., FloatArrayLike] = self.params["fun"]
|
|
92
|
+
n = self.params["n"]
|
|
93
|
+
args = self.params["args"]
|
|
94
|
+
xlim = self.params["xlim"]
|
|
93
95
|
range_x = xlim or scales.x.dimension((0, 0))
|
|
94
96
|
|
|
95
97
|
if isinstance(args, (list, tuple)):
|
plotnine/stats/stat_hull.py
CHANGED
|
@@ -26,6 +26,10 @@ class stat_hull(stat):
|
|
|
26
26
|
Raised when Qhull encounters an error condition,
|
|
27
27
|
such as geometrical degeneracy when options to resolve are
|
|
28
28
|
not enabled.
|
|
29
|
+
|
|
30
|
+
See Also
|
|
31
|
+
--------
|
|
32
|
+
plotnine.geom_path : The default `geom` for this `stat`.
|
|
29
33
|
"""
|
|
30
34
|
|
|
31
35
|
_aesthetics_doc = """
|
|
@@ -47,12 +51,11 @@ class stat_hull(stat):
|
|
|
47
51
|
}
|
|
48
52
|
CREATES = {"area"}
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
def compute_group(cls, data, scales, **params):
|
|
54
|
+
def compute_group(self, data, scales):
|
|
52
55
|
from scipy.spatial import ConvexHull
|
|
53
56
|
|
|
54
57
|
hull = ConvexHull(
|
|
55
|
-
data[["x", "y"]], qhull_options=params["qhull_options"]
|
|
58
|
+
data[["x", "y"]], qhull_options=self.params["qhull_options"]
|
|
56
59
|
)
|
|
57
60
|
idx = np.hstack([hull.vertices, hull.vertices[0]])
|
|
58
61
|
|
plotnine/stats/stat_identity.py
CHANGED
|
@@ -12,10 +12,13 @@ class stat_identity(stat):
|
|
|
12
12
|
Parameters
|
|
13
13
|
----------
|
|
14
14
|
{common_parameters}
|
|
15
|
+
|
|
16
|
+
See Also
|
|
17
|
+
--------
|
|
18
|
+
plotnine.geom_point : The default `geom` for this `stat`.
|
|
15
19
|
"""
|
|
16
20
|
|
|
17
21
|
DEFAULT_PARAMS = {"geom": "point", "position": "identity", "na_rm": False}
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
def compute_panel(cls, data, scales, **params):
|
|
23
|
+
def compute_panel(self, data, scales):
|
|
21
24
|
return data
|
|
@@ -24,6 +24,7 @@ class stat_pointdensity(stat):
|
|
|
24
24
|
|
|
25
25
|
See Also
|
|
26
26
|
--------
|
|
27
|
+
plotnine.geom_density_2d : The default `geom` for this `stat`.
|
|
27
28
|
statsmodels.nonparametric.kde.KDEMultivariate
|
|
28
29
|
scipy.stats.gaussian_kde
|
|
29
30
|
sklearn.neighbors.KernelDensity
|
|
@@ -51,7 +52,7 @@ class stat_pointdensity(stat):
|
|
|
51
52
|
CREATES = {"density"}
|
|
52
53
|
|
|
53
54
|
def setup_params(self, data):
|
|
54
|
-
params = self.params
|
|
55
|
+
params = self.params
|
|
55
56
|
if params["kde_params"] is None:
|
|
56
57
|
params["kde_params"] = {}
|
|
57
58
|
|
|
@@ -63,12 +64,9 @@ class stat_pointdensity(stat):
|
|
|
63
64
|
y_type = get_var_type(data["y"])
|
|
64
65
|
kde_params["var_type"] = f"{x_type}{y_type}"
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def compute_group(cls, data, scales, **params):
|
|
70
|
-
package = params["package"]
|
|
71
|
-
kde_params = params["kde_params"]
|
|
67
|
+
def compute_group(self, data, scales):
|
|
68
|
+
package = self.params["package"]
|
|
69
|
+
kde_params = self.params["kde_params"]
|
|
72
70
|
|
|
73
71
|
var_data = np.array([data["x"].to_numpy(), data["y"].to_numpy()]).T
|
|
74
72
|
density = kde(var_data, var_data, package, **kde_params)
|