plotnine 0.15.2__py3-none-any.whl → 0.16.0a1__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/_mpl/gridspec.py +50 -6
- plotnine/_mpl/layout_manager/__init__.py +2 -5
- plotnine/_mpl/layout_manager/_composition_layout_items.py +98 -0
- plotnine/_mpl/layout_manager/_composition_side_space.py +461 -0
- plotnine/_mpl/layout_manager/_engine.py +19 -58
- plotnine/_mpl/layout_manager/_grid.py +94 -0
- plotnine/_mpl/layout_manager/_layout_tree.py +402 -817
- plotnine/_mpl/layout_manager/{_layout_items.py → _plot_layout_items.py} +55 -278
- plotnine/_mpl/layout_manager/{_spaces.py → _plot_side_space.py} +111 -291
- plotnine/_mpl/layout_manager/_side_space.py +176 -0
- plotnine/_mpl/utils.py +259 -1
- plotnine/_utils/__init__.py +23 -3
- plotnine/_utils/context.py +1 -1
- plotnine/_utils/dataclasses.py +24 -0
- plotnine/animation.py +13 -12
- plotnine/composition/__init__.py +6 -0
- plotnine/composition/_beside.py +13 -11
- plotnine/composition/_compose.py +263 -99
- plotnine/composition/_plot_annotation.py +75 -0
- plotnine/composition/_plot_layout.py +143 -0
- plotnine/composition/_plot_spacer.py +1 -1
- plotnine/composition/_stack.py +13 -11
- plotnine/composition/_types.py +28 -0
- plotnine/composition/_wrap.py +60 -0
- plotnine/facets/facet.py +9 -12
- plotnine/facets/facet_grid.py +2 -2
- plotnine/facets/facet_wrap.py +1 -1
- plotnine/geoms/geom.py +2 -2
- plotnine/geoms/geom_map.py +4 -5
- plotnine/geoms/geom_path.py +8 -7
- plotnine/geoms/geom_rug.py +6 -10
- plotnine/geoms/geom_text.py +5 -5
- plotnine/ggplot.py +63 -9
- plotnine/guides/guide.py +24 -6
- plotnine/guides/guide_colorbar.py +88 -46
- plotnine/guides/guide_legend.py +47 -20
- plotnine/guides/guides.py +2 -2
- plotnine/iapi.py +17 -1
- plotnine/scales/scale.py +1 -1
- plotnine/stats/binning.py +15 -43
- plotnine/stats/smoothers.py +7 -3
- plotnine/stats/stat.py +2 -2
- plotnine/stats/stat_density_2d.py +10 -6
- plotnine/stats/stat_pointdensity.py +8 -1
- plotnine/stats/stat_qq.py +5 -5
- plotnine/stats/stat_qq_line.py +6 -1
- plotnine/stats/stat_sina.py +19 -20
- plotnine/stats/stat_summary.py +4 -2
- plotnine/stats/stat_summary_bin.py +7 -1
- plotnine/themes/elements/element_line.py +2 -0
- plotnine/themes/elements/element_text.py +12 -1
- plotnine/themes/theme.py +18 -24
- plotnine/themes/themeable.py +17 -3
- plotnine/typing.py +6 -1
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/METADATA +2 -2
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/RECORD +59 -51
- plotnine/composition/_plotspec.py +0 -50
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/WHEEL +0 -0
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/licenses/LICENSE +0 -0
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from itertools import cycle
|
|
5
|
+
from typing import TYPE_CHECKING, Sequence
|
|
6
|
+
|
|
7
|
+
from ..composition._types import ComposeAddable
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ._compose import Compose
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(kw_only=True)
|
|
14
|
+
class plot_layout(ComposeAddable):
|
|
15
|
+
"""
|
|
16
|
+
Customise the layout of plots in a composition
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
nrow: int | None = None
|
|
20
|
+
"""
|
|
21
|
+
Number of rows
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
ncol: int | None = None
|
|
25
|
+
"""
|
|
26
|
+
Number of columns
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
byrow: bool | None = None
|
|
30
|
+
"""
|
|
31
|
+
How to place plots into the grid.
|
|
32
|
+
If None or True, they are placed row by row, left to right.
|
|
33
|
+
If False, they are placed column by column, top to bottom.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
widths: Sequence[float] | None = None
|
|
37
|
+
"""
|
|
38
|
+
Relative widths of each column
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
heights: Sequence[float] | None = None
|
|
42
|
+
"""
|
|
43
|
+
Relative heights of each column
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
_cmp: Compose = field(init=False, repr=False)
|
|
47
|
+
"""
|
|
48
|
+
Composition that this layout is attached to
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __radd__(self, cmp: Compose) -> Compose:
|
|
52
|
+
"""
|
|
53
|
+
Add plot layout to composition
|
|
54
|
+
"""
|
|
55
|
+
cmp.layout = self
|
|
56
|
+
return cmp
|
|
57
|
+
|
|
58
|
+
def _setup(self, cmp: Compose):
|
|
59
|
+
"""
|
|
60
|
+
Setup default parameters as they are expected by the layout manager
|
|
61
|
+
|
|
62
|
+
- Ensure nrow and ncol have values
|
|
63
|
+
- Ensure the widths & heights are set and normalised to mean=1
|
|
64
|
+
"""
|
|
65
|
+
from . import Beside, Stack
|
|
66
|
+
|
|
67
|
+
# setup nrow & ncol
|
|
68
|
+
if isinstance(cmp, Beside):
|
|
69
|
+
if self.ncol is None:
|
|
70
|
+
self.ncol = len(cmp)
|
|
71
|
+
elif self.ncol < len(cmp):
|
|
72
|
+
raise ValueError(
|
|
73
|
+
"Composition has more items than the layout columns."
|
|
74
|
+
)
|
|
75
|
+
if self.nrow is None:
|
|
76
|
+
self.nrow = 1
|
|
77
|
+
elif isinstance(cmp, Stack):
|
|
78
|
+
if self.nrow is None:
|
|
79
|
+
self.nrow = len(cmp)
|
|
80
|
+
elif self.nrow < len(cmp):
|
|
81
|
+
raise ValueError(
|
|
82
|
+
"Composition has more items than the layout rows."
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if self.ncol is None:
|
|
86
|
+
self.ncol = 1
|
|
87
|
+
else:
|
|
88
|
+
from plotnine.facets.facet_wrap import wrap_dims
|
|
89
|
+
|
|
90
|
+
self.nrow, self.ncol = wrap_dims(len(cmp), self.nrow, self.ncol)
|
|
91
|
+
|
|
92
|
+
nrow, ncol = self.nrow, self.ncol
|
|
93
|
+
|
|
94
|
+
# byrow
|
|
95
|
+
if self.byrow is None:
|
|
96
|
+
self.byrow = True
|
|
97
|
+
|
|
98
|
+
# setup widths & heights
|
|
99
|
+
ws, hs = self.widths, self.heights
|
|
100
|
+
if ws is None:
|
|
101
|
+
ws = (1 / ncol,) * ncol
|
|
102
|
+
elif len(ws) != ncol:
|
|
103
|
+
ws = repeat(ws, ncol)
|
|
104
|
+
|
|
105
|
+
if hs is None:
|
|
106
|
+
hs = (1 / nrow,) * nrow
|
|
107
|
+
elif len(hs) != nrow:
|
|
108
|
+
hs = repeat(hs, nrow)
|
|
109
|
+
|
|
110
|
+
self.widths = normalise(ws)
|
|
111
|
+
self.heights = normalise(hs)
|
|
112
|
+
|
|
113
|
+
def update(self, other: plot_layout):
|
|
114
|
+
"""
|
|
115
|
+
Update this layout with the contents of other
|
|
116
|
+
"""
|
|
117
|
+
if other.widths:
|
|
118
|
+
self.widths = other.widths
|
|
119
|
+
if other.heights:
|
|
120
|
+
self.heights = other.heights
|
|
121
|
+
if other.ncol:
|
|
122
|
+
self.ncol = other.ncol
|
|
123
|
+
if other.nrow:
|
|
124
|
+
self.nrow = other.nrow
|
|
125
|
+
if other.byrow is not None:
|
|
126
|
+
self.byrow = other.byrow
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def repeat(seq: Sequence[float], n: int) -> list[float]:
|
|
130
|
+
"""
|
|
131
|
+
Ensure returned sequence has n values, repeat as necessary
|
|
132
|
+
"""
|
|
133
|
+
return [val for _, val in zip(range(n), cycle(seq))]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def normalise(seq: Sequence[float]) -> list[float]:
|
|
137
|
+
"""
|
|
138
|
+
Normalise seq so that the mean is 1
|
|
139
|
+
"""
|
|
140
|
+
mean = sum(seq) / len(seq)
|
|
141
|
+
if mean == 0:
|
|
142
|
+
raise ValueError("Cannot rescale: mean is zero")
|
|
143
|
+
return [x / mean for x in seq]
|
|
@@ -39,7 +39,7 @@ class plot_spacer(ggplot):
|
|
|
39
39
|
if fill:
|
|
40
40
|
self.theme += theme(plot_background=element_rect(fill=fill))
|
|
41
41
|
|
|
42
|
-
def __add__(self, rhs) -> plot_spacer:
|
|
42
|
+
def __add__(self, rhs) -> plot_spacer: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
43
43
|
"""
|
|
44
44
|
Add to spacer
|
|
45
45
|
|
plotnine/composition/_stack.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from dataclasses import dataclass
|
|
4
3
|
from typing import TYPE_CHECKING
|
|
5
4
|
|
|
6
5
|
from ._compose import Compose
|
|
@@ -9,7 +8,6 @@ if TYPE_CHECKING:
|
|
|
9
8
|
from plotnine.ggplot import ggplot
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
@dataclass(repr=False)
|
|
13
11
|
class Stack(Compose):
|
|
14
12
|
"""
|
|
15
13
|
Place plots or compositions on top of each other
|
|
@@ -26,25 +24,18 @@ class Stack(Compose):
|
|
|
26
24
|
See Also
|
|
27
25
|
--------
|
|
28
26
|
plotnine.composition.Beside : To arrange plots side by side
|
|
27
|
+
plotnine.composition.Wrap : To arrange plots in a grid
|
|
29
28
|
plotnine.composition.plot_spacer : To add a blank space between plots
|
|
30
29
|
plotnine.composition.Compose : For more on composing plots
|
|
31
30
|
"""
|
|
32
31
|
|
|
33
|
-
@property
|
|
34
|
-
def nrow(self) -> int:
|
|
35
|
-
return len(self)
|
|
36
|
-
|
|
37
|
-
@property
|
|
38
|
-
def ncol(self) -> int:
|
|
39
|
-
return 1
|
|
40
|
-
|
|
41
32
|
def __truediv__(self, rhs: ggplot | Compose) -> Compose:
|
|
42
33
|
"""
|
|
43
34
|
Add rhs as a row
|
|
44
35
|
"""
|
|
45
36
|
# This is an adjacent div i.e. (DIV | rhs) so we collapse the
|
|
46
37
|
# operands into a single operation
|
|
47
|
-
return Stack([*self, rhs])
|
|
38
|
+
return Stack([*self, rhs]) + self.layout + self.annotation
|
|
48
39
|
|
|
49
40
|
def __or__(self, rhs: ggplot | Compose) -> Compose:
|
|
50
41
|
"""
|
|
@@ -53,3 +44,14 @@ class Stack(Compose):
|
|
|
53
44
|
from ._beside import Beside
|
|
54
45
|
|
|
55
46
|
return Beside([self, rhs])
|
|
47
|
+
|
|
48
|
+
def __add__(self, rhs):
|
|
49
|
+
"""
|
|
50
|
+
Add rhs into the stacking composition
|
|
51
|
+
"""
|
|
52
|
+
from plotnine import ggplot
|
|
53
|
+
|
|
54
|
+
if not isinstance(rhs, (ggplot, Compose)):
|
|
55
|
+
return super().__add__(rhs)
|
|
56
|
+
|
|
57
|
+
return self / rhs
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from ._compose import Compose
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ComposeAddable:
|
|
10
|
+
"""
|
|
11
|
+
Object that can be added to a ggplot object
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __radd__(self, other: Compose) -> Compose:
|
|
15
|
+
"""
|
|
16
|
+
Add to compose object
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
other :
|
|
21
|
+
Compose object
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
:
|
|
26
|
+
Compose object
|
|
27
|
+
"""
|
|
28
|
+
return other
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ..ggplot import ggplot
|
|
4
|
+
from ._compose import Compose
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Wrap(Compose):
|
|
8
|
+
"""
|
|
9
|
+
Wrap plots or compositions into a grid
|
|
10
|
+
|
|
11
|
+
**Usage**
|
|
12
|
+
|
|
13
|
+
plot + plot
|
|
14
|
+
plot + composition
|
|
15
|
+
composition + plot
|
|
16
|
+
composition + composition
|
|
17
|
+
|
|
18
|
+
Typically, you will use this class through the `+` operator.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
items:
|
|
23
|
+
The objects to be arranged (composed)
|
|
24
|
+
nrow:
|
|
25
|
+
Number of rows in the composition
|
|
26
|
+
ncol:
|
|
27
|
+
Number of cols in the composition
|
|
28
|
+
|
|
29
|
+
See Also
|
|
30
|
+
--------
|
|
31
|
+
plotnine.composition.Beside : To arrange plots side by side
|
|
32
|
+
plotnine.composition.Stack : To arrange plots vertically
|
|
33
|
+
plotnine.composition.plot_spacer : To add a blank space between plots
|
|
34
|
+
plotnine.composition.Compose : For more on composing plots
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __add__(self, rhs):
|
|
38
|
+
"""
|
|
39
|
+
Add rhs into the wrapping composition
|
|
40
|
+
"""
|
|
41
|
+
if not isinstance(rhs, (ggplot, Compose)):
|
|
42
|
+
return super().__add__(rhs)
|
|
43
|
+
|
|
44
|
+
return Wrap([*self, rhs]) + self.layout + self.annotation
|
|
45
|
+
|
|
46
|
+
def __or__(self, rhs: ggplot | Compose) -> Compose:
|
|
47
|
+
"""
|
|
48
|
+
Add rhs as a column
|
|
49
|
+
"""
|
|
50
|
+
from ._beside import Beside
|
|
51
|
+
|
|
52
|
+
return Beside([self, rhs])
|
|
53
|
+
|
|
54
|
+
def __truediv__(self, rhs: ggplot | Compose) -> Compose:
|
|
55
|
+
"""
|
|
56
|
+
Add rhs as a row
|
|
57
|
+
"""
|
|
58
|
+
from ._stack import Stack
|
|
59
|
+
|
|
60
|
+
return Stack([self, rhs])
|
plotnine/facets/facet.py
CHANGED
|
@@ -93,7 +93,6 @@ class facet:
|
|
|
93
93
|
|
|
94
94
|
# Axes
|
|
95
95
|
axs: list[Axes]
|
|
96
|
-
_panels_gridspec: p9GridSpec
|
|
97
96
|
|
|
98
97
|
# ggplot object that the facet belongs to
|
|
99
98
|
plot: ggplot
|
|
@@ -144,15 +143,15 @@ class facet:
|
|
|
144
143
|
self.figure = plot.figure
|
|
145
144
|
|
|
146
145
|
if hasattr(plot, "axs"):
|
|
147
|
-
self.axs = plot.axs
|
|
146
|
+
gs, self.axs = plot._sub_gridspec, plot.axs
|
|
148
147
|
else:
|
|
149
|
-
self.axs = self._make_axes()
|
|
148
|
+
gs, self.axs = self._make_axes()
|
|
150
149
|
|
|
151
150
|
self.coordinates = plot.coordinates
|
|
152
151
|
self.theme = plot.theme
|
|
153
152
|
self.layout.axs = self.axs
|
|
154
153
|
self.strips = Strips.from_facet(self)
|
|
155
|
-
return self.axs
|
|
154
|
+
return gs, self.axs
|
|
156
155
|
|
|
157
156
|
def setup_data(self, data: list[pd.DataFrame]) -> list[pd.DataFrame]:
|
|
158
157
|
"""
|
|
@@ -378,7 +377,7 @@ class facet:
|
|
|
378
377
|
|
|
379
378
|
return result
|
|
380
379
|
|
|
381
|
-
def
|
|
380
|
+
def _make_gridspec(self):
|
|
382
381
|
"""
|
|
383
382
|
Create gridspec for the panels
|
|
384
383
|
"""
|
|
@@ -388,21 +387,19 @@ class facet:
|
|
|
388
387
|
self.nrow, self.ncol, self.figure, nest_into=self.plot._gridspec[0]
|
|
389
388
|
)
|
|
390
389
|
|
|
391
|
-
def _make_axes(self) -> list[Axes]:
|
|
390
|
+
def _make_axes(self) -> tuple[p9GridSpec, list[Axes]]:
|
|
392
391
|
"""
|
|
393
392
|
Create and return subplot axes
|
|
394
393
|
"""
|
|
394
|
+
|
|
395
395
|
num_panels = len(self.layout.layout)
|
|
396
396
|
axsarr = np.empty((self.nrow, self.ncol), dtype=object)
|
|
397
|
-
|
|
398
|
-
self._panels_gridspec = self._get_panels_gridspec()
|
|
397
|
+
gs = self._make_gridspec()
|
|
399
398
|
|
|
400
399
|
# Create axes
|
|
401
400
|
it = itertools.product(range(self.nrow), range(self.ncol))
|
|
402
401
|
for i, (row, col) in enumerate(it):
|
|
403
|
-
axsarr[row, col] = self.figure.add_subplot(
|
|
404
|
-
self._panels_gridspec[i]
|
|
405
|
-
)
|
|
402
|
+
axsarr[row, col] = self.figure.add_subplot(gs[i])
|
|
406
403
|
|
|
407
404
|
# Rearrange axes
|
|
408
405
|
# They are ordered to match the positions in the layout table
|
|
@@ -423,7 +420,7 @@ class facet:
|
|
|
423
420
|
for ax in axs[num_panels:]:
|
|
424
421
|
self.figure.delaxes(ax)
|
|
425
422
|
axs = axs[:num_panels]
|
|
426
|
-
return list(axs)
|
|
423
|
+
return gs, list(axs)
|
|
427
424
|
|
|
428
425
|
def _aspect_ratio(self) -> Optional[float]:
|
|
429
426
|
"""
|
plotnine/facets/facet_grid.py
CHANGED
|
@@ -107,7 +107,7 @@ class facet_grid(facet):
|
|
|
107
107
|
self.space = space
|
|
108
108
|
self.margins = margins
|
|
109
109
|
|
|
110
|
-
def
|
|
110
|
+
def _make_gridspec(self):
|
|
111
111
|
"""
|
|
112
112
|
Create gridspec for the panels
|
|
113
113
|
"""
|
|
@@ -189,7 +189,7 @@ class facet_grid(facet):
|
|
|
189
189
|
|
|
190
190
|
n = len(base)
|
|
191
191
|
panel = ninteraction(base, drop=True)
|
|
192
|
-
panel = pd.Categorical(panel, categories=range(1, n + 1))
|
|
192
|
+
panel = pd.Categorical(panel, categories=range(1, n + 1)) # pyright: ignore[reportArgumentType]
|
|
193
193
|
|
|
194
194
|
if self.rows:
|
|
195
195
|
rows = ninteraction(base[self.rows], drop=True)
|
plotnine/facets/facet_wrap.py
CHANGED
|
@@ -115,7 +115,7 @@ class facet_wrap(facet):
|
|
|
115
115
|
|
|
116
116
|
layout = pd.DataFrame(
|
|
117
117
|
{
|
|
118
|
-
"PANEL": pd.Categorical(range(1, n + 1)),
|
|
118
|
+
"PANEL": pd.Categorical(range(1, n + 1)), # pyright: ignore[reportArgumentType]
|
|
119
119
|
"ROW": row.astype(int),
|
|
120
120
|
"COL": col.astype(int),
|
|
121
121
|
}
|
plotnine/geoms/geom.py
CHANGED
|
@@ -166,10 +166,10 @@ class geom(ABC, metaclass=Register):
|
|
|
166
166
|
shallow = {"data", "_kwargs", "environment"}
|
|
167
167
|
for key, item in old.items():
|
|
168
168
|
if key in shallow:
|
|
169
|
-
new[key] = item
|
|
169
|
+
new[key] = item # pyright: ignore[reportIndexIssue]
|
|
170
170
|
memo[id(new[key])] = new[key]
|
|
171
171
|
else:
|
|
172
|
-
new[key] = deepcopy(item, memo)
|
|
172
|
+
new[key] = deepcopy(item, memo) # pyright: ignore[reportIndexIssue]
|
|
173
173
|
|
|
174
174
|
return result
|
|
175
175
|
|
plotnine/geoms/geom_map.py
CHANGED
|
@@ -126,18 +126,18 @@ class geom_map(geom):
|
|
|
126
126
|
params = self.params
|
|
127
127
|
data.loc[data["color"].isna(), "color"] = "none"
|
|
128
128
|
data.loc[data["fill"].isna(), "fill"] = "none"
|
|
129
|
-
data["fill"] = to_rgba(data["fill"], data["alpha"])
|
|
130
129
|
|
|
131
130
|
geom_type = data.geometry.iloc[0].geom_type
|
|
132
131
|
if geom_type in ("Polygon", "MultiPolygon"):
|
|
133
132
|
from matplotlib.collections import PatchCollection
|
|
134
133
|
|
|
135
134
|
linewidth = data["size"] * SIZE_FACTOR
|
|
135
|
+
fill = to_rgba(data["fill"], data["alpha"])
|
|
136
136
|
patches = [PolygonPatch(g) for g in data["geometry"]]
|
|
137
137
|
coll = PatchCollection(
|
|
138
138
|
patches,
|
|
139
139
|
edgecolor=data["color"],
|
|
140
|
-
facecolor=
|
|
140
|
+
facecolor=fill,
|
|
141
141
|
linestyle=data["linetype"],
|
|
142
142
|
linewidth=linewidth,
|
|
143
143
|
zorder=params["zorder"],
|
|
@@ -152,7 +152,6 @@ class geom_map(geom):
|
|
|
152
152
|
data["y"] = arr[:, 1]
|
|
153
153
|
for _, gdata in data.groupby("group"):
|
|
154
154
|
gdata.reset_index(inplace=True, drop=True)
|
|
155
|
-
gdata.is_copy = None
|
|
156
155
|
geom_point.draw_group(gdata, panel_params, coord, ax, params)
|
|
157
156
|
elif geom_type == "MultiPoint":
|
|
158
157
|
# Where n is the length of the dataframe (no. of multipoints),
|
|
@@ -173,7 +172,7 @@ class geom_map(geom):
|
|
|
173
172
|
from matplotlib.collections import LineCollection
|
|
174
173
|
|
|
175
174
|
linewidth = data["size"] * SIZE_FACTOR
|
|
176
|
-
|
|
175
|
+
color = to_rgba(data["color"], data["alpha"])
|
|
177
176
|
segments = []
|
|
178
177
|
for g in data["geometry"]:
|
|
179
178
|
if g.geom_type == "LineString":
|
|
@@ -183,7 +182,7 @@ class geom_map(geom):
|
|
|
183
182
|
|
|
184
183
|
coll = LineCollection(
|
|
185
184
|
segments,
|
|
186
|
-
edgecolor=
|
|
185
|
+
edgecolor=color,
|
|
187
186
|
linewidth=linewidth,
|
|
188
187
|
linestyle=data["linetype"],
|
|
189
188
|
zorder=params["zorder"],
|
plotnine/geoms/geom_path.py
CHANGED
|
@@ -96,8 +96,9 @@ class geom_path(geom):
|
|
|
96
96
|
n2 = len(data)
|
|
97
97
|
|
|
98
98
|
if n2 != n1 and not self.params["na_rm"]:
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
geom = self.__class__.__name__
|
|
100
|
+
msg = f"{geom}: Removed {n1 - n2} rows containing missing values."
|
|
101
|
+
warn(msg, PlotnineWarning)
|
|
101
102
|
|
|
102
103
|
return data
|
|
103
104
|
|
|
@@ -109,8 +110,9 @@ class geom_path(geom):
|
|
|
109
110
|
ax: Axes,
|
|
110
111
|
):
|
|
111
112
|
if not any(data["group"].duplicated()):
|
|
113
|
+
geom = self.__class__.__name__
|
|
112
114
|
warn(
|
|
113
|
-
"
|
|
115
|
+
f"{geom}: Each group consist of only one "
|
|
114
116
|
"observation. Do you need to adjust the "
|
|
115
117
|
"group aesthetic?",
|
|
116
118
|
PlotnineWarning,
|
|
@@ -300,7 +302,7 @@ class arrow:
|
|
|
300
302
|
last = self.ends in ("last", "both")
|
|
301
303
|
|
|
302
304
|
data = data.sort_values("group", kind="mergesort")
|
|
303
|
-
data["color"] = to_rgba(data["color"], data["alpha"])
|
|
305
|
+
data["color"] = to_rgba(data["color"], data["alpha"]) # pyright: ignore[reportCallIssue,reportArgumentType]
|
|
304
306
|
|
|
305
307
|
if self.type == "open":
|
|
306
308
|
data["facecolor"] = "none"
|
|
@@ -423,9 +425,8 @@ class arrow:
|
|
|
423
425
|
# We need the axes dimensions so that we can
|
|
424
426
|
# compute scaling factors
|
|
425
427
|
width, height = _axes_get_size_inches(ax)
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
height_ = np.ptp(ranges.y)
|
|
428
|
+
width_ = np.ptp(panel_params.x.range)
|
|
429
|
+
height_ = np.ptp(panel_params.y.range)
|
|
429
430
|
|
|
430
431
|
# scaling factors to prevent skewed arrowheads
|
|
431
432
|
lx = self.length * width_ / width
|
plotnine/geoms/geom_rug.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from typing import TYPE_CHECKING, cast
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ from ..doctools import document
|
|
|
10
10
|
from .geom import geom
|
|
11
11
|
from .geom_path import geom_path
|
|
12
12
|
|
|
13
|
-
if
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
14
|
from typing import Any
|
|
15
15
|
|
|
16
16
|
import pandas as pd
|
|
@@ -89,30 +89,26 @@ class geom_rug(geom):
|
|
|
89
89
|
xheight = (xmax - xmin) * params["length"]
|
|
90
90
|
yheight = (ymax - ymin) * params["length"]
|
|
91
91
|
|
|
92
|
-
# Please the type checker
|
|
93
|
-
x: FloatArray
|
|
94
|
-
y: FloatArray
|
|
95
|
-
|
|
96
92
|
if has_x:
|
|
93
|
+
x = cast("FloatArray", np.repeat(data["x"].to_numpy(), 2))
|
|
94
|
+
|
|
97
95
|
if "b" in sides:
|
|
98
|
-
x = np.repeat(data["x"].to_numpy(), 2)
|
|
99
96
|
y = np.tile([ymin, ymin + yheight], n)
|
|
100
97
|
rugs.extend(make_line_segments(x, y, ispath=False))
|
|
101
98
|
|
|
102
99
|
if "t" in sides:
|
|
103
|
-
x = np.repeat(data["x"].to_numpy(), 2)
|
|
104
100
|
y = np.tile([ymax - yheight, ymax], n)
|
|
105
101
|
rugs.extend(make_line_segments(x, y, ispath=False))
|
|
106
102
|
|
|
107
103
|
if has_y:
|
|
104
|
+
y = cast("FloatArray", np.repeat(data["y"].to_numpy(), 2))
|
|
105
|
+
|
|
108
106
|
if "l" in sides:
|
|
109
107
|
x = np.tile([xmin, xmin + xheight], n)
|
|
110
|
-
y = np.repeat(data["y"].to_numpy(), 2)
|
|
111
108
|
rugs.extend(make_line_segments(x, y, ispath=False))
|
|
112
109
|
|
|
113
110
|
if "r" in sides:
|
|
114
111
|
x = np.tile([xmax - xheight, xmax], n)
|
|
115
|
-
y = np.repeat(data["y"].to_numpy(), 2)
|
|
116
112
|
rugs.extend(make_line_segments(x, y, ispath=False))
|
|
117
113
|
|
|
118
114
|
color = to_rgba(data["color"], data["alpha"])
|
plotnine/geoms/geom_text.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import typing
|
|
4
3
|
from contextlib import suppress
|
|
4
|
+
from typing import TYPE_CHECKING, cast
|
|
5
5
|
from warnings import warn
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
@@ -12,7 +12,7 @@ from ..exceptions import PlotnineError, PlotnineWarning
|
|
|
12
12
|
from ..positions import position_nudge
|
|
13
13
|
from .geom import geom
|
|
14
14
|
|
|
15
|
-
if
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
16
|
from typing import Any, Sequence
|
|
17
17
|
|
|
18
18
|
import pandas as pd
|
|
@@ -244,7 +244,7 @@ class geom_text(geom):
|
|
|
244
244
|
axis=1,
|
|
245
245
|
inplace=True,
|
|
246
246
|
)
|
|
247
|
-
plot_data["color"] = color
|
|
247
|
+
plot_data["color"] = color # pyright: ignore[reportCallIssue,reportArgumentType]
|
|
248
248
|
plot_data["zorder"] = zorder
|
|
249
249
|
plot_data["rasterized"] = params["raster"]
|
|
250
250
|
plot_data["clip_on"] = True
|
|
@@ -255,7 +255,7 @@ class geom_text(geom):
|
|
|
255
255
|
fill = to_rgba(data.pop("fill"), data["alpha"])
|
|
256
256
|
if isinstance(fill, tuple):
|
|
257
257
|
fill = [list(fill)] * len(data["x"])
|
|
258
|
-
plot_data["facecolor"] = fill
|
|
258
|
+
plot_data["facecolor"] = fill # pyright: ignore[reportCallIssue,reportArgumentType]
|
|
259
259
|
|
|
260
260
|
tokens = [params["boxstyle"], f"pad={params['label_padding']}"]
|
|
261
261
|
if params["boxstyle"] in {"round", "round4"}:
|
|
@@ -272,7 +272,7 @@ class geom_text(geom):
|
|
|
272
272
|
|
|
273
273
|
# For labels add a bbox
|
|
274
274
|
for i in range(len(data)):
|
|
275
|
-
kw
|
|
275
|
+
kw = cast("dict[str, Any]", plot_data.iloc[i].to_dict())
|
|
276
276
|
if draw_label:
|
|
277
277
|
kw["bbox"] = bbox
|
|
278
278
|
kw["bbox"]["edgecolor"] = params["boxcolor"] or kw["color"]
|