plotnine 0.15.0a2__py3-none-any.whl → 0.15.0a3__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/layout_manager/_layout_tree.py +16 -6
- plotnine/_utils/__init__.py +4 -2
- plotnine/geoms/annotation_logticks.py +5 -8
- plotnine/geoms/annotation_stripes.py +4 -6
- plotnine/geoms/geom.py +20 -8
- plotnine/geoms/geom_abline.py +3 -2
- plotnine/geoms/geom_blank.py +0 -3
- plotnine/geoms/geom_boxplot.py +4 -4
- plotnine/geoms/geom_crossbar.py +3 -3
- plotnine/geoms/geom_dotplot.py +1 -1
- plotnine/geoms/geom_errorbar.py +2 -2
- plotnine/geoms/geom_errorbarh.py +2 -2
- plotnine/geoms/geom_hline.py +3 -2
- plotnine/geoms/geom_linerange.py +2 -2
- plotnine/geoms/geom_map.py +3 -3
- plotnine/geoms/geom_path.py +10 -11
- plotnine/geoms/geom_point.py +4 -5
- plotnine/geoms/geom_pointrange.py +3 -5
- plotnine/geoms/geom_polygon.py +2 -3
- 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_smooth.py +3 -3
- plotnine/geoms/geom_step.py +2 -2
- plotnine/geoms/geom_text.py +2 -3
- plotnine/geoms/geom_violin.py +4 -5
- plotnine/geoms/geom_vline.py +3 -2
- plotnine/guides/guides.py +1 -1
- plotnine/layer.py +18 -12
- plotnine/mapping/_eval_environment.py +1 -1
- plotnine/scales/scale_color.py +46 -14
- plotnine/scales/scale_continuous.py +5 -4
- plotnine/scales/scale_datetime.py +28 -14
- plotnine/scales/scale_discrete.py +2 -2
- plotnine/scales/scale_xy.py +2 -2
- plotnine/stats/smoothers.py +19 -19
- plotnine/stats/stat.py +15 -25
- plotnine/stats/stat_bin.py +2 -5
- plotnine/stats/stat_bin_2d.py +7 -9
- plotnine/stats/stat_bindot.py +5 -8
- plotnine/stats/stat_boxplot.py +5 -5
- plotnine/stats/stat_count.py +5 -9
- plotnine/stats/stat_density.py +5 -8
- plotnine/stats/stat_density_2d.py +12 -9
- plotnine/stats/stat_ecdf.py +6 -5
- plotnine/stats/stat_ellipse.py +5 -6
- plotnine/stats/stat_function.py +6 -8
- plotnine/stats/stat_hull.py +2 -3
- plotnine/stats/stat_identity.py +1 -2
- plotnine/stats/stat_pointdensity.py +4 -7
- plotnine/stats/stat_qq.py +45 -20
- plotnine/stats/stat_qq_line.py +15 -11
- plotnine/stats/stat_quantile.py +6 -7
- plotnine/stats/stat_sina.py +12 -14
- plotnine/stats/stat_smooth.py +7 -10
- plotnine/stats/stat_sum.py +1 -2
- plotnine/stats/stat_summary.py +6 -9
- plotnine/stats/stat_summary_bin.py +10 -13
- plotnine/stats/stat_unique.py +1 -2
- plotnine/stats/stat_ydensity.py +7 -10
- {plotnine-0.15.0a2.dist-info → plotnine-0.15.0a3.dist-info}/METADATA +3 -3
- {plotnine-0.15.0a2.dist-info → plotnine-0.15.0a3.dist-info}/RECORD +67 -67
- {plotnine-0.15.0a2.dist-info → plotnine-0.15.0a3.dist-info}/WHEEL +1 -1
- {plotnine-0.15.0a2.dist-info → plotnine-0.15.0a3.dist-info}/licenses/LICENSE +0 -0
- {plotnine-0.15.0a2.dist-info → plotnine-0.15.0a3.dist-info}/top_level.txt +0 -0
plotnine/geoms/geom_ribbon.py
CHANGED
|
@@ -94,7 +94,7 @@ class geom_ribbon(geom):
|
|
|
94
94
|
panel_params: panel_view,
|
|
95
95
|
coord: coord,
|
|
96
96
|
ax: Axes,
|
|
97
|
-
|
|
97
|
+
params: dict[str, Any],
|
|
98
98
|
):
|
|
99
99
|
_x = "y" if isinstance(coord, coord_flip) else "x"
|
|
100
100
|
data = coord.transform(data, panel_params, munch=True)
|
|
@@ -107,7 +107,7 @@ class geom_ribbon(geom):
|
|
|
107
107
|
|
|
108
108
|
for _, udata in data.groupby(units, dropna=False):
|
|
109
109
|
udata.reset_index(inplace=True, drop=True)
|
|
110
|
-
geom_ribbon.draw_unit(udata, panel_params, coord, ax,
|
|
110
|
+
geom_ribbon.draw_unit(udata, panel_params, coord, ax, params)
|
|
111
111
|
|
|
112
112
|
@staticmethod
|
|
113
113
|
def draw_unit(
|
|
@@ -115,7 +115,7 @@ class geom_ribbon(geom):
|
|
|
115
115
|
panel_params: panel_view,
|
|
116
116
|
coord: coord,
|
|
117
117
|
ax: Axes,
|
|
118
|
-
|
|
118
|
+
params: dict[str, Any],
|
|
119
119
|
):
|
|
120
120
|
linewidth = data["size"].iloc[0] * SIZE_FACTOR
|
|
121
121
|
fill = to_rgba(data["fill"], data["alpha"])
|
|
@@ -159,7 +159,7 @@ class geom_ribbon(geom):
|
|
|
159
159
|
|
|
160
160
|
# Alpha does not affect the outlines
|
|
161
161
|
data["alpha"] = 1
|
|
162
|
-
geom_ribbon._draw_outline(data, panel_params, coord, ax,
|
|
162
|
+
geom_ribbon._draw_outline(data, panel_params, coord, ax, params)
|
|
163
163
|
|
|
164
164
|
@staticmethod
|
|
165
165
|
def _draw_outline(
|
|
@@ -167,7 +167,7 @@ class geom_ribbon(geom):
|
|
|
167
167
|
panel_params: panel_view,
|
|
168
168
|
coord: coord,
|
|
169
169
|
ax: Axes,
|
|
170
|
-
|
|
170
|
+
params: dict[str, Any],
|
|
171
171
|
):
|
|
172
172
|
outline_type = params["outline_type"]
|
|
173
173
|
|
|
@@ -185,7 +185,7 @@ class geom_ribbon(geom):
|
|
|
185
185
|
panel_params,
|
|
186
186
|
coord,
|
|
187
187
|
ax,
|
|
188
|
-
|
|
188
|
+
params,
|
|
189
189
|
)
|
|
190
190
|
|
|
191
191
|
if outline_type in ("upper", "both"):
|
|
@@ -194,5 +194,5 @@ class geom_ribbon(geom):
|
|
|
194
194
|
panel_params,
|
|
195
195
|
coord,
|
|
196
196
|
ax,
|
|
197
|
-
|
|
197
|
+
params,
|
|
198
198
|
)
|
plotnine/geoms/geom_rug.py
CHANGED
plotnine/geoms/geom_segment.py
CHANGED
|
@@ -64,7 +64,7 @@ class geom_segment(geom):
|
|
|
64
64
|
panel_params: panel_view,
|
|
65
65
|
coord: coord,
|
|
66
66
|
ax: Axes,
|
|
67
|
-
|
|
67
|
+
params: dict[str, Any],
|
|
68
68
|
):
|
|
69
69
|
from matplotlib.collections import LineCollection
|
|
70
70
|
|
|
@@ -100,5 +100,5 @@ class geom_segment(geom):
|
|
|
100
100
|
adata[param] = np.hstack([data[param], data[param]])
|
|
101
101
|
|
|
102
102
|
params["arrow"].draw(
|
|
103
|
-
adata, panel_params, coord, ax, constant=False
|
|
103
|
+
adata, panel_params, coord, ax, params, constant=False
|
|
104
104
|
)
|
plotnine/geoms/geom_smooth.py
CHANGED
|
@@ -78,7 +78,7 @@ class geom_smooth(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
|
has_ribbon = "ymin" in data and "ymax" in data
|
|
84
84
|
if has_ribbon:
|
|
@@ -86,10 +86,10 @@ class geom_smooth(geom):
|
|
|
86
86
|
data2["color"] = "none"
|
|
87
87
|
params2 = params.copy()
|
|
88
88
|
params2["outline_type"] = "full"
|
|
89
|
-
geom_ribbon.draw_group(data2, panel_params, coord, ax,
|
|
89
|
+
geom_ribbon.draw_group(data2, panel_params, coord, ax, params2)
|
|
90
90
|
|
|
91
91
|
data["alpha"] = 1
|
|
92
|
-
geom_line.draw_group(data, panel_params, coord, ax,
|
|
92
|
+
geom_line.draw_group(data, panel_params, coord, ax, params)
|
|
93
93
|
|
|
94
94
|
@staticmethod
|
|
95
95
|
def draw_legend(
|
plotnine/geoms/geom_step.py
CHANGED
|
@@ -54,7 +54,7 @@ class geom_step(geom_path):
|
|
|
54
54
|
panel_params: panel_view,
|
|
55
55
|
coord: coord,
|
|
56
56
|
ax: Axes,
|
|
57
|
-
|
|
57
|
+
params: dict[str, Any],
|
|
58
58
|
):
|
|
59
59
|
direction = params["direction"]
|
|
60
60
|
n = len(data)
|
|
@@ -84,4 +84,4 @@ class geom_step(geom_path):
|
|
|
84
84
|
|
|
85
85
|
path_data = pd.DataFrame({"x": new_x, "y": new_y})
|
|
86
86
|
copy_missing_columns(path_data, data)
|
|
87
|
-
geom_path.draw_group(path_data, panel_params, coord, ax,
|
|
87
|
+
geom_path.draw_group(path_data, panel_params, coord, ax, params)
|
plotnine/geoms/geom_text.py
CHANGED
|
@@ -214,9 +214,8 @@ class geom_text(geom):
|
|
|
214
214
|
panel_params: panel_view,
|
|
215
215
|
coord: coord,
|
|
216
216
|
ax: Axes,
|
|
217
|
-
**params: Any,
|
|
218
217
|
):
|
|
219
|
-
super().draw_panel(data, panel_params, coord, ax
|
|
218
|
+
super().draw_panel(data, panel_params, coord, ax)
|
|
220
219
|
|
|
221
220
|
@staticmethod
|
|
222
221
|
def draw_group(
|
|
@@ -224,7 +223,7 @@ class geom_text(geom):
|
|
|
224
223
|
panel_params: panel_view,
|
|
225
224
|
coord: coord,
|
|
226
225
|
ax: Axes,
|
|
227
|
-
|
|
226
|
+
params: dict[str, Any],
|
|
228
227
|
):
|
|
229
228
|
data = coord.transform(data, panel_params)
|
|
230
229
|
zorder = params["zorder"]
|
plotnine/geoms/geom_violin.py
CHANGED
|
@@ -113,8 +113,8 @@ class geom_violin(geom):
|
|
|
113
113
|
panel_params: panel_view,
|
|
114
114
|
coord: coord,
|
|
115
115
|
ax: Axes,
|
|
116
|
-
**params: Any,
|
|
117
116
|
):
|
|
117
|
+
params = self.params.copy()
|
|
118
118
|
quantiles = params.pop("draw_quantiles")
|
|
119
119
|
style = params.pop("style")
|
|
120
120
|
zorder = params.pop("zorder")
|
|
@@ -125,6 +125,7 @@ class geom_violin(geom):
|
|
|
125
125
|
# in the range [zorder, zorder + 1) to stay within the layer.
|
|
126
126
|
group = cast("int", group)
|
|
127
127
|
group_zorder = zorder + 0.9 / group
|
|
128
|
+
params["zorder"] = group_zorder
|
|
128
129
|
|
|
129
130
|
# Find the points for the line to go all the way around
|
|
130
131
|
df["xminv"] = df["x"] - df["violinwidth"] * (df["x"] - df["xmin"])
|
|
@@ -167,8 +168,7 @@ class geom_violin(geom):
|
|
|
167
168
|
panel_params,
|
|
168
169
|
coord,
|
|
169
170
|
ax,
|
|
170
|
-
|
|
171
|
-
**params,
|
|
171
|
+
params,
|
|
172
172
|
)
|
|
173
173
|
|
|
174
174
|
if quantiles is not None:
|
|
@@ -190,8 +190,7 @@ class geom_violin(geom):
|
|
|
190
190
|
panel_params,
|
|
191
191
|
coord,
|
|
192
192
|
ax,
|
|
193
|
-
|
|
194
|
-
**params,
|
|
193
|
+
params,
|
|
195
194
|
)
|
|
196
195
|
|
|
197
196
|
|
plotnine/geoms/geom_vline.py
CHANGED
|
@@ -80,7 +80,6 @@ class geom_vline(geom):
|
|
|
80
80
|
panel_params: panel_view,
|
|
81
81
|
coord: coord,
|
|
82
82
|
ax: Axes,
|
|
83
|
-
**params: Any,
|
|
84
83
|
):
|
|
85
84
|
"""
|
|
86
85
|
Plot all groups
|
|
@@ -94,7 +93,9 @@ class geom_vline(geom):
|
|
|
94
93
|
|
|
95
94
|
for _, gdata in data.groupby("group"):
|
|
96
95
|
gdata.reset_index(inplace=True)
|
|
97
|
-
geom_segment.draw_group(
|
|
96
|
+
geom_segment.draw_group(
|
|
97
|
+
gdata, panel_params, coord, ax, self.params
|
|
98
|
+
)
|
|
98
99
|
|
|
99
100
|
@staticmethod
|
|
100
101
|
def draw_legend(
|
plotnine/guides/guides.py
CHANGED
|
@@ -369,7 +369,7 @@ class guides:
|
|
|
369
369
|
# place the guides according to the guide.order
|
|
370
370
|
default = max(g.order for g in gdefs) + 1
|
|
371
371
|
orders = [default if g.order == 0 else g.order for g in gdefs]
|
|
372
|
-
idx
|
|
372
|
+
idx = cast("Sequence[int]", np.argsort(orders))
|
|
373
373
|
gdefs = [gdefs[i] for i in idx]
|
|
374
374
|
|
|
375
375
|
# Draw each guide into a box
|
plotnine/layer.py
CHANGED
|
@@ -163,6 +163,7 @@ class layer:
|
|
|
163
163
|
self._make_layer_data(plot.data)
|
|
164
164
|
self._make_layer_mapping(plot.mapping)
|
|
165
165
|
self._make_layer_environments(plot.environment)
|
|
166
|
+
self._share_layer_params()
|
|
166
167
|
|
|
167
168
|
def _make_layer_data(self, plot_data: DataLike | None):
|
|
168
169
|
"""
|
|
@@ -250,6 +251,13 @@ class layer:
|
|
|
250
251
|
self.geom.environment = plot_environment
|
|
251
252
|
self.stat.environment = plot_environment
|
|
252
253
|
|
|
254
|
+
def _share_layer_params(self):
|
|
255
|
+
"""
|
|
256
|
+
Pass necessary layer parameters to the geom
|
|
257
|
+
"""
|
|
258
|
+
self.geom.params["zorder"] = self.zorder
|
|
259
|
+
self.geom.params["raster"] = self.raster
|
|
260
|
+
|
|
253
261
|
def compute_aesthetics(self, plot: ggplot):
|
|
254
262
|
"""
|
|
255
263
|
Return a dataframe where the columns match the aesthetic mappings
|
|
@@ -278,10 +286,10 @@ class layer:
|
|
|
278
286
|
if not len(data):
|
|
279
287
|
return
|
|
280
288
|
|
|
281
|
-
|
|
289
|
+
self.stat.setup_params(data)
|
|
282
290
|
data = self.stat.use_defaults(data)
|
|
283
291
|
data = self.stat.setup_data(data)
|
|
284
|
-
data = self.stat.compute_layer(data,
|
|
292
|
+
data = self.stat.compute_layer(data, layout)
|
|
285
293
|
self.data = data
|
|
286
294
|
|
|
287
295
|
def map_statistic(self, plot: ggplot):
|
|
@@ -320,6 +328,8 @@ class layer:
|
|
|
320
328
|
if len(data) == 0:
|
|
321
329
|
return
|
|
322
330
|
|
|
331
|
+
self.geom.params.update(self.stat.params)
|
|
332
|
+
self.geom.setup_params(data)
|
|
323
333
|
data = self.geom.setup_data(data)
|
|
324
334
|
|
|
325
335
|
check_required_aesthetics(
|
|
@@ -357,14 +367,10 @@ class layer:
|
|
|
357
367
|
coord : coord
|
|
358
368
|
Type of coordinate axes
|
|
359
369
|
"""
|
|
360
|
-
params = copy(self.geom.params)
|
|
361
|
-
params.update(self.stat.params)
|
|
362
|
-
params["zorder"] = self.zorder
|
|
363
|
-
params["raster"] = self.raster
|
|
364
370
|
self.data = self.geom.handle_na(self.data)
|
|
365
371
|
# At this point each layer must have the data
|
|
366
372
|
# that is created by the plot build process
|
|
367
|
-
self.geom.draw_layer(self.data, layout, coord
|
|
373
|
+
self.geom.draw_layer(self.data, layout, coord)
|
|
368
374
|
|
|
369
375
|
def use_defaults(
|
|
370
376
|
self,
|
|
@@ -399,7 +405,7 @@ class layer:
|
|
|
399
405
|
"""
|
|
400
406
|
Prepare/modify data for plotting
|
|
401
407
|
"""
|
|
402
|
-
self.stat.finish_layer(self.data
|
|
408
|
+
self.stat.finish_layer(self.data)
|
|
403
409
|
|
|
404
410
|
|
|
405
411
|
class Layers(List[layer]):
|
|
@@ -450,7 +456,9 @@ class Layers(List[layer]):
|
|
|
450
456
|
return [l.data for l in self]
|
|
451
457
|
|
|
452
458
|
def setup(self, plot: ggplot):
|
|
453
|
-
|
|
459
|
+
# If zorder is 0, it is left to MPL
|
|
460
|
+
for i, l in enumerate(self, start=1):
|
|
461
|
+
l.zorder = i
|
|
454
462
|
l.setup(plot)
|
|
455
463
|
|
|
456
464
|
def setup_data(self):
|
|
@@ -458,9 +466,7 @@ class Layers(List[layer]):
|
|
|
458
466
|
l.setup_data()
|
|
459
467
|
|
|
460
468
|
def draw(self, layout: Layout, coord: coord):
|
|
461
|
-
|
|
462
|
-
for i, l in enumerate(self, start=1):
|
|
463
|
-
l.zorder = i
|
|
469
|
+
for l in self:
|
|
464
470
|
l.draw(layout, coord)
|
|
465
471
|
|
|
466
472
|
def compute_aesthetics(self, plot: ggplot):
|
|
@@ -48,7 +48,7 @@ def factor(
|
|
|
48
48
|
`categories` attribute (which in turn is the `categories` argument, if
|
|
49
49
|
provided).
|
|
50
50
|
"""
|
|
51
|
-
return pd.Categorical(values, categories=categories, ordered=None)
|
|
51
|
+
return pd.Categorical(values, categories=categories, ordered=None) # pyright: ignore[reportArgumentType]
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
def reorder(x, y, fun=np.median, ascending=True):
|
plotnine/scales/scale_color.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from dataclasses import KW_ONLY, InitVar, dataclass
|
|
3
|
+
from dataclasses import KW_ONLY, InitVar, dataclass, field
|
|
4
4
|
from typing import Literal, Sequence
|
|
5
5
|
from warnings import warn
|
|
6
6
|
|
|
@@ -50,34 +50,66 @@ class scale_color_hue(_scale_color_discrete):
|
|
|
50
50
|
Qualitative color scale with evenly spaced hues
|
|
51
51
|
"""
|
|
52
52
|
|
|
53
|
-
h: InitVar[float] =
|
|
53
|
+
h: InitVar[float | tuple[float, float]] = 15
|
|
54
54
|
"""
|
|
55
|
-
Hue.
|
|
55
|
+
Hue. If a float, it is the first hue value, in the range `[0, 360]`.
|
|
56
|
+
The range of the palette will be `[first, first + 360)`.
|
|
57
|
+
|
|
58
|
+
If a tuple, it is the range `[first, last)` of the hues.
|
|
56
59
|
"""
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
c: InitVar[float] = 100
|
|
59
62
|
"""
|
|
60
|
-
|
|
63
|
+
Chroma. Must be in the range `[0, 100]`
|
|
61
64
|
"""
|
|
62
65
|
|
|
63
|
-
|
|
66
|
+
l: InitVar[float] = 65
|
|
64
67
|
"""
|
|
65
|
-
|
|
68
|
+
Lightness. Must be in the range [0, 100]
|
|
66
69
|
"""
|
|
67
70
|
|
|
68
|
-
|
|
71
|
+
direction: InitVar[Literal[1, -1]] = 1
|
|
69
72
|
"""
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
or [hsluv](https://www.hsluv.org/).
|
|
73
|
-
https://www.hsluv.org/
|
|
73
|
+
The order of colours in the scale. If -1 the order
|
|
74
|
+
of colours is reversed. The default is 1.
|
|
74
75
|
"""
|
|
75
76
|
|
|
76
|
-
|
|
77
|
+
_: KW_ONLY
|
|
78
|
+
|
|
79
|
+
s: None = field(default=None, repr=False)
|
|
80
|
+
"""
|
|
81
|
+
Not being use and will be removed in a future version
|
|
82
|
+
"""
|
|
83
|
+
color_space: None = field(default=None, repr=False)
|
|
84
|
+
"""
|
|
85
|
+
Not being use and will be removed in a future version
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def __post_init__(self, h, c, l, direction):
|
|
77
89
|
from mizani.palettes import hue_pal
|
|
78
90
|
|
|
91
|
+
if (s := self.s) is not None:
|
|
92
|
+
warn(
|
|
93
|
+
f"You used {s=} for the saturation which has been ignored. "
|
|
94
|
+
f"{self.__class__.__name__} now works in HCL colorspace. "
|
|
95
|
+
f"Using `s` in future versions will throw an exception.",
|
|
96
|
+
FutureWarning,
|
|
97
|
+
)
|
|
98
|
+
del self.s
|
|
99
|
+
|
|
100
|
+
if (color_space := self.color_space) is not None:
|
|
101
|
+
warn(
|
|
102
|
+
f"You used {color_space=} to select a color_space and it "
|
|
103
|
+
f"has been ignored. {self.__class__.__name__} now only works "
|
|
104
|
+
f"in HCL colorspace. Using `color_space` in future versions "
|
|
105
|
+
"will throw an exception.",
|
|
106
|
+
FutureWarning,
|
|
107
|
+
)
|
|
108
|
+
del self.color_space
|
|
109
|
+
|
|
79
110
|
super().__post_init__()
|
|
80
|
-
self.palette = hue_pal(h,
|
|
111
|
+
self.palette = hue_pal(h, c, l, direction)
|
|
112
|
+
self.palette.h
|
|
81
113
|
|
|
82
114
|
|
|
83
115
|
@dataclass
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from contextlib import suppress
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import TYPE_CHECKING, Sequence
|
|
5
|
+
from typing import TYPE_CHECKING, Sequence, cast
|
|
6
6
|
from warnings import warn
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
@@ -387,15 +387,16 @@ class scale_continuous(
|
|
|
387
387
|
limits = self.final_limits
|
|
388
388
|
|
|
389
389
|
x = self.oob(self.rescaler(x, _from=limits))
|
|
390
|
+
na_value = cast("float", self.na_value)
|
|
390
391
|
|
|
391
392
|
uniq = np.unique(x)
|
|
392
393
|
pal = np.asarray(self.palette(uniq))
|
|
393
394
|
scaled = pal[match(x, uniq)]
|
|
394
395
|
if scaled.dtype.kind == "U":
|
|
395
|
-
scaled = [
|
|
396
|
+
scaled = [na_value if x == "nan" else x for x in scaled]
|
|
396
397
|
else:
|
|
397
|
-
scaled[pd.isna(scaled)] =
|
|
398
|
-
return scaled
|
|
398
|
+
scaled[pd.isna(scaled)] = na_value
|
|
399
|
+
return scaled # pyright: ignore[reportReturnType]
|
|
399
400
|
|
|
400
401
|
def get_breaks(
|
|
401
402
|
self, limits: Optional[tuple[float, float]] = None
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import KW_ONLY, InitVar, dataclass
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
5
|
+
from warnings import warn
|
|
5
6
|
|
|
6
7
|
from ._runtime_typing import TransUser # noqa: TCH001
|
|
7
8
|
from .scale_continuous import scale_continuous
|
|
@@ -20,24 +21,21 @@ class scale_datetime(scale_continuous):
|
|
|
20
21
|
"""
|
|
21
22
|
A string giving the distance between major breaks.
|
|
22
23
|
For example `'2 weeks'`, `'5 years'`. If specified,
|
|
23
|
-
`date_breaks` takes precedence over
|
|
24
|
-
`breaks`.
|
|
24
|
+
`date_breaks` takes precedence over `breaks`.
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
27
|
date_labels: InitVar[str | None] = None
|
|
28
28
|
"""
|
|
29
29
|
Format string for the labels.
|
|
30
30
|
See [strftime](:ref:`strftime-strptime-behavior`).
|
|
31
|
-
If specified, `date_labels` takes precedence over
|
|
32
|
-
`labels`.
|
|
31
|
+
If specified, `date_labels` takes precedence over `labels`.
|
|
33
32
|
"""
|
|
34
33
|
|
|
35
34
|
date_minor_breaks: InitVar[str | None] = None
|
|
36
35
|
"""
|
|
37
36
|
A string giving the distance between minor breaks.
|
|
38
37
|
For example `'2 weeks'`, `'5 years'`. If specified,
|
|
39
|
-
`date_minor_breaks` takes precedence over
|
|
40
|
-
`minor_breaks`.
|
|
38
|
+
`date_minor_breaks` takes precedence over `minor_breaks`.
|
|
41
39
|
"""
|
|
42
40
|
|
|
43
41
|
_: KW_ONLY
|
|
@@ -80,22 +78,38 @@ class scale_datetime(scale_continuous):
|
|
|
80
78
|
date_labels: str | None,
|
|
81
79
|
date_minor_breaks: str | None,
|
|
82
80
|
):
|
|
83
|
-
from mizani.breaks import
|
|
84
|
-
from mizani.labels import label_date
|
|
81
|
+
from mizani.breaks import breaks_date_width
|
|
82
|
+
from mizani.labels import label_date
|
|
85
83
|
|
|
86
84
|
if date_breaks is not None:
|
|
87
|
-
self.breaks =
|
|
85
|
+
self.breaks = breaks_date_width(date_breaks) # pyright: ignore[reportAttributeAccessIssue]
|
|
88
86
|
elif isinstance(self.breaks, str):
|
|
89
|
-
|
|
87
|
+
warn(
|
|
88
|
+
"Passing a string to `breaks` will not work in "
|
|
89
|
+
f"future versions. Use `date_breaks={self.breaks!r}`",
|
|
90
|
+
FutureWarning,
|
|
91
|
+
)
|
|
92
|
+
self.breaks = breaks_date_width(width=self.breaks) # pyright: ignore[reportAttributeAccessIssue]
|
|
90
93
|
|
|
91
94
|
if date_labels is not None:
|
|
92
|
-
self.labels =
|
|
95
|
+
self.labels = label_date(fmt=date_labels) # pyright: ignore[reportAttributeAccessIssue]
|
|
93
96
|
elif isinstance(self.labels, str):
|
|
94
|
-
|
|
97
|
+
warn(
|
|
98
|
+
"Passing a string to `labels` will not work in "
|
|
99
|
+
f"future versions. Use `date_labels={self.labels!r}`",
|
|
100
|
+
FutureWarning,
|
|
101
|
+
)
|
|
102
|
+
self.labels = label_date(fmt=self.labels) # pyright: ignore[reportAttributeAccessIssue]
|
|
95
103
|
|
|
96
104
|
if date_minor_breaks is not None:
|
|
97
|
-
self.minor_breaks =
|
|
105
|
+
self.minor_breaks = breaks_date_width(date_minor_breaks) # pyright: ignore[reportAttributeAccessIssue]
|
|
98
106
|
elif isinstance(self.minor_breaks, str):
|
|
99
|
-
|
|
107
|
+
warn(
|
|
108
|
+
"Passing a string to `minor_breaks` will not work in "
|
|
109
|
+
"future versions. "
|
|
110
|
+
f"Use `date_minor_breaks={self.minor_breaks!r}`",
|
|
111
|
+
FutureWarning,
|
|
112
|
+
)
|
|
113
|
+
self.minor_breaks = breaks_date_width(width=self.minor_breaks) # pyright: ignore[reportAttributeAccessIssue]
|
|
100
114
|
|
|
101
115
|
scale_continuous.__post_init__(self)
|
|
@@ -156,7 +156,7 @@ class scale_discrete(
|
|
|
156
156
|
range = self.dimension(limits=limits)
|
|
157
157
|
|
|
158
158
|
breaks_d = self.get_breaks(limits)
|
|
159
|
-
breaks = self.map(pd.Categorical(breaks_d))
|
|
159
|
+
breaks = self.map(pd.Categorical(breaks_d)) # pyright: ignore[reportArgumentType]
|
|
160
160
|
minor_breaks = []
|
|
161
161
|
labels = self.get_labels(breaks_d)
|
|
162
162
|
|
|
@@ -206,7 +206,7 @@ class scale_discrete(
|
|
|
206
206
|
pal = np.asarray(pal, dtype=object)
|
|
207
207
|
idx = np.asarray(match(x, limits))
|
|
208
208
|
try:
|
|
209
|
-
pal_match = [pal[i] if i >= 0 else None for i in idx]
|
|
209
|
+
pal_match = [pal[i] if i >= 0 else None for i in idx] # pyright: ignore[reportCallIssue,reportArgumentType]
|
|
210
210
|
except IndexError:
|
|
211
211
|
# Deal with missing data
|
|
212
212
|
# - Insert NaN where there is no match
|
plotnine/scales/scale_xy.py
CHANGED
|
@@ -213,7 +213,7 @@ class scale_x_discrete(scale_position_discrete):
|
|
|
213
213
|
Discrete x position
|
|
214
214
|
"""
|
|
215
215
|
|
|
216
|
-
_aesthetics = ["x", "xmin", "xmax", "xend"]
|
|
216
|
+
_aesthetics = ["x", "xmin", "xmax", "xend", "xintercept"]
|
|
217
217
|
|
|
218
218
|
|
|
219
219
|
@dataclass(kw_only=True)
|
|
@@ -222,7 +222,7 @@ class scale_y_discrete(scale_position_discrete):
|
|
|
222
222
|
Discrete y position
|
|
223
223
|
"""
|
|
224
224
|
|
|
225
|
-
_aesthetics = ["y", "ymin", "ymax", "yend"]
|
|
225
|
+
_aesthetics = ["y", "ymin", "ymax", "yend", "yintercept"]
|
|
226
226
|
|
|
227
227
|
|
|
228
228
|
# Not part of the user API
|