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/doctools.py
CHANGED
|
@@ -71,7 +71,7 @@ STAT_SIGNATURE_TPL = """
|
|
|
71
71
|
|
|
72
72
|
common_params_doc = {
|
|
73
73
|
"mapping": """\
|
|
74
|
-
Aesthetic mappings created with [aes](:class:`plotnine.mapping.aes`). If \
|
|
74
|
+
Aesthetic mappings created with [aes](:class:`plotnine.mapping.aes.aes`). If \
|
|
75
75
|
specified and `inherit_aes=True`{.py}, it is combined with the default \
|
|
76
76
|
mapping for the plot. You must supply mapping if there is no plot mapping.""",
|
|
77
77
|
"data": """\
|
|
@@ -103,7 +103,7 @@ the final image is in vector format.""",
|
|
|
103
103
|
|
|
104
104
|
|
|
105
105
|
GEOM_PARAMS_TPL = """
|
|
106
|
-
mapping : ~plotnine.mapping.aes, default=None
|
|
106
|
+
mapping : ~plotnine.mapping.aes.aes, default=None
|
|
107
107
|
{mapping}
|
|
108
108
|
{_aesthetics_doc}
|
|
109
109
|
data : ~pandas.DataFrame, default=None
|
|
@@ -124,7 +124,7 @@ raster : bool, default={default_raster}
|
|
|
124
124
|
"""
|
|
125
125
|
|
|
126
126
|
STAT_PARAMS_TPL = """
|
|
127
|
-
mapping : ~plotnine.mapping.aes, default=None
|
|
127
|
+
mapping : ~plotnine.mapping.aes.aes, default=None
|
|
128
128
|
{mapping}
|
|
129
129
|
{_aesthetics_doc}
|
|
130
130
|
data : ~pandas.DataFrame, default=None
|
|
@@ -451,7 +451,7 @@ def document_geom(geom: type[geom]) -> type[geom]:
|
|
|
451
451
|
table = dict_to_table(("Aesthetic", "Default value"), contents)
|
|
452
452
|
aesthetics_table = AESTHETICS_TABLE_TPL.format(table=table)
|
|
453
453
|
tpl = dedent(geom._aesthetics_doc).strip()
|
|
454
|
-
aesthetics_doc = tpl.
|
|
454
|
+
aesthetics_doc = tpl.replace("{aesthetics_table}", aesthetics_table)
|
|
455
455
|
aesthetics_doc = indent(aesthetics_doc, " " * 4)
|
|
456
456
|
|
|
457
457
|
# common_parameters
|
plotnine/facets/facet.py
CHANGED
|
@@ -130,13 +130,13 @@ class facet:
|
|
|
130
130
|
"y": scales in ("free_y", "free"),
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
def __radd__(self,
|
|
133
|
+
def __radd__(self, other: ggplot) -> ggplot:
|
|
134
134
|
"""
|
|
135
135
|
Add facet to ggplot object
|
|
136
136
|
"""
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return
|
|
137
|
+
other.facet = copy(self)
|
|
138
|
+
other.facet.environment = other.environment
|
|
139
|
+
return other
|
|
140
140
|
|
|
141
141
|
def setup(self, plot: ggplot):
|
|
142
142
|
self.plot = plot
|
plotnine/facets/strips.py
CHANGED
|
@@ -67,56 +67,45 @@ class strip:
|
|
|
67
67
|
if position == "top":
|
|
68
68
|
# The x & y values are just starting locations
|
|
69
69
|
# The final location is determined by the layout manager.
|
|
70
|
-
|
|
70
|
+
bg_y = 1
|
|
71
71
|
ha = theme.getp(("strip_text_x", "ha"), "center")
|
|
72
|
-
va = theme.getp(("strip_text_x", "va"), "
|
|
72
|
+
va = theme.getp(("strip_text_x", "va"), "center")
|
|
73
73
|
rotation = theme.getp(("strip_text_x", "rotation"))
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
# TODO: Allow two unique paddings for either side.
|
|
77
|
-
# Requires implementing an mpl.patches.boxstyle that recognises
|
|
78
|
-
# two padding values.
|
|
79
|
-
strip_text_margin = (
|
|
80
|
-
theme.getp(("strip_text_x", "margin")).to("lines").b
|
|
81
|
-
)
|
|
74
|
+
bg_height = 0 # Determined by the text size
|
|
75
|
+
margin = theme.getp(("strip_text_x", "margin")).to("lines")
|
|
82
76
|
strip_align = theme.getp("strip_align_x")
|
|
83
77
|
|
|
84
78
|
# x & width properties of the background slide and
|
|
85
79
|
# shrink the strip horizontally.
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
bg_x = theme.getp(("strip_text_x", "x"), 0)
|
|
81
|
+
bg_width = theme.getp(("strip_background_x", "width"), 1)
|
|
88
82
|
|
|
89
83
|
elif position == "right":
|
|
90
84
|
# The x & y values are just starting locations
|
|
91
85
|
# The final location is determined by the layout manager.
|
|
92
|
-
|
|
93
|
-
ha = theme.getp(("strip_text_y", "ha"), "
|
|
86
|
+
bg_x = 1
|
|
87
|
+
ha = theme.getp(("strip_text_y", "ha"), "center")
|
|
94
88
|
va = theme.getp(("strip_text_y", "va"), "center")
|
|
95
89
|
rotation = theme.getp(("strip_text_y", "rotation"))
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
# Requires implementing an mpl.patches.boxstyle that recognises
|
|
99
|
-
# two padding values.
|
|
100
|
-
strip_text_margin = (
|
|
101
|
-
theme.getp(("strip_text_y", "margin")).to("lines").r
|
|
102
|
-
)
|
|
90
|
+
bg_width = 0 # Determine by the text height
|
|
91
|
+
margin = theme.getp(("strip_text_y", "margin")).to("lines")
|
|
103
92
|
strip_align = theme.getp("strip_align_y")
|
|
104
93
|
|
|
105
94
|
# y & height properties of the background slide and
|
|
106
95
|
# shrink the strip vertically.
|
|
107
|
-
|
|
108
|
-
|
|
96
|
+
bg_y = theme.getp(("strip_text_y", "y"), 0)
|
|
97
|
+
bg_height = theme.getp(("strip_background_y", "height"), 1)
|
|
109
98
|
else:
|
|
110
99
|
raise ValueError(f"Unknown position for strip text: {position!r}")
|
|
111
100
|
|
|
112
101
|
return strip_draw_info(
|
|
113
|
-
|
|
114
|
-
|
|
102
|
+
bg_x=bg_x,
|
|
103
|
+
bg_y=bg_y,
|
|
115
104
|
ha=ha,
|
|
116
105
|
va=va,
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
106
|
+
bg_width=bg_width,
|
|
107
|
+
bg_height=bg_height,
|
|
108
|
+
margin=margin,
|
|
120
109
|
strip_align=strip_align,
|
|
121
110
|
position=position,
|
|
122
111
|
label=self.label_info.text(),
|
plotnine/geoms/annotate.py
CHANGED
|
@@ -64,16 +64,16 @@ class annotate:
|
|
|
64
64
|
def __init__(
|
|
65
65
|
self,
|
|
66
66
|
geom: str | type[geom_base_class],
|
|
67
|
-
x: float | None = None,
|
|
68
|
-
y: float | None = None,
|
|
69
|
-
xmin: float | None = None,
|
|
70
|
-
xmax: float | None = None,
|
|
71
|
-
xend: float | None = None,
|
|
72
|
-
xintercept: float | None = None,
|
|
73
|
-
ymin: float | None = None,
|
|
74
|
-
ymax: float | None = None,
|
|
75
|
-
yend: float | None = None,
|
|
76
|
-
yintercept: float | None = None,
|
|
67
|
+
x: float | list[float] | None = None,
|
|
68
|
+
y: float | list[float] | None = None,
|
|
69
|
+
xmin: float | list[float] | None = None,
|
|
70
|
+
xmax: float | list[float] | None = None,
|
|
71
|
+
xend: float | list[float] | None = None,
|
|
72
|
+
xintercept: float | list[float] | None = None,
|
|
73
|
+
ymin: float | list[float] | None = None,
|
|
74
|
+
ymax: float | list[float] | None = None,
|
|
75
|
+
yend: float | list[float] | None = None,
|
|
76
|
+
yintercept: float | list[float] | None = None,
|
|
77
77
|
**kwargs: Any,
|
|
78
78
|
):
|
|
79
79
|
variables = locals()
|
|
@@ -131,12 +131,12 @@ class annotate:
|
|
|
131
131
|
**kwargs,
|
|
132
132
|
)
|
|
133
133
|
|
|
134
|
-
def __radd__(self,
|
|
134
|
+
def __radd__(self, other: ggplot) -> ggplot:
|
|
135
135
|
"""
|
|
136
136
|
Add to ggplot
|
|
137
137
|
"""
|
|
138
|
-
|
|
139
|
-
return
|
|
138
|
+
other += self.to_layer() # Add layer
|
|
139
|
+
return other
|
|
140
140
|
|
|
141
141
|
def to_layer(self) -> layer:
|
|
142
142
|
"""
|
|
@@ -46,9 +46,7 @@ class _geom_logticks(geom_rug):
|
|
|
46
46
|
}
|
|
47
47
|
draw_legend = staticmethod(geom_path.draw_legend)
|
|
48
48
|
|
|
49
|
-
def draw_layer(
|
|
50
|
-
self, data: pd.DataFrame, layout: Layout, coord: coord, **params: Any
|
|
51
|
-
):
|
|
49
|
+
def draw_layer(self, data: pd.DataFrame, layout: Layout, coord: coord):
|
|
52
50
|
"""
|
|
53
51
|
Draw ticks on every panel
|
|
54
52
|
"""
|
|
@@ -56,7 +54,7 @@ class _geom_logticks(geom_rug):
|
|
|
56
54
|
ploc = pid - 1
|
|
57
55
|
panel_params = layout.panel_params[ploc]
|
|
58
56
|
ax = layout.axs[ploc]
|
|
59
|
-
self.draw_panel(data, panel_params, coord, ax
|
|
57
|
+
self.draw_panel(data, panel_params, coord, ax)
|
|
60
58
|
|
|
61
59
|
@staticmethod
|
|
62
60
|
def _check_log_scale(
|
|
@@ -184,8 +182,8 @@ class _geom_logticks(geom_rug):
|
|
|
184
182
|
panel_params: panel_view,
|
|
185
183
|
coord: coord,
|
|
186
184
|
ax: Axes,
|
|
187
|
-
**params: Any,
|
|
188
185
|
):
|
|
186
|
+
params = self.params
|
|
189
187
|
# Any passed data is ignored, the relevant data is created
|
|
190
188
|
sides = params["sides"]
|
|
191
189
|
lengths = params["lengths"]
|
|
@@ -203,9 +201,8 @@ class _geom_logticks(geom_rug):
|
|
|
203
201
|
):
|
|
204
202
|
for position, length in zip(tick_positions, lengths):
|
|
205
203
|
data = pd.DataFrame({axis: position, **_aesthetics})
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
)
|
|
204
|
+
params["length"] = length
|
|
205
|
+
geom.draw_group(data, panel_params, coord, ax, params)
|
|
209
206
|
|
|
210
207
|
if isinstance(coord, coord_flip):
|
|
211
208
|
tick_range_x = panel_params.y.range
|
|
@@ -285,4 +282,6 @@ class annotation_logticks(annotate):
|
|
|
285
282
|
linetype=linetype,
|
|
286
283
|
lengths=lengths,
|
|
287
284
|
base=base,
|
|
285
|
+
inherit_aes=False,
|
|
286
|
+
show_legend=False,
|
|
288
287
|
)
|
|
@@ -72,6 +72,8 @@ class annotation_stripes(annotate):
|
|
|
72
72
|
fill_range=fill_range,
|
|
73
73
|
extend=extend,
|
|
74
74
|
direction=direction,
|
|
75
|
+
inherit_aes=False,
|
|
76
|
+
show_legend=False,
|
|
75
77
|
**kwargs,
|
|
76
78
|
)
|
|
77
79
|
|
|
@@ -94,9 +96,7 @@ class _geom_stripes(geom):
|
|
|
94
96
|
}
|
|
95
97
|
draw_legend = staticmethod(geom_polygon.draw_legend)
|
|
96
98
|
|
|
97
|
-
def draw_layer(
|
|
98
|
-
self, data: pd.DataFrame, layout: Layout, coord: coord, **params: Any
|
|
99
|
-
):
|
|
99
|
+
def draw_layer(self, data: pd.DataFrame, layout: Layout, coord: coord):
|
|
100
100
|
"""
|
|
101
101
|
Draw stripes on every panel
|
|
102
102
|
"""
|
|
@@ -104,7 +104,7 @@ class _geom_stripes(geom):
|
|
|
104
104
|
ploc = pid - 1
|
|
105
105
|
panel_params = layout.panel_params[ploc]
|
|
106
106
|
ax = layout.axs[ploc]
|
|
107
|
-
self.draw_group(data, panel_params, coord, ax,
|
|
107
|
+
self.draw_group(data, panel_params, coord, ax, self.params)
|
|
108
108
|
|
|
109
109
|
@staticmethod
|
|
110
110
|
def draw_group(
|
|
@@ -112,7 +112,7 @@ class _geom_stripes(geom):
|
|
|
112
112
|
panel_params: panel_view,
|
|
113
113
|
coord: coord,
|
|
114
114
|
ax: Axes,
|
|
115
|
-
|
|
115
|
+
params: dict[str, Any],
|
|
116
116
|
):
|
|
117
117
|
extend = params["extend"]
|
|
118
118
|
fill_range = params["fill_range"]
|
|
@@ -193,4 +193,4 @@ class _geom_stripes(geom):
|
|
|
193
193
|
}
|
|
194
194
|
)
|
|
195
195
|
|
|
196
|
-
return geom_rect.draw_group(data, panel_params, coord, ax,
|
|
196
|
+
return geom_rect.draw_group(data, panel_params, coord, ax, params)
|
plotnine/geoms/geom.py
CHANGED
|
@@ -2,18 +2,20 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import typing
|
|
4
4
|
from abc import ABC
|
|
5
|
+
from contextlib import suppress
|
|
5
6
|
from copy import deepcopy
|
|
6
7
|
from itertools import chain, repeat
|
|
7
8
|
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
8
11
|
from .._utils import (
|
|
9
12
|
data_mapping_as_kwargs,
|
|
10
|
-
is_list_like,
|
|
11
13
|
remove_missing,
|
|
12
14
|
)
|
|
13
15
|
from .._utils.registry import Register, Registry
|
|
14
16
|
from ..exceptions import PlotnineError
|
|
15
17
|
from ..layer import layer
|
|
16
|
-
from ..mapping.aes import
|
|
18
|
+
from ..mapping.aes import rename_aesthetics
|
|
17
19
|
from ..mapping.evaluation import evaluate
|
|
18
20
|
from ..positions.position import position
|
|
19
21
|
from ..stats.stat import stat
|
|
@@ -171,6 +173,26 @@ class geom(ABC, metaclass=Register):
|
|
|
171
173
|
|
|
172
174
|
return result
|
|
173
175
|
|
|
176
|
+
def setup_params(self, data: pd.DataFrame):
|
|
177
|
+
"""
|
|
178
|
+
Override this method to verify and/or adjust parameters
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
data :
|
|
183
|
+
Data
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
def setup_aes_params(self, data: pd.DataFrame):
|
|
187
|
+
"""
|
|
188
|
+
Override this method to verify and/or adjust aesthetic parameters
|
|
189
|
+
|
|
190
|
+
Parameters
|
|
191
|
+
----------
|
|
192
|
+
data :
|
|
193
|
+
Data
|
|
194
|
+
"""
|
|
195
|
+
|
|
174
196
|
def setup_data(self, data: pd.DataFrame) -> pd.DataFrame:
|
|
175
197
|
"""
|
|
176
198
|
Modify the data before drawing takes place
|
|
@@ -224,6 +246,9 @@ class geom(ABC, metaclass=Register):
|
|
|
224
246
|
:
|
|
225
247
|
Data used for drawing the geom.
|
|
226
248
|
"""
|
|
249
|
+
from plotnine.mapping import _atomic as atomic
|
|
250
|
+
from plotnine.mapping._atomic import ae_value
|
|
251
|
+
|
|
227
252
|
missing_aes = (
|
|
228
253
|
self.DEFAULT_AES.keys()
|
|
229
254
|
- self.aes_params.keys()
|
|
@@ -240,30 +265,39 @@ class geom(ABC, metaclass=Register):
|
|
|
240
265
|
data[ae] = evaled[ae]
|
|
241
266
|
|
|
242
267
|
num_panels = len(data["PANEL"].unique()) if "PANEL" in data else 1
|
|
268
|
+
across_panels = num_panels > 1 and not self.params["inherit_aes"]
|
|
243
269
|
|
|
244
|
-
# Aesthetics set as parameters
|
|
270
|
+
# Aesthetics set as parameters in the geom/stat
|
|
245
271
|
for ae, value in self.aes_params.items():
|
|
246
|
-
|
|
272
|
+
if isinstance(value, (str, int, float, np.integer, np.floating)):
|
|
273
|
+
data[ae] = value
|
|
274
|
+
elif isinstance(value, ae_value):
|
|
275
|
+
data[ae] = value * len(data)
|
|
276
|
+
elif across_panels:
|
|
277
|
+
value = list(chain(*repeat(value, num_panels)))
|
|
247
278
|
data[ae] = value
|
|
248
|
-
|
|
249
|
-
#
|
|
250
|
-
#
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
279
|
+
else:
|
|
280
|
+
# Try to make sense of aesthetics whose values can be tuples
|
|
281
|
+
# or sequences of sorts.
|
|
282
|
+
ae_value_cls: type[ae_value] | None = getattr(atomic, ae, None)
|
|
283
|
+
if ae_value_cls:
|
|
284
|
+
with suppress(ValueError):
|
|
285
|
+
data[ae] = ae_value_cls(value) * len(data)
|
|
286
|
+
continue
|
|
287
|
+
|
|
288
|
+
# This should catch the aesthetic assignments to
|
|
289
|
+
# non-numeric or non-string values or sequence of values.
|
|
290
|
+
# e.g. x=datetime, x=Sequence[datetime],
|
|
291
|
+
# x=Sequence[float], shape=Sequence[str]
|
|
292
|
+
try:
|
|
293
|
+
data[ae] = value
|
|
294
|
+
except ValueError as e:
|
|
295
|
+
msg = f"'{ae}={value}' does not look like a valid value"
|
|
260
296
|
raise PlotnineError(msg) from e
|
|
261
297
|
|
|
262
298
|
return data
|
|
263
299
|
|
|
264
|
-
def draw_layer(
|
|
265
|
-
self, data: pd.DataFrame, layout: Layout, coord: coord, **params: Any
|
|
266
|
-
):
|
|
300
|
+
def draw_layer(self, data: pd.DataFrame, layout: Layout, coord: coord):
|
|
267
301
|
"""
|
|
268
302
|
Draw layer across all panels
|
|
269
303
|
|
|
@@ -289,7 +323,7 @@ class geom(ABC, metaclass=Register):
|
|
|
289
323
|
ploc = pdata["PANEL"].iloc[0] - 1
|
|
290
324
|
panel_params = layout.panel_params[ploc]
|
|
291
325
|
ax = layout.axs[ploc]
|
|
292
|
-
self.draw_panel(pdata, panel_params, coord, ax
|
|
326
|
+
self.draw_panel(pdata, panel_params, coord, ax)
|
|
293
327
|
|
|
294
328
|
def draw_panel(
|
|
295
329
|
self,
|
|
@@ -297,7 +331,6 @@ class geom(ABC, metaclass=Register):
|
|
|
297
331
|
panel_params: panel_view,
|
|
298
332
|
coord: coord,
|
|
299
333
|
ax: Axes,
|
|
300
|
-
**params: Any,
|
|
301
334
|
):
|
|
302
335
|
"""
|
|
303
336
|
Plot all groups
|
|
@@ -331,7 +364,7 @@ class geom(ABC, metaclass=Register):
|
|
|
331
364
|
"""
|
|
332
365
|
for _, gdata in data.groupby("group"):
|
|
333
366
|
gdata.reset_index(inplace=True, drop=True)
|
|
334
|
-
self.draw_group(gdata, panel_params, coord, ax,
|
|
367
|
+
self.draw_group(gdata, panel_params, coord, ax, self.params)
|
|
335
368
|
|
|
336
369
|
@staticmethod
|
|
337
370
|
def draw_group(
|
|
@@ -339,7 +372,7 @@ class geom(ABC, metaclass=Register):
|
|
|
339
372
|
panel_params: panel_view,
|
|
340
373
|
coord: coord,
|
|
341
374
|
ax: Axes,
|
|
342
|
-
|
|
375
|
+
params: dict[str, Any],
|
|
343
376
|
):
|
|
344
377
|
"""
|
|
345
378
|
Plot data belonging to a group.
|
|
@@ -376,7 +409,7 @@ class geom(ABC, metaclass=Register):
|
|
|
376
409
|
panel_params: panel_view,
|
|
377
410
|
coord: coord,
|
|
378
411
|
ax: Axes,
|
|
379
|
-
|
|
412
|
+
params: dict[str, Any],
|
|
380
413
|
):
|
|
381
414
|
"""
|
|
382
415
|
Plot data belonging to a unit.
|
|
@@ -426,7 +459,7 @@ class geom(ABC, metaclass=Register):
|
|
|
426
459
|
msg = "The geom should implement this method."
|
|
427
460
|
raise NotImplementedError(msg)
|
|
428
461
|
|
|
429
|
-
def __radd__(self,
|
|
462
|
+
def __radd__(self, other: ggplot) -> ggplot:
|
|
430
463
|
"""
|
|
431
464
|
Add layer representing geom object on the right
|
|
432
465
|
|
|
@@ -440,8 +473,8 @@ class geom(ABC, metaclass=Register):
|
|
|
440
473
|
:
|
|
441
474
|
ggplot object with added layer.
|
|
442
475
|
"""
|
|
443
|
-
|
|
444
|
-
return
|
|
476
|
+
other += self.to_layer() # Add layer
|
|
477
|
+
return other
|
|
445
478
|
|
|
446
479
|
def to_layer(self) -> layer:
|
|
447
480
|
"""
|
plotnine/geoms/geom_abline.py
CHANGED
|
@@ -102,7 +102,6 @@ class geom_abline(geom):
|
|
|
102
102
|
panel_params: panel_view,
|
|
103
103
|
coord: coord,
|
|
104
104
|
ax: Axes,
|
|
105
|
-
**params: Any,
|
|
106
105
|
):
|
|
107
106
|
"""
|
|
108
107
|
Plot all groups
|
|
@@ -116,4 +115,6 @@ class geom_abline(geom):
|
|
|
116
115
|
|
|
117
116
|
for _, gdata in data.groupby("group"):
|
|
118
117
|
gdata.reset_index(inplace=True)
|
|
119
|
-
geom_segment.draw_group(
|
|
118
|
+
geom_segment.draw_group(
|
|
119
|
+
gdata, panel_params, coord, ax, self.params
|
|
120
|
+
)
|
plotnine/geoms/geom_area.py
CHANGED
|
@@ -14,12 +14,12 @@ class geom_area(geom_ribbon):
|
|
|
14
14
|
"""
|
|
15
15
|
Area plot
|
|
16
16
|
|
|
17
|
+
{usage}
|
|
18
|
+
|
|
17
19
|
An area plot is a special case of geom_ribbon,
|
|
18
20
|
where the minimum of the range is fixed to 0,
|
|
19
21
|
and the position adjustment defaults to 'stack'.
|
|
20
22
|
|
|
21
|
-
{usage}
|
|
22
|
-
|
|
23
23
|
Parameters
|
|
24
24
|
----------
|
|
25
25
|
{common_parameters}
|
plotnine/geoms/geom_bar.py
CHANGED
plotnine/geoms/geom_bin_2d.py
CHANGED
|
@@ -7,16 +7,20 @@ class geom_bin_2d(geom_rect):
|
|
|
7
7
|
"""
|
|
8
8
|
Heatmap of 2d bin counts
|
|
9
9
|
|
|
10
|
+
{usage}
|
|
11
|
+
|
|
10
12
|
Divides the plane into rectangles, counts the number of
|
|
11
13
|
cases in each rectangle, and then (by default) maps the number
|
|
12
14
|
of cases to the rectangle's fill. This is a useful alternative
|
|
13
15
|
to geom_point in the presence of overplotting.
|
|
14
16
|
|
|
15
|
-
{usage}
|
|
16
|
-
|
|
17
17
|
Parameters
|
|
18
18
|
----------
|
|
19
19
|
{common_parameters}
|
|
20
|
+
|
|
21
|
+
See Also
|
|
22
|
+
--------
|
|
23
|
+
plotnine.stat_bin_2d : The default stat for this `geom`.
|
|
20
24
|
"""
|
|
21
25
|
|
|
22
26
|
DEFAULT_PARAMS = {"stat": "bin_2d", "position": "identity", "na_rm": False}
|
plotnine/geoms/geom_blank.py
CHANGED
|
@@ -6,8 +6,6 @@ from ..doctools import document
|
|
|
6
6
|
from .geom import geom
|
|
7
7
|
|
|
8
8
|
if typing.TYPE_CHECKING:
|
|
9
|
-
from typing import Any
|
|
10
|
-
|
|
11
9
|
import pandas as pd
|
|
12
10
|
from matplotlib.axes import Axes
|
|
13
11
|
|
|
@@ -39,7 +37,6 @@ class geom_blank(geom):
|
|
|
39
37
|
panel_params: panel_view,
|
|
40
38
|
coord: coord,
|
|
41
39
|
ax: Axes,
|
|
42
|
-
**params: Any,
|
|
43
40
|
):
|
|
44
41
|
pass
|
|
45
42
|
|
plotnine/geoms/geom_boxplot.py
CHANGED
|
@@ -70,6 +70,10 @@ class geom_boxplot(geom):
|
|
|
70
70
|
fatten : float, default=2
|
|
71
71
|
A multiplicative factor used to increase the size of the
|
|
72
72
|
middle bar across the box.
|
|
73
|
+
|
|
74
|
+
See Also
|
|
75
|
+
--------
|
|
76
|
+
plotnine.stat_boxplot : The default `stat` for this `geom`.
|
|
73
77
|
"""
|
|
74
78
|
|
|
75
79
|
DEFAULT_AES = {
|
|
@@ -183,7 +187,7 @@ class geom_boxplot(geom):
|
|
|
183
187
|
panel_params: panel_view,
|
|
184
188
|
coord: coord,
|
|
185
189
|
ax: Axes,
|
|
186
|
-
|
|
190
|
+
params: dict[str, Any],
|
|
187
191
|
):
|
|
188
192
|
def flat(*args: pd.Series[Any]) -> npt.NDArray[Any]:
|
|
189
193
|
"""Flatten list-likes"""
|
|
@@ -245,11 +249,11 @@ class geom_boxplot(geom):
|
|
|
245
249
|
outliers["shape"] = outlier_value("shape")
|
|
246
250
|
outliers["size"] = outlier_value("size")
|
|
247
251
|
outliers["stroke"] = outlier_value("stroke")
|
|
248
|
-
geom_point.draw_group(outliers, panel_params, coord, ax,
|
|
252
|
+
geom_point.draw_group(outliers, panel_params, coord, ax, params)
|
|
249
253
|
|
|
250
254
|
# plot
|
|
251
|
-
geom_segment.draw_group(whiskers, panel_params, coord, ax,
|
|
252
|
-
geom_crossbar.draw_group(box, panel_params, coord, ax,
|
|
255
|
+
geom_segment.draw_group(whiskers, panel_params, coord, ax, params)
|
|
256
|
+
geom_crossbar.draw_group(box, panel_params, coord, ax, params)
|
|
253
257
|
|
|
254
258
|
@staticmethod
|
|
255
259
|
def draw_legend(
|
plotnine/geoms/geom_col.py
CHANGED
|
@@ -7,13 +7,13 @@ class geom_col(geom_bar):
|
|
|
7
7
|
"""
|
|
8
8
|
Bar plot with base on the x-axis
|
|
9
9
|
|
|
10
|
+
{usage}
|
|
11
|
+
|
|
10
12
|
This is an alternate version of [](`~plotnine.geoms.geom_bar`) that maps
|
|
11
13
|
the height of bars to an existing variable in your data. If
|
|
12
14
|
you want the height of the bar to represent a count of cases,
|
|
13
15
|
use [](`~plotnine.geoms.geom_bar`).
|
|
14
16
|
|
|
15
|
-
{usage}
|
|
16
|
-
|
|
17
17
|
Parameters
|
|
18
18
|
----------
|
|
19
19
|
{common_parameters}
|
plotnine/geoms/geom_count.py
CHANGED
|
@@ -7,15 +7,19 @@ class geom_count(geom_point):
|
|
|
7
7
|
"""
|
|
8
8
|
Plot overlapping points
|
|
9
9
|
|
|
10
|
+
{usage}
|
|
11
|
+
|
|
10
12
|
This is a variant [](`~plotnine.geoms.geom_point`) that counts the number
|
|
11
13
|
of observations at each location, then maps the count to point
|
|
12
14
|
area. It useful when you have discrete data and overplotting.
|
|
13
15
|
|
|
14
|
-
{usage}
|
|
15
|
-
|
|
16
16
|
Parameters
|
|
17
17
|
----------
|
|
18
18
|
{common_parameters}
|
|
19
|
+
|
|
20
|
+
See Also
|
|
21
|
+
--------
|
|
22
|
+
plotnine.stat_sum : The default `stat` for this `geom`.
|
|
19
23
|
"""
|
|
20
24
|
|
|
21
25
|
DEFAULT_PARAMS = {"stat": "sum", "position": "identity", "na_rm": False}
|
plotnine/geoms/geom_crossbar.py
CHANGED
|
@@ -78,7 +78,7 @@ class geom_crossbar(geom):
|
|
|
78
78
|
panel_params: panel_view,
|
|
79
79
|
coord: coord,
|
|
80
80
|
ax: Axes,
|
|
81
|
-
|
|
81
|
+
params: dict[str, Any],
|
|
82
82
|
):
|
|
83
83
|
y = data["y"]
|
|
84
84
|
xmin = data["xmin"]
|
|
@@ -160,8 +160,8 @@ class geom_crossbar(geom):
|
|
|
160
160
|
)
|
|
161
161
|
|
|
162
162
|
copy_missing_columns(box, data)
|
|
163
|
-
geom_polygon.draw_group(box, panel_params, coord, ax,
|
|
164
|
-
geom_segment.draw_group(middle, panel_params, coord, ax,
|
|
163
|
+
geom_polygon.draw_group(box, panel_params, coord, ax, params)
|
|
164
|
+
geom_segment.draw_group(middle, panel_params, coord, ax, params)
|
|
165
165
|
|
|
166
166
|
@staticmethod
|
|
167
167
|
def draw_legend(
|
|
@@ -7,13 +7,17 @@ class geom_density_2d(geom_path):
|
|
|
7
7
|
"""
|
|
8
8
|
2D density estimate
|
|
9
9
|
|
|
10
|
-
This is a 2d version of [](`~plotnine.geoms.geom_density`).
|
|
11
|
-
|
|
12
10
|
{usage}
|
|
13
11
|
|
|
12
|
+
This is a 2d version of [](`~plotnine.geoms.geom_density`).
|
|
13
|
+
|
|
14
14
|
Parameters
|
|
15
15
|
----------
|
|
16
16
|
{common_parameters}
|
|
17
|
+
|
|
18
|
+
See Also
|
|
19
|
+
--------
|
|
20
|
+
plotnine.stat_density_2d : The default `stat` for this `geom`.
|
|
17
21
|
"""
|
|
18
22
|
|
|
19
23
|
DEFAULT_PARAMS = {
|
plotnine/geoms/geom_dotplot.py
CHANGED
|
@@ -46,7 +46,7 @@ class geom_dotplot(geom):
|
|
|
46
46
|
|
|
47
47
|
See Also
|
|
48
48
|
--------
|
|
49
|
-
plotnine.stat_bindot
|
|
49
|
+
plotnine.stat_bindot : The default `stat` for this `geom`.
|
|
50
50
|
"""
|
|
51
51
|
|
|
52
52
|
DEFAULT_AES = {"alpha": 1, "color": "black", "fill": "black"}
|
|
@@ -186,7 +186,7 @@ class geom_dotplot(geom):
|
|
|
186
186
|
panel_params: panel_view,
|
|
187
187
|
coord: coord,
|
|
188
188
|
ax: Axes,
|
|
189
|
-
|
|
189
|
+
params: dict[str, Any],
|
|
190
190
|
):
|
|
191
191
|
from matplotlib.collections import PatchCollection
|
|
192
192
|
from matplotlib.patches import Ellipse
|