plotnine 0.15.0.dev2__py3-none-any.whl → 0.15.1__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 +128 -83
- plotnine/_mpl/layout_manager/_layout_tree.py +761 -310
- plotnine/_mpl/layout_manager/_spaces.py +320 -103
- 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 +21 -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 +11 -2
- 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 +8 -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 +28 -8
- 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 +85 -0
- plotnine/mapping/aes.py +91 -72
- plotnine/mapping/evaluation.py +7 -65
- 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 +45 -14
- 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 +110 -32
- plotnine/typing.py +17 -6
- plotnine/watermark.py +3 -3
- {plotnine-0.15.0.dev2.dist-info → plotnine-0.15.1.dist-info}/METADATA +13 -6
- plotnine-0.15.1.dist-info/RECORD +221 -0
- {plotnine-0.15.0.dev2.dist-info → plotnine-0.15.1.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.dev2.dist-info/RECORD +0 -214
- /plotnine/{plot_composition → composition}/_plotspec.py +0 -0
- {plotnine-0.15.0.dev2.dist-info → plotnine-0.15.1.dist-info}/licenses/LICENSE +0 -0
- {plotnine-0.15.0.dev2.dist-info → plotnine-0.15.1.dist-info}/top_level.txt +0 -0
plotnine/stats/smoothers.py
CHANGED
|
@@ -12,12 +12,9 @@ from ..exceptions import PlotnineError, PlotnineWarning
|
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
14
|
import statsmodels.api as sm
|
|
15
|
-
from patsy.eval import EvalEnvironment
|
|
16
15
|
|
|
17
|
-
from plotnine.mapping import Environment
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
def predictdf(data, xseq, **params) -> pd.DataFrame:
|
|
17
|
+
def predictdf(data, xseq, params) -> pd.DataFrame:
|
|
21
18
|
"""
|
|
22
19
|
Make prediction on the data
|
|
23
20
|
|
|
@@ -49,21 +46,21 @@ def predictdf(data, xseq, **params) -> pd.DataFrame:
|
|
|
49
46
|
if not callable(method):
|
|
50
47
|
msg = (
|
|
51
48
|
"'method' should either be a string or a function"
|
|
52
|
-
"with the signature `func(data, xseq,
|
|
49
|
+
"with the signature `func(data, xseq, params)`"
|
|
53
50
|
)
|
|
54
51
|
raise PlotnineError(msg)
|
|
55
52
|
|
|
56
|
-
return method(data, xseq,
|
|
53
|
+
return method(data, xseq, params)
|
|
57
54
|
|
|
58
55
|
|
|
59
|
-
def lm(data, xseq,
|
|
56
|
+
def lm(data, xseq, params) -> pd.DataFrame:
|
|
60
57
|
"""
|
|
61
58
|
Fit OLS / WLS if data has weight
|
|
62
59
|
"""
|
|
63
60
|
import statsmodels.api as sm
|
|
64
61
|
|
|
65
62
|
if params["formula"]:
|
|
66
|
-
return lm_formula(data, xseq,
|
|
63
|
+
return lm_formula(data, xseq, params)
|
|
67
64
|
|
|
68
65
|
X = sm.add_constant(data["x"])
|
|
69
66
|
Xseq = sm.add_constant(xseq)
|
|
@@ -96,14 +93,14 @@ def lm(data, xseq, **params) -> pd.DataFrame:
|
|
|
96
93
|
return data
|
|
97
94
|
|
|
98
95
|
|
|
99
|
-
def lm_formula(data, xseq,
|
|
96
|
+
def lm_formula(data, xseq, params) -> pd.DataFrame:
|
|
100
97
|
"""
|
|
101
98
|
Fit OLS / WLS using a formula
|
|
102
99
|
"""
|
|
103
100
|
import statsmodels.api as sm
|
|
104
101
|
import statsmodels.formula.api as smf
|
|
105
102
|
|
|
106
|
-
eval_env =
|
|
103
|
+
eval_env = params["environment"].to_patsy_env()
|
|
107
104
|
formula = params["formula"]
|
|
108
105
|
weights = data.get("weight", None)
|
|
109
106
|
|
|
@@ -140,14 +137,14 @@ def lm_formula(data, xseq, **params) -> pd.DataFrame:
|
|
|
140
137
|
return data
|
|
141
138
|
|
|
142
139
|
|
|
143
|
-
def rlm(data, xseq,
|
|
140
|
+
def rlm(data, xseq, params) -> pd.DataFrame:
|
|
144
141
|
"""
|
|
145
142
|
Fit RLM
|
|
146
143
|
"""
|
|
147
144
|
import statsmodels.api as sm
|
|
148
145
|
|
|
149
146
|
if params["formula"]:
|
|
150
|
-
return rlm_formula(data, xseq,
|
|
147
|
+
return rlm_formula(data, xseq, params)
|
|
151
148
|
|
|
152
149
|
X = sm.add_constant(data["x"])
|
|
153
150
|
Xseq = sm.add_constant(xseq)
|
|
@@ -170,14 +167,14 @@ def rlm(data, xseq, **params) -> pd.DataFrame:
|
|
|
170
167
|
return data
|
|
171
168
|
|
|
172
169
|
|
|
173
|
-
def rlm_formula(data, xseq,
|
|
170
|
+
def rlm_formula(data, xseq, params) -> pd.DataFrame:
|
|
174
171
|
"""
|
|
175
172
|
Fit RLM using a formula
|
|
176
173
|
"""
|
|
177
174
|
import statsmodels.api as sm
|
|
178
175
|
import statsmodels.formula.api as smf
|
|
179
176
|
|
|
180
|
-
eval_env =
|
|
177
|
+
eval_env = params["environment"].to_patsy_env()
|
|
181
178
|
formula = params["formula"]
|
|
182
179
|
init_kwargs, fit_kwargs = separate_method_kwargs(
|
|
183
180
|
params["method_args"], sm.RLM, sm.RLM.fit
|
|
@@ -196,14 +193,14 @@ def rlm_formula(data, xseq, **params) -> pd.DataFrame:
|
|
|
196
193
|
return data
|
|
197
194
|
|
|
198
195
|
|
|
199
|
-
def gls(data, xseq,
|
|
196
|
+
def gls(data, xseq, params) -> pd.DataFrame:
|
|
200
197
|
"""
|
|
201
198
|
Fit GLS
|
|
202
199
|
"""
|
|
203
200
|
import statsmodels.api as sm
|
|
204
201
|
|
|
205
202
|
if params["formula"]:
|
|
206
|
-
return gls_formula(data, xseq,
|
|
203
|
+
return gls_formula(data, xseq, params)
|
|
207
204
|
|
|
208
205
|
X = sm.add_constant(data["x"])
|
|
209
206
|
Xseq = sm.add_constant(xseq)
|
|
@@ -227,14 +224,14 @@ def gls(data, xseq, **params) -> pd.DataFrame:
|
|
|
227
224
|
return data
|
|
228
225
|
|
|
229
226
|
|
|
230
|
-
def gls_formula(data, xseq,
|
|
227
|
+
def gls_formula(data, xseq, params):
|
|
231
228
|
"""
|
|
232
229
|
Fit GLL using a formula
|
|
233
230
|
"""
|
|
234
231
|
import statsmodels.api as sm
|
|
235
232
|
import statsmodels.formula.api as smf
|
|
236
233
|
|
|
237
|
-
eval_env =
|
|
234
|
+
eval_env = params["environment"].to_patsy_env()
|
|
238
235
|
formula = params["formula"]
|
|
239
236
|
init_kwargs, fit_kwargs = separate_method_kwargs(
|
|
240
237
|
params["method_args"], sm.GLS, sm.GLS.fit
|
|
@@ -258,14 +255,14 @@ def gls_formula(data, xseq, **params):
|
|
|
258
255
|
return data
|
|
259
256
|
|
|
260
257
|
|
|
261
|
-
def glm(data, xseq,
|
|
258
|
+
def glm(data, xseq, params) -> pd.DataFrame:
|
|
262
259
|
"""
|
|
263
260
|
Fit GLM
|
|
264
261
|
"""
|
|
265
262
|
import statsmodels.api as sm
|
|
266
263
|
|
|
267
264
|
if params["formula"]:
|
|
268
|
-
return glm_formula(data, xseq,
|
|
265
|
+
return glm_formula(data, xseq, params)
|
|
269
266
|
|
|
270
267
|
X = sm.add_constant(data["x"])
|
|
271
268
|
Xseq = sm.add_constant(xseq)
|
|
@@ -292,14 +289,14 @@ def glm(data, xseq, **params) -> pd.DataFrame:
|
|
|
292
289
|
return data
|
|
293
290
|
|
|
294
291
|
|
|
295
|
-
def glm_formula(data, xseq,
|
|
292
|
+
def glm_formula(data, xseq, params):
|
|
296
293
|
"""
|
|
297
294
|
Fit with GLM formula
|
|
298
295
|
"""
|
|
299
296
|
import statsmodels.api as sm
|
|
300
297
|
import statsmodels.formula.api as smf
|
|
301
298
|
|
|
302
|
-
eval_env =
|
|
299
|
+
eval_env = params["environment"].to_patsy_env()
|
|
303
300
|
init_kwargs, fit_kwargs = separate_method_kwargs(
|
|
304
301
|
params["method_args"], sm.GLM, sm.GLM.fit
|
|
305
302
|
)
|
|
@@ -321,7 +318,7 @@ def glm_formula(data, xseq, **params):
|
|
|
321
318
|
return data
|
|
322
319
|
|
|
323
320
|
|
|
324
|
-
def lowess(data, xseq,
|
|
321
|
+
def lowess(data, xseq, params) -> pd.DataFrame:
|
|
325
322
|
"""
|
|
326
323
|
Lowess fitting
|
|
327
324
|
"""
|
|
@@ -351,7 +348,7 @@ def lowess(data, xseq, **params) -> pd.DataFrame:
|
|
|
351
348
|
return data
|
|
352
349
|
|
|
353
350
|
|
|
354
|
-
def loess(data, xseq,
|
|
351
|
+
def loess(data, xseq, params) -> pd.DataFrame:
|
|
355
352
|
"""
|
|
356
353
|
Loess smoothing
|
|
357
354
|
"""
|
|
@@ -402,7 +399,7 @@ def loess(data, xseq, **params) -> pd.DataFrame:
|
|
|
402
399
|
return data
|
|
403
400
|
|
|
404
401
|
|
|
405
|
-
def mavg(data, xseq,
|
|
402
|
+
def mavg(data, xseq, params) -> pd.DataFrame:
|
|
406
403
|
"""
|
|
407
404
|
Fit moving average
|
|
408
405
|
"""
|
|
@@ -426,7 +423,7 @@ def mavg(data, xseq, **params) -> pd.DataFrame:
|
|
|
426
423
|
return data
|
|
427
424
|
|
|
428
425
|
|
|
429
|
-
def gpr(data, xseq,
|
|
426
|
+
def gpr(data, xseq, params):
|
|
430
427
|
"""
|
|
431
428
|
Fit gaussian process
|
|
432
429
|
"""
|
|
@@ -593,16 +590,6 @@ def separate_method_kwargs(method_args, init_method, fit_method):
|
|
|
593
590
|
return init_kwargs, fit_kwargs
|
|
594
591
|
|
|
595
592
|
|
|
596
|
-
def _to_patsy_env(environment: Environment) -> EvalEnvironment:
|
|
597
|
-
"""
|
|
598
|
-
Convert a plotnine environment to a patsy environment
|
|
599
|
-
"""
|
|
600
|
-
from patsy.eval import EvalEnvironment
|
|
601
|
-
|
|
602
|
-
eval_env = EvalEnvironment(environment.namespaces)
|
|
603
|
-
return eval_env
|
|
604
|
-
|
|
605
|
-
|
|
606
593
|
def _glm_family(family: str) -> sm.families.Family:
|
|
607
594
|
"""
|
|
608
595
|
Get glm-family instance
|
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
|
"""
|