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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Margin
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
@@ -17,17 +17,55 @@ if TYPE_CHECKING:
|
|
|
17
17
|
|
|
18
18
|
@dataclass
|
|
19
19
|
class margin:
|
|
20
|
+
"""
|
|
21
|
+
Margin
|
|
22
|
+
"""
|
|
23
|
+
|
|
20
24
|
t: float = 0
|
|
25
|
+
"""
|
|
26
|
+
Top margin
|
|
27
|
+
"""
|
|
28
|
+
|
|
21
29
|
r: float = 0
|
|
30
|
+
"""
|
|
31
|
+
Right margin
|
|
32
|
+
"""
|
|
33
|
+
|
|
22
34
|
b: float = 0
|
|
35
|
+
"""
|
|
36
|
+
Bottom margin
|
|
37
|
+
"""
|
|
38
|
+
|
|
23
39
|
l: float = 0
|
|
40
|
+
"""
|
|
41
|
+
Left Margin
|
|
42
|
+
"""
|
|
43
|
+
|
|
24
44
|
unit: Literal["pt", "in", "lines", "fig"] = "pt"
|
|
45
|
+
"""
|
|
46
|
+
The units (coordinate space) of the values
|
|
47
|
+
"""
|
|
25
48
|
|
|
26
49
|
# These are set by the themeable when it is applied
|
|
27
50
|
fontsize: float = field(init=False, default=0)
|
|
51
|
+
"""
|
|
52
|
+
Font size of text that this margin applies to
|
|
53
|
+
"""
|
|
54
|
+
|
|
28
55
|
figure_size: tuple[float, float] = field(init=False, default=(0, 0))
|
|
56
|
+
"""
|
|
57
|
+
Size of the figure in inches
|
|
58
|
+
"""
|
|
29
59
|
|
|
30
60
|
def setup(self, theme: theme, themeable_name: str):
|
|
61
|
+
"""
|
|
62
|
+
Setup the margin to be used in the layout
|
|
63
|
+
|
|
64
|
+
For the margin's values to be useful, we need to be able to
|
|
65
|
+
convert them to different units as is required. Here we get
|
|
66
|
+
all the parameters that we shall need to do the conversions.
|
|
67
|
+
"""
|
|
68
|
+
self.themeable_name = themeable_name
|
|
31
69
|
self.fontsize = theme.getp((themeable_name, "size"), 11)
|
|
32
70
|
self.figure_size = theme.getp("figure_size")
|
|
33
71
|
|
|
@@ -35,6 +73,8 @@ class margin:
|
|
|
35
73
|
def pt(self) -> margin:
|
|
36
74
|
"""
|
|
37
75
|
Return margin in points
|
|
76
|
+
|
|
77
|
+
These are the units of the display coordinate system
|
|
38
78
|
"""
|
|
39
79
|
return self.to("pt")
|
|
40
80
|
|
|
@@ -42,6 +82,8 @@ class margin:
|
|
|
42
82
|
def inch(self) -> margin:
|
|
43
83
|
"""
|
|
44
84
|
Return margin in inches
|
|
85
|
+
|
|
86
|
+
These are the units of the figure-inches coordinate system
|
|
45
87
|
"""
|
|
46
88
|
return self.to("in")
|
|
47
89
|
|
|
@@ -56,6 +98,8 @@ class margin:
|
|
|
56
98
|
def fig(self) -> margin:
|
|
57
99
|
"""
|
|
58
100
|
Return margin in figure units
|
|
101
|
+
|
|
102
|
+
These are the units of the figure coordinate system
|
|
59
103
|
"""
|
|
60
104
|
return self.to("fig")
|
|
61
105
|
|
|
@@ -102,3 +146,22 @@ class margin:
|
|
|
102
146
|
}
|
|
103
147
|
|
|
104
148
|
return functions[conversion](value)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def margin_auto(
|
|
152
|
+
t: float = 0.0,
|
|
153
|
+
r: float | None = None,
|
|
154
|
+
b: float | None = None,
|
|
155
|
+
l: float | None = None,
|
|
156
|
+
unit: Literal["pt", "in", "lines", "fig"] = "pt",
|
|
157
|
+
) -> margin:
|
|
158
|
+
"""
|
|
159
|
+
Create margin with minimal arguments
|
|
160
|
+
"""
|
|
161
|
+
if r is None:
|
|
162
|
+
r = t
|
|
163
|
+
if b is None:
|
|
164
|
+
b = t
|
|
165
|
+
if l is None:
|
|
166
|
+
l = r
|
|
167
|
+
return margin(t, r, b, l, unit)
|
plotnine/themes/theme.py
CHANGED
|
@@ -72,7 +72,7 @@ class theme:
|
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
will only modify the x-axis text.
|
|
75
|
-
kwargs:
|
|
75
|
+
kwargs: Any
|
|
76
76
|
kwargs are `themeables`. The themeables are elements that are
|
|
77
77
|
subclasses of `themeable`. Many themeables are defined using
|
|
78
78
|
theme elements i.e
|
|
@@ -276,6 +276,14 @@ class theme:
|
|
|
276
276
|
"""
|
|
277
277
|
return self.themeables.getp((name, "margin"))
|
|
278
278
|
|
|
279
|
+
@cached_property
|
|
280
|
+
def get_ha(self):
|
|
281
|
+
return self.themeables.get_ha
|
|
282
|
+
|
|
283
|
+
@cached_property
|
|
284
|
+
def get_va(self):
|
|
285
|
+
return self.themeables.get_va
|
|
286
|
+
|
|
279
287
|
def apply(self):
|
|
280
288
|
"""
|
|
281
289
|
Apply this theme, then apply additional modifications in order.
|
plotnine/themes/theme_538.py
CHANGED
|
@@ -23,7 +23,6 @@ class theme_538(theme_gray):
|
|
|
23
23
|
axis_ticks=element_blank(),
|
|
24
24
|
title=element_text(color="#3C3C3C"),
|
|
25
25
|
legend_background=element_rect(fill="none"),
|
|
26
|
-
legend_key=element_rect(fill="#E0E0E0"),
|
|
27
26
|
panel_background=element_rect(fill=bgcolor),
|
|
28
27
|
panel_border=element_blank(),
|
|
29
28
|
panel_grid_major=element_line(color="#D5D5D5"),
|
plotnine/themes/theme_bw.py
CHANGED
|
@@ -20,7 +20,6 @@ class theme_bw(theme_gray):
|
|
|
20
20
|
super().__init__(base_size, base_family)
|
|
21
21
|
self += theme(
|
|
22
22
|
axis_text=element_text(size=0.8 * base_size),
|
|
23
|
-
legend_key=element_rect(fill="none", color="#CCCCCC"),
|
|
24
23
|
panel_background=element_rect(fill="white"),
|
|
25
24
|
panel_border=element_rect(fill="none", color="#7f7f7f"),
|
|
26
25
|
panel_grid_major=element_line(color="#E5E5E5"),
|
plotnine/themes/theme_dark.py
CHANGED
|
@@ -24,7 +24,6 @@ class theme_dark(theme_gray):
|
|
|
24
24
|
self += theme(
|
|
25
25
|
axis_ticks=element_line(color="#666666", size=0.5),
|
|
26
26
|
axis_ticks_minor=element_blank(),
|
|
27
|
-
legend_key=element_rect(fill="#7F7F7F", color="#666666", size=0.5),
|
|
28
27
|
panel_background=element_rect(fill="#7F7F7F", color="none"),
|
|
29
28
|
panel_grid_major=element_line(color="#666666", size=0.5),
|
|
30
29
|
panel_grid_minor=element_line(color="#737373", size=0.25),
|
plotnine/themes/theme_gray.py
CHANGED
|
@@ -6,6 +6,7 @@ from .elements import (
|
|
|
6
6
|
element_rect,
|
|
7
7
|
element_text,
|
|
8
8
|
margin,
|
|
9
|
+
margin_auto,
|
|
9
10
|
)
|
|
10
11
|
from .theme import theme
|
|
11
12
|
|
|
@@ -27,6 +28,7 @@ class theme_gray(theme):
|
|
|
27
28
|
|
|
28
29
|
def __init__(self, base_size=11, base_family=None):
|
|
29
30
|
base_family = base_family or get_option("base_family")
|
|
31
|
+
half_line = base_size / 2
|
|
30
32
|
quarter_line = base_size / 4
|
|
31
33
|
fifth_line = base_size / 5
|
|
32
34
|
eighth_line = base_size / 8
|
|
@@ -81,7 +83,6 @@ class theme_gray(theme):
|
|
|
81
83
|
legend_frame=element_blank(),
|
|
82
84
|
legend_key_spacing_x=6,
|
|
83
85
|
legend_key_spacing_y=2,
|
|
84
|
-
legend_key=element_rect(fill="#F2F2F2", colour="none"),
|
|
85
86
|
legend_key_size=base_size * 0.8 * 1.8,
|
|
86
87
|
legend_ticks_length=0.2,
|
|
87
88
|
legend_margin=0, # points
|
|
@@ -89,13 +90,13 @@ class theme_gray(theme):
|
|
|
89
90
|
legend_spacing=10, # points
|
|
90
91
|
legend_text=element_text(
|
|
91
92
|
size=base_size * 0.8,
|
|
92
|
-
margin=
|
|
93
|
+
margin=margin_auto(m / 1.5, unit="fig"),
|
|
93
94
|
),
|
|
94
95
|
legend_ticks=element_line(color="#CCCCCC", size=1),
|
|
95
96
|
legend_title=element_text(
|
|
96
97
|
margin=margin(t=m, l=m * 2, b=m / 2, r=m * 2, unit="fig")
|
|
97
98
|
),
|
|
98
|
-
panel_background=element_rect(fill="#EBEBEB"),
|
|
99
|
+
panel_background=element_rect(fill="#EBEBEB", color="none"),
|
|
99
100
|
panel_border=element_blank(),
|
|
100
101
|
panel_grid_major=element_line(color="white", size=1),
|
|
101
102
|
panel_grid_minor=element_line(color="white", size=0.5),
|
|
@@ -136,8 +137,8 @@ class theme_gray(theme):
|
|
|
136
137
|
strip_text=element_text(
|
|
137
138
|
color="#1A1A1A",
|
|
138
139
|
size=base_size * 0.8,
|
|
139
|
-
linespacing=1.
|
|
140
|
-
margin=
|
|
140
|
+
linespacing=1.5,
|
|
141
|
+
margin=margin_auto(half_line * 0.8),
|
|
141
142
|
),
|
|
142
143
|
strip_text_y=element_text(rotation=-90),
|
|
143
144
|
complete=True,
|
plotnine/themes/theme_light.py
CHANGED
|
@@ -24,7 +24,7 @@ class theme_light(theme_gray):
|
|
|
24
24
|
self += theme(
|
|
25
25
|
axis_ticks=element_line(color="#B3B3B3", size=0.5),
|
|
26
26
|
axis_ticks_minor=element_blank(),
|
|
27
|
-
legend_key=element_rect(
|
|
27
|
+
legend_key=element_rect(color="#7F7F7F", size=0.72),
|
|
28
28
|
panel_background=element_rect(fill="white"),
|
|
29
29
|
panel_border=element_rect(fill="none", color="#B3B3B3", size=1),
|
|
30
30
|
panel_grid_major=element_line(color="#D9D9D9", size=0.5),
|
|
@@ -5,6 +5,7 @@ from .elements import (
|
|
|
5
5
|
element_rect,
|
|
6
6
|
element_text,
|
|
7
7
|
margin,
|
|
8
|
+
margin_auto,
|
|
8
9
|
)
|
|
9
10
|
from .theme import theme
|
|
10
11
|
|
|
@@ -33,6 +34,7 @@ class theme_matplotlib(theme):
|
|
|
33
34
|
m = get_option("base_margin")
|
|
34
35
|
base_size = mpl.rcParams.get("font.size", 11)
|
|
35
36
|
linewidth = mpl.rcParams.get("grid.linewidth", 0.8)
|
|
37
|
+
half_line = base_size / 2
|
|
36
38
|
|
|
37
39
|
super().__init__(
|
|
38
40
|
line=element_line(size=linewidth),
|
|
@@ -63,15 +65,12 @@ class theme_matplotlib(theme):
|
|
|
63
65
|
legend_key_spacing_x=6,
|
|
64
66
|
legend_key_spacing_y=2,
|
|
65
67
|
legend_frame=element_rect(color="black"),
|
|
66
|
-
legend_key=element_blank(),
|
|
67
68
|
legend_key_size=16,
|
|
68
69
|
legend_ticks_length=0.2,
|
|
69
70
|
legend_margin=0,
|
|
70
71
|
legend_position="right",
|
|
71
72
|
legend_spacing=10,
|
|
72
|
-
legend_text=element_text(
|
|
73
|
-
margin=margin(m / 2, m / 2, m / 2, m / 2, "fig")
|
|
74
|
-
),
|
|
73
|
+
legend_text=element_text(margin=margin_auto(m / 2, unit="fig")),
|
|
75
74
|
legend_ticks=element_line(color="black"),
|
|
76
75
|
legend_title=element_text(
|
|
77
76
|
ha="left",
|
|
@@ -112,7 +111,8 @@ class theme_matplotlib(theme):
|
|
|
112
111
|
fill="#D9D9D9", color="black", size=linewidth
|
|
113
112
|
),
|
|
114
113
|
strip_text=element_text(
|
|
115
|
-
|
|
114
|
+
linespacing=1.5,
|
|
115
|
+
margin=margin_auto(half_line * 0.8),
|
|
116
116
|
),
|
|
117
117
|
strip_text_y=element_text(rotation=-90),
|
|
118
118
|
complete=True,
|
plotnine/themes/theme_seaborn.py
CHANGED
|
@@ -5,6 +5,7 @@ from .elements import (
|
|
|
5
5
|
element_rect,
|
|
6
6
|
element_text,
|
|
7
7
|
margin,
|
|
8
|
+
margin_auto,
|
|
8
9
|
)
|
|
9
10
|
from .theme import theme
|
|
10
11
|
|
|
@@ -20,7 +21,7 @@ class theme_seaborn(theme):
|
|
|
20
21
|
|
|
21
22
|
Parameters
|
|
22
23
|
----------
|
|
23
|
-
style: "
|
|
24
|
+
style: "white", "dark", "whitegrid", "darkgrid", "ticks"
|
|
24
25
|
Style of axis background.
|
|
25
26
|
context: "notebook", "talk", "paper", "poster"]``
|
|
26
27
|
Intended context for resulting figures.
|
|
@@ -83,13 +84,15 @@ class theme_seaborn(theme):
|
|
|
83
84
|
legend_position="right",
|
|
84
85
|
legend_spacing=10, # points
|
|
85
86
|
legend_text=element_text(
|
|
86
|
-
|
|
87
|
+
size=base_size * 0.8,
|
|
88
|
+
margin=margin_auto(m / 1.5, unit="fig"),
|
|
87
89
|
),
|
|
88
90
|
legend_ticks=element_line(color="#CCCCCC", size=1),
|
|
89
91
|
legend_title=element_text(
|
|
90
92
|
margin=margin(t=m, l=m * 2, b=m / 2, r=m * 2, unit="fig")
|
|
91
93
|
),
|
|
92
94
|
panel_spacing=m,
|
|
95
|
+
panel_background=element_rect(fill=rcparams["axes.facecolor"]),
|
|
93
96
|
plot_caption=element_text(
|
|
94
97
|
size=base_size * 0.8,
|
|
95
98
|
ha="right",
|
|
@@ -123,8 +126,8 @@ class theme_seaborn(theme):
|
|
|
123
126
|
strip_background=element_rect(color="none", fill="#D1CDDF"),
|
|
124
127
|
strip_text=element_text(
|
|
125
128
|
size=base_size * 0.8,
|
|
126
|
-
linespacing=1.
|
|
127
|
-
margin=
|
|
129
|
+
linespacing=1.5,
|
|
130
|
+
margin=margin_auto(half_line * 0.8),
|
|
128
131
|
),
|
|
129
132
|
strip_text_y=element_text(rotation=-90),
|
|
130
133
|
complete=True,
|
plotnine/themes/theme_void.py
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
from ..options import get_option
|
|
2
|
-
from .elements import
|
|
2
|
+
from .elements import (
|
|
3
|
+
element_blank,
|
|
4
|
+
element_line,
|
|
5
|
+
element_text,
|
|
6
|
+
margin,
|
|
7
|
+
margin_auto,
|
|
8
|
+
)
|
|
3
9
|
from .theme import theme
|
|
4
10
|
|
|
5
11
|
|
|
@@ -54,7 +60,7 @@ class theme_void(theme):
|
|
|
54
60
|
legend_spacing=10,
|
|
55
61
|
legend_text=element_text(
|
|
56
62
|
size=base_size * 0.8,
|
|
57
|
-
margin=
|
|
63
|
+
margin=margin_auto(m / 1.5, unit="fig"),
|
|
58
64
|
),
|
|
59
65
|
legend_ticks=element_line(color="#CCCCCC", size=1),
|
|
60
66
|
legend_title=element_text(
|
|
@@ -91,11 +97,6 @@ class theme_void(theme):
|
|
|
91
97
|
plot_tag_location="margin",
|
|
92
98
|
plot_tag_position="topleft",
|
|
93
99
|
strip_align=0,
|
|
94
|
-
strip_text=element_text(
|
|
95
|
-
color="#1A1A1A",
|
|
96
|
-
size=base_size * 0.8,
|
|
97
|
-
linespacing=1.0,
|
|
98
|
-
margin=margin(1 / 3, 1 / 3, 1 / 3, 1 / 3, "lines"),
|
|
99
|
-
),
|
|
100
|
+
strip_text=element_text(size=base_size * 0.8),
|
|
100
101
|
complete=True,
|
|
101
102
|
)
|
plotnine/themes/theme_xkcd.py
CHANGED
|
@@ -50,7 +50,6 @@ class theme_xkcd(theme_gray):
|
|
|
50
50
|
legend_background=element_rect(color="black"),
|
|
51
51
|
legend_box_margin=2,
|
|
52
52
|
legend_margin=5,
|
|
53
|
-
legend_key=element_rect(fill="none"),
|
|
54
53
|
panel_border=element_rect(color="black", size=1),
|
|
55
54
|
panel_grid=element_blank(),
|
|
56
55
|
panel_background=element_rect(fill="white"),
|
plotnine/themes/themeable.py
CHANGED
|
@@ -17,7 +17,7 @@ from warnings import warn
|
|
|
17
17
|
|
|
18
18
|
import numpy as np
|
|
19
19
|
|
|
20
|
-
from .._utils import to_rgba
|
|
20
|
+
from .._utils import has_alpha_channel, to_rgba
|
|
21
21
|
from .._utils.registry import RegistryHierarchyMeta
|
|
22
22
|
from ..exceptions import PlotnineError, deprecated_themeable_name
|
|
23
23
|
from .elements import element_blank
|
|
@@ -377,6 +377,36 @@ class Themeables(dict[str, themeable]):
|
|
|
377
377
|
|
|
378
378
|
return default
|
|
379
379
|
|
|
380
|
+
def get_ha(self, name: str) -> float:
|
|
381
|
+
"""
|
|
382
|
+
Get the horizontal alignement of themeable as a float
|
|
383
|
+
|
|
384
|
+
The themeable should be and element_text
|
|
385
|
+
"""
|
|
386
|
+
lookup = {"left": 0.0, "center": 0.5, "right": 1.0}
|
|
387
|
+
ha: str | float = self.getp((name, "ha"), "center")
|
|
388
|
+
if isinstance(ha, str):
|
|
389
|
+
ha = lookup[ha]
|
|
390
|
+
return ha
|
|
391
|
+
|
|
392
|
+
def get_va(self, name) -> float:
|
|
393
|
+
"""
|
|
394
|
+
Get the vertical alignement of themeable as a float
|
|
395
|
+
|
|
396
|
+
The themeable should be and element_text
|
|
397
|
+
"""
|
|
398
|
+
lookup = {
|
|
399
|
+
"bottom": 0.0,
|
|
400
|
+
"center": 0.5,
|
|
401
|
+
"baseline": 0.5,
|
|
402
|
+
"center_baseline": 0.5,
|
|
403
|
+
"top": 1.0,
|
|
404
|
+
}
|
|
405
|
+
va: str | float = self.getp((name, "va"), "center")
|
|
406
|
+
if isinstance(va, str):
|
|
407
|
+
va = lookup[va]
|
|
408
|
+
return va
|
|
409
|
+
|
|
380
410
|
def property(self, name: str, key: str = "value") -> Any:
|
|
381
411
|
"""
|
|
382
412
|
Get the value a specific themeable(s) property
|
|
@@ -474,6 +504,25 @@ class MixinSequenceOfValues(themeable):
|
|
|
474
504
|
a.set(**{name: value})
|
|
475
505
|
|
|
476
506
|
|
|
507
|
+
def blend_alpha(
|
|
508
|
+
properties: dict[str, Any], key: str = "color"
|
|
509
|
+
) -> dict[str, Any]:
|
|
510
|
+
"""
|
|
511
|
+
Blend color with alpha
|
|
512
|
+
|
|
513
|
+
When setting color property values of matplotlib objects,
|
|
514
|
+
for a color with an alpha channel, we don't want the alpha
|
|
515
|
+
property if any to have any effect on that color.
|
|
516
|
+
"""
|
|
517
|
+
if (color := properties.get(key)) is not None:
|
|
518
|
+
if "alpha" in properties:
|
|
519
|
+
properties[key] = to_rgba(color, properties["alpha"])
|
|
520
|
+
properties["alpha"] = None
|
|
521
|
+
elif has_alpha_channel(color):
|
|
522
|
+
properties["alpha"] = None
|
|
523
|
+
return properties
|
|
524
|
+
|
|
525
|
+
|
|
477
526
|
# element_text themeables
|
|
478
527
|
|
|
479
528
|
|
|
@@ -729,18 +778,29 @@ class plot_tag(themeable):
|
|
|
729
778
|
|
|
730
779
|
Notes
|
|
731
780
|
-----
|
|
732
|
-
The `ha` & `va` of element_text
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
781
|
+
The `ha` & `va` of element_text have no effect in some cases. e.g.
|
|
782
|
+
if [](:class:`~plotnine.themes.themeable.plot_tag_position`) is "margin"
|
|
783
|
+
and the tag is at the top it cannot be vertically aligned.
|
|
784
|
+
|
|
785
|
+
Also `ha` & `va` can be floats if it makes sense to justify the tag
|
|
786
|
+
over a span. e.g. along the panel or plot, or when aligning with
|
|
787
|
+
other tags in a composition.
|
|
736
788
|
"""
|
|
737
789
|
|
|
738
790
|
_omit = ["margin"]
|
|
739
791
|
|
|
740
792
|
def apply_figure(self, figure: Figure, targets: ThemeTargets):
|
|
741
793
|
super().apply_figure(figure, targets)
|
|
794
|
+
props = self.properties
|
|
795
|
+
|
|
796
|
+
if "va" in props and not isinstance(props["va"], str):
|
|
797
|
+
del props["va"]
|
|
798
|
+
|
|
799
|
+
if "ha" in props and not isinstance(props["ha"], str):
|
|
800
|
+
del props["ha"]
|
|
801
|
+
|
|
742
802
|
if text := targets.plot_tag:
|
|
743
|
-
text.set(**
|
|
803
|
+
text.set(**props)
|
|
744
804
|
|
|
745
805
|
def blank_figure(self, figure: Figure, targets: ThemeTargets):
|
|
746
806
|
super().blank_figure(figure, targets)
|
|
@@ -811,7 +871,7 @@ class strip_text_x(MixinSequenceOfValues):
|
|
|
811
871
|
theme_element : element_text
|
|
812
872
|
"""
|
|
813
873
|
|
|
814
|
-
_omit = ["margin", "ha"]
|
|
874
|
+
_omit = ["margin", "ha", "va"]
|
|
815
875
|
|
|
816
876
|
def apply_figure(self, figure: Figure, targets: ThemeTargets):
|
|
817
877
|
super().apply_figure(figure, targets)
|
|
@@ -834,7 +894,7 @@ class strip_text_y(MixinSequenceOfValues):
|
|
|
834
894
|
theme_element : element_text
|
|
835
895
|
"""
|
|
836
896
|
|
|
837
|
-
_omit = ["margin", "va"]
|
|
897
|
+
_omit = ["margin", "ha", "va"]
|
|
838
898
|
|
|
839
899
|
def apply_figure(self, figure: Figure, targets: ThemeTargets):
|
|
840
900
|
super().apply_figure(figure, targets)
|
|
@@ -894,13 +954,28 @@ class axis_text_x(MixinSequenceOfValues):
|
|
|
894
954
|
|
|
895
955
|
def apply_ax(self, ax: Axes):
|
|
896
956
|
super().apply_ax(ax)
|
|
897
|
-
|
|
957
|
+
|
|
958
|
+
# TODO: Remove this code when the minimum matplotlib >= 3.10.0,
|
|
959
|
+
# and use the commented one below it
|
|
960
|
+
import matplotlib as mpl
|
|
961
|
+
from packaging import version
|
|
962
|
+
|
|
963
|
+
vinstalled = version.parse(mpl.__version__)
|
|
964
|
+
v310 = version.parse("3.10.0")
|
|
965
|
+
name = "labelbottom" if vinstalled >= v310 else "labelleft"
|
|
966
|
+
if not ax.xaxis.get_tick_params()[name]:
|
|
967
|
+
return
|
|
968
|
+
|
|
969
|
+
# if not ax.xaxis.get_tick_params()["labelbottom"]:
|
|
970
|
+
# return
|
|
971
|
+
|
|
972
|
+
labels = [t.label1 for t in ax.xaxis.get_major_ticks()]
|
|
973
|
+
self.set(labels)
|
|
898
974
|
|
|
899
975
|
def blank_ax(self, ax: Axes):
|
|
900
976
|
super().blank_ax(ax)
|
|
901
|
-
ax.xaxis.
|
|
902
|
-
|
|
903
|
-
)
|
|
977
|
+
for t in ax.xaxis.get_major_ticks():
|
|
978
|
+
t.label1.set_visible(False)
|
|
904
979
|
|
|
905
980
|
|
|
906
981
|
class axis_text_y(MixinSequenceOfValues):
|
|
@@ -927,13 +1002,17 @@ class axis_text_y(MixinSequenceOfValues):
|
|
|
927
1002
|
|
|
928
1003
|
def apply_ax(self, ax: Axes):
|
|
929
1004
|
super().apply_ax(ax)
|
|
930
|
-
|
|
1005
|
+
|
|
1006
|
+
if not ax.yaxis.get_tick_params()["labelleft"]:
|
|
1007
|
+
return
|
|
1008
|
+
|
|
1009
|
+
labels = [t.label1 for t in ax.yaxis.get_major_ticks()]
|
|
1010
|
+
self.set(labels)
|
|
931
1011
|
|
|
932
1012
|
def blank_ax(self, ax: Axes):
|
|
933
1013
|
super().blank_ax(ax)
|
|
934
|
-
ax.yaxis.
|
|
935
|
-
|
|
936
|
-
)
|
|
1014
|
+
for t in ax.yaxis.get_major_ticks():
|
|
1015
|
+
t.label1.set_visible(False)
|
|
937
1016
|
|
|
938
1017
|
|
|
939
1018
|
class axis_text(axis_text_x, axis_text_y):
|
|
@@ -1306,7 +1385,7 @@ class panel_grid_major_x(themeable):
|
|
|
1306
1385
|
|
|
1307
1386
|
def apply_ax(self, ax: Axes):
|
|
1308
1387
|
super().apply_ax(ax)
|
|
1309
|
-
ax.xaxis.grid(which="major", **self.properties)
|
|
1388
|
+
ax.xaxis.grid(which="major", **blend_alpha(self.properties))
|
|
1310
1389
|
|
|
1311
1390
|
def blank_ax(self, ax: Axes):
|
|
1312
1391
|
super().blank_ax(ax)
|
|
@@ -1324,7 +1403,7 @@ class panel_grid_major_y(themeable):
|
|
|
1324
1403
|
|
|
1325
1404
|
def apply_ax(self, ax: Axes):
|
|
1326
1405
|
super().apply_ax(ax)
|
|
1327
|
-
ax.yaxis.grid(which="major", **self.properties)
|
|
1406
|
+
ax.yaxis.grid(which="major", **blend_alpha(self.properties))
|
|
1328
1407
|
|
|
1329
1408
|
def blank_ax(self, ax: Axes):
|
|
1330
1409
|
super().blank_ax(ax)
|
|
@@ -1448,8 +1527,13 @@ class legend_key(MixinSequenceOfValues):
|
|
|
1448
1527
|
def apply_figure(self, figure: Figure, targets: ThemeTargets):
|
|
1449
1528
|
super().apply_figure(figure, targets)
|
|
1450
1529
|
properties = self.properties
|
|
1530
|
+
edgecolor = properties.get("edgecolor", None)
|
|
1531
|
+
|
|
1532
|
+
if isinstance(self, rect) and edgecolor:
|
|
1533
|
+
del properties["edgecolor"]
|
|
1534
|
+
|
|
1451
1535
|
# Prevent invisible strokes from having any effect
|
|
1452
|
-
if
|
|
1536
|
+
if edgecolor in ("none", "None"):
|
|
1453
1537
|
properties["linewidth"] = 0
|
|
1454
1538
|
|
|
1455
1539
|
rects = [da.patch for da in targets.legend_key]
|
|
@@ -1533,7 +1617,7 @@ class legend_box_background(themeable):
|
|
|
1533
1617
|
"""
|
|
1534
1618
|
|
|
1535
1619
|
|
|
1536
|
-
class panel_background(
|
|
1620
|
+
class panel_background(legend_key):
|
|
1537
1621
|
"""
|
|
1538
1622
|
Panel background
|
|
1539
1623
|
|
|
@@ -1542,13 +1626,12 @@ class panel_background(themeable):
|
|
|
1542
1626
|
theme_element : element_rect
|
|
1543
1627
|
"""
|
|
1544
1628
|
|
|
1629
|
+
def apply_figure(self, figure: Figure, targets: ThemeTargets):
|
|
1630
|
+
super().apply_figure(figure, targets)
|
|
1631
|
+
|
|
1545
1632
|
def apply_ax(self, ax: Axes):
|
|
1546
1633
|
super().apply_ax(ax)
|
|
1547
|
-
d = self.properties
|
|
1548
|
-
if "facecolor" in d and "alpha" in d:
|
|
1549
|
-
d["facecolor"] = to_rgba(d["facecolor"], d["alpha"])
|
|
1550
|
-
del d["alpha"]
|
|
1551
|
-
|
|
1634
|
+
d = blend_alpha(self.properties, "facecolor")
|
|
1552
1635
|
d["edgecolor"] = "none"
|
|
1553
1636
|
d["linewidth"] = 0
|
|
1554
1637
|
ax.patch.set(**d)
|
|
@@ -1574,16 +1657,12 @@ class panel_border(MixinSequenceOfValues):
|
|
|
1574
1657
|
if not (rects := targets.panel_border):
|
|
1575
1658
|
return
|
|
1576
1659
|
|
|
1577
|
-
d = self.properties
|
|
1660
|
+
d = blend_alpha(self.properties, "edgecolor")
|
|
1578
1661
|
|
|
1579
1662
|
with suppress(KeyError):
|
|
1580
1663
|
if d["edgecolor"] == "none" or d["size"] == 0:
|
|
1581
1664
|
return
|
|
1582
1665
|
|
|
1583
|
-
if "edgecolor" in d and "alpha" in d:
|
|
1584
|
-
d["edgecolor"] = to_rgba(d["edgecolor"], d["alpha"])
|
|
1585
|
-
del d["alpha"]
|
|
1586
|
-
|
|
1587
1666
|
self.set(rects, d)
|
|
1588
1667
|
|
|
1589
1668
|
def blank_figure(self, figure: Figure, targets: ThemeTargets):
|
|
@@ -1663,7 +1742,6 @@ class strip_background(strip_background_x, strip_background_y):
|
|
|
1663
1742
|
|
|
1664
1743
|
|
|
1665
1744
|
class rect(
|
|
1666
|
-
legend_key,
|
|
1667
1745
|
legend_frame,
|
|
1668
1746
|
legend_background,
|
|
1669
1747
|
panel_background,
|
plotnine/typing.py
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import sys
|
|
4
|
-
from datetime import datetime, timedelta
|
|
5
3
|
from typing import (
|
|
6
|
-
TYPE_CHECKING,
|
|
7
4
|
Any,
|
|
8
5
|
Callable,
|
|
9
6
|
Literal,
|
|
7
|
+
NotRequired,
|
|
10
8
|
Protocol,
|
|
11
9
|
Sequence,
|
|
10
|
+
TypedDict,
|
|
12
11
|
TypeVar,
|
|
13
12
|
)
|
|
14
13
|
|
|
@@ -80,7 +79,7 @@ FacetSpaceRatios: TypeAlias = dict[Literal["x", "y"], Sequence[float]]
|
|
|
80
79
|
|
|
81
80
|
StripPosition: TypeAlias = Literal["top", "right"]
|
|
82
81
|
|
|
83
|
-
|
|
82
|
+
# Scales
|
|
84
83
|
|
|
85
84
|
# Name names of scaled aesthetics
|
|
86
85
|
ScaledAestheticsName: TypeAlias = Literal[
|
|
@@ -110,11 +109,11 @@ ScaledAestheticsName: TypeAlias = Literal[
|
|
|
110
109
|
"upper",
|
|
111
110
|
]
|
|
112
111
|
|
|
113
|
-
|
|
112
|
+
# Coords
|
|
114
113
|
CoordRange: TypeAlias = tuple[float, float]
|
|
115
114
|
|
|
116
115
|
# Guide
|
|
117
|
-
|
|
116
|
+
Side: TypeAlias = Literal["left", "right", "top", "bottom"]
|
|
118
117
|
LegendPosition: TypeAlias = (
|
|
119
118
|
Literal["left", "right", "top", "bottom", "inside"] | tuple[float, float]
|
|
120
119
|
)
|
|
@@ -142,3 +141,15 @@ class PTransform(Protocol):
|
|
|
142
141
|
"""
|
|
143
142
|
|
|
144
143
|
def __call__(self, x: TFloatArrayLike) -> TFloatArrayLike: ...
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class DisplayMetadata(TypedDict):
|
|
147
|
+
"""
|
|
148
|
+
Metadata for the IPython output
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
width: NotRequired[int]
|
|
152
|
+
height: NotRequired[int]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
MimeBundle: TypeAlias = tuple[dict[str, bytes], dict[str, DisplayMetadata]]
|
plotnine/watermark.py
CHANGED
|
@@ -50,12 +50,12 @@ class watermark:
|
|
|
50
50
|
kwargs["zorder"] = 99.9
|
|
51
51
|
self.kwargs = kwargs
|
|
52
52
|
|
|
53
|
-
def __radd__(self,
|
|
53
|
+
def __radd__(self, other: p9.ggplot) -> p9.ggplot:
|
|
54
54
|
"""
|
|
55
55
|
Add watermark to ggplot object
|
|
56
56
|
"""
|
|
57
|
-
|
|
58
|
-
return
|
|
57
|
+
other.watermarks.append(self)
|
|
58
|
+
return other
|
|
59
59
|
|
|
60
60
|
def draw(self, figure: matplotlib.figure.Figure):
|
|
61
61
|
"""
|