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/_utils/context.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from dataclasses import dataclass
|
|
3
4
|
from typing import TYPE_CHECKING
|
|
4
5
|
|
|
5
6
|
import pandas as pd
|
|
@@ -8,17 +9,40 @@ if TYPE_CHECKING:
|
|
|
8
9
|
from typing_extensions import Self
|
|
9
10
|
|
|
10
11
|
from plotnine import ggplot
|
|
12
|
+
from plotnine.composition import Compose
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def reopen(fig):
|
|
16
|
+
"""
|
|
17
|
+
Reopen an MPL figure that has been closed with plt.close
|
|
18
|
+
|
|
19
|
+
When drawing compositions, plot_composition_context will nest
|
|
20
|
+
plot_context. In this case, plot_context may close an MPL figure
|
|
21
|
+
that belongs to composition. A closed figure cannot be shown with
|
|
22
|
+
plt.show, so for compositions compose.show (if called) will do nothing.
|
|
23
|
+
"""
|
|
24
|
+
from matplotlib._pylab_helpers import Gcf
|
|
25
|
+
|
|
26
|
+
Gcf.set_active(fig.canvas.manager)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def is_closed(fig) -> bool:
|
|
30
|
+
"""
|
|
31
|
+
Return True if figure is closed
|
|
32
|
+
"""
|
|
33
|
+
import matplotlib.pyplot as plt
|
|
34
|
+
|
|
35
|
+
return not plt.fignum_exists(fig.number)
|
|
11
36
|
|
|
12
37
|
|
|
13
38
|
class plot_context:
|
|
14
39
|
"""
|
|
15
|
-
Context
|
|
40
|
+
Context within which the plot is built
|
|
16
41
|
|
|
17
42
|
Parameters
|
|
18
43
|
----------
|
|
19
44
|
plot :
|
|
20
45
|
ggplot object to be built within the context.
|
|
21
|
-
exits.
|
|
22
46
|
show :
|
|
23
47
|
Whether to show the plot.
|
|
24
48
|
"""
|
|
@@ -66,3 +90,55 @@ class plot_context:
|
|
|
66
90
|
|
|
67
91
|
self.rc_context.__exit__(exc_type, exc_value, exc_traceback)
|
|
68
92
|
self.pd_option_context.__exit__(exc_type, exc_value, exc_traceback)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class plot_composition_context:
|
|
97
|
+
"""
|
|
98
|
+
Context within which a plot composition is built
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
cmp :
|
|
103
|
+
composition object to be built within the context.
|
|
104
|
+
show :
|
|
105
|
+
Whether to show the plot.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
cmp: Compose
|
|
109
|
+
show: bool
|
|
110
|
+
|
|
111
|
+
def __post_init__(self):
|
|
112
|
+
import matplotlib as mpl
|
|
113
|
+
|
|
114
|
+
# The dpi is needed when the figure is created, either as
|
|
115
|
+
# a parameter to plt.figure() or an rcParam.
|
|
116
|
+
# https://github.com/matplotlib/matplotlib/issues/24644
|
|
117
|
+
# When drawing the Composition, the dpi themeable is infective
|
|
118
|
+
# because it sets the rcParam after this figure is created.
|
|
119
|
+
rcParams = {"figure.dpi": self.cmp.last_plot.theme.getp("dpi")}
|
|
120
|
+
self._rc_context = mpl.rc_context(rcParams)
|
|
121
|
+
|
|
122
|
+
def __enter__(self) -> Self:
|
|
123
|
+
"""
|
|
124
|
+
Enclose in matplolib & pandas environments
|
|
125
|
+
"""
|
|
126
|
+
self._rc_context.__enter__()
|
|
127
|
+
return self
|
|
128
|
+
|
|
129
|
+
def __exit__(self, exc_type, exc_value, exc_traceback):
|
|
130
|
+
import matplotlib.pyplot as plt
|
|
131
|
+
|
|
132
|
+
if exc_type is None:
|
|
133
|
+
if self.show:
|
|
134
|
+
if is_closed(self.cmp.figure):
|
|
135
|
+
reopen(self.cmp.figure)
|
|
136
|
+
plt.show()
|
|
137
|
+
else:
|
|
138
|
+
plt.close(self.cmp.figure)
|
|
139
|
+
else:
|
|
140
|
+
# There is an exception, close any figure
|
|
141
|
+
if hasattr(self.cmp, "figure"):
|
|
142
|
+
plt.close(self.cmp.figure)
|
|
143
|
+
|
|
144
|
+
self._rc_context.__exit__(exc_type, exc_value, exc_traceback)
|
plotnine/_utils/ipython.py
CHANGED
|
@@ -3,32 +3,24 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
|
-
from typing import Callable, Literal, TypeAlias
|
|
7
|
-
|
|
8
6
|
from IPython.core.interactiveshell import InteractiveShell
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
"png", "retina", "jpeg", "jpg", "svg", "pdf"
|
|
12
|
-
]
|
|
8
|
+
from ..typing import DisplayMetadata, FigureFormat, MimeBundle
|
|
13
9
|
|
|
14
10
|
|
|
15
|
-
def get_ipython() -> "InteractiveShell":
|
|
11
|
+
def get_ipython() -> "None | InteractiveShell":
|
|
16
12
|
"""
|
|
17
13
|
Return running IPython instance or None
|
|
18
14
|
"""
|
|
19
15
|
try:
|
|
20
16
|
from IPython.core.getipython import get_ipython as _get_ipython
|
|
21
|
-
except ImportError
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
ip = _get_ipython()
|
|
25
|
-
if ip is None:
|
|
26
|
-
raise RuntimeError("Not running in a juptyer session.")
|
|
17
|
+
except ImportError:
|
|
18
|
+
return None
|
|
27
19
|
|
|
28
|
-
return
|
|
20
|
+
return _get_ipython()
|
|
29
21
|
|
|
30
22
|
|
|
31
|
-
def is_inline_backend():
|
|
23
|
+
def is_inline_backend() -> bool:
|
|
32
24
|
"""
|
|
33
25
|
Return True if the inline_backend is on
|
|
34
26
|
|
|
@@ -36,47 +28,39 @@ def is_inline_backend():
|
|
|
36
28
|
"""
|
|
37
29
|
import matplotlib as mpl
|
|
38
30
|
|
|
39
|
-
|
|
31
|
+
backend = mpl.get_backend()
|
|
32
|
+
return backend in ("inline", "module://matplotlib_inline.backend_inline")
|
|
40
33
|
|
|
41
34
|
|
|
42
|
-
def
|
|
43
|
-
format: FigureFormat, figure_size_px: tuple[int, int]
|
|
44
|
-
) ->
|
|
35
|
+
def get_mimebundle(
|
|
36
|
+
b: bytes, format: FigureFormat, figure_size_px: tuple[int, int]
|
|
37
|
+
) -> MimeBundle:
|
|
45
38
|
"""
|
|
46
|
-
Return a
|
|
39
|
+
Return a the display MIME bundle from image data
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
format :
|
|
44
|
+
The figure format
|
|
45
|
+
figure_size_px :
|
|
46
|
+
The figure size in pixels (width, height)
|
|
47
47
|
"""
|
|
48
|
-
from IPython.display import (
|
|
49
|
-
SVG,
|
|
50
|
-
Image,
|
|
51
|
-
display_jpeg,
|
|
52
|
-
display_pdf,
|
|
53
|
-
display_png,
|
|
54
|
-
display_svg,
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
w, h = figure_size_px
|
|
58
|
-
|
|
59
|
-
def png(b: bytes):
|
|
60
|
-
display_png(Image(b, format="png", width=w, height=h))
|
|
61
|
-
|
|
62
|
-
def retina(b: bytes):
|
|
63
|
-
display_png(Image(b, format="png", retina=True))
|
|
64
|
-
|
|
65
|
-
def jpeg(b: bytes):
|
|
66
|
-
display_jpeg(Image(b, format="jpeg", width=w, height=h))
|
|
67
|
-
|
|
68
|
-
def svg(b: bytes):
|
|
69
|
-
display_svg(SVG(b))
|
|
70
|
-
|
|
71
|
-
def pdf(b: bytes):
|
|
72
|
-
display_pdf(b, raw=True)
|
|
73
48
|
|
|
74
49
|
lookup = {
|
|
75
|
-
"png": png,
|
|
76
|
-
"retina":
|
|
77
|
-
"jpeg": jpeg,
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"pdf": pdf,
|
|
50
|
+
"png": "image/png",
|
|
51
|
+
"retina": "image/png",
|
|
52
|
+
"jpeg": "image/jpeg",
|
|
53
|
+
"svg": "image/svg+xml",
|
|
54
|
+
"pdf": "application/pdf",
|
|
81
55
|
}
|
|
82
|
-
|
|
56
|
+
mimetype = lookup[format]
|
|
57
|
+
|
|
58
|
+
metadata: dict[str, DisplayMetadata] = {}
|
|
59
|
+
w, h = figure_size_px
|
|
60
|
+
if format in ("png", "jpeg"):
|
|
61
|
+
metadata = {mimetype: {"width": w, "height": h}}
|
|
62
|
+
elif format == "retina":
|
|
63
|
+
# `retina=True` in IPython.display.Image just halves width/height
|
|
64
|
+
metadata = {mimetype: {"width": w // 2, "height": h // 2}}
|
|
65
|
+
|
|
66
|
+
return {mimetype: b}, metadata
|
plotnine/_utils/quarto.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import sys
|
|
3
|
+
from functools import lru_cache
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
def is_quarto_environment() -> bool:
|
|
@@ -31,3 +33,27 @@ def set_options_from_quarto():
|
|
|
31
33
|
set_option("dpi", dpi)
|
|
32
34
|
set_option("figure_size", figure_size)
|
|
33
35
|
set_option("figure_format", figure_format)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# We do not expect the contents the file stored in the QUARTO_EXECUTE_INFO
|
|
39
|
+
# variable to change. We can can cache the output
|
|
40
|
+
@lru_cache()
|
|
41
|
+
def is_knitr_engine() -> bool:
|
|
42
|
+
"""
|
|
43
|
+
Return True if knitr is executing the code
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
if filename := os.environ.get("QUARTO_EXECUTE_INFO"): # Quarto >= 1.8.21
|
|
47
|
+
import json
|
|
48
|
+
from pathlib import Path
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
info = json.loads(Path(filename).read_text())
|
|
52
|
+
except FileNotFoundError:
|
|
53
|
+
# NOTE: Remove this branch some time after quarto 1.9 is released
|
|
54
|
+
# https://github.com/quarto-dev/quarto-cli/issues/13613
|
|
55
|
+
return "rpytools" in sys.modules
|
|
56
|
+
return info["format"]["execute"].get("engine") == "knitr"
|
|
57
|
+
else:
|
|
58
|
+
# NOTE: Remove this branch some time after quarto 1.9 is released
|
|
59
|
+
return "rpytools" in sys.modules
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Functions/class to quickly create plots for development and testing
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from plotnine import (
|
|
8
|
+
aes,
|
|
9
|
+
element_blank,
|
|
10
|
+
element_rect,
|
|
11
|
+
element_text,
|
|
12
|
+
geom_col,
|
|
13
|
+
geom_point,
|
|
14
|
+
ggplot,
|
|
15
|
+
labs,
|
|
16
|
+
theme,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = ("geom", "legend", "plot", "rotate", "tag")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class _Plot:
|
|
23
|
+
"""
|
|
24
|
+
Create a plot
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __getattr__(self, color: str):
|
|
28
|
+
"""
|
|
29
|
+
Create a blank plot with given background color
|
|
30
|
+
"""
|
|
31
|
+
return (
|
|
32
|
+
ggplot()
|
|
33
|
+
+ labs(
|
|
34
|
+
x="x-axis",
|
|
35
|
+
y="y-axis",
|
|
36
|
+
title=color.title(),
|
|
37
|
+
)
|
|
38
|
+
+ theme(
|
|
39
|
+
figure_size=(8, 6),
|
|
40
|
+
text=element_text(color="black", size=11),
|
|
41
|
+
panel_background=element_rect(fill=color, size=1),
|
|
42
|
+
plot_background=element_rect(fill=color, alpha=0.2),
|
|
43
|
+
panel_border=element_rect(color="black"),
|
|
44
|
+
strip_background=element_rect(color="black"),
|
|
45
|
+
panel_grid=element_blank(),
|
|
46
|
+
legend_key_size=12,
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class _Geom:
|
|
52
|
+
"""
|
|
53
|
+
Create some simple geoms
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
data = pd.DataFrame(
|
|
57
|
+
{
|
|
58
|
+
"cat": ["a", "b", "c", "d"],
|
|
59
|
+
"cat2": ["r", "r", "s", "s"],
|
|
60
|
+
"value": [1, 2, 3, 4],
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def points(self):
|
|
66
|
+
return geom_point(aes("cat", "value", color="cat"), self.data, size=2)
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def cols(self):
|
|
70
|
+
return geom_col(aes("cat", "value", fill="cat"), self.data)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class _Legend:
|
|
74
|
+
"""
|
|
75
|
+
Position Legends
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def left(self):
|
|
80
|
+
return theme(legend_position="left")
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def bottom(self):
|
|
84
|
+
return theme(legend_position="bottom")
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def right(self):
|
|
88
|
+
return theme(legend_position="right")
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def top(self):
|
|
92
|
+
return theme(legend_position="top")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class _Rotate:
|
|
96
|
+
"""
|
|
97
|
+
Rotate a text themeable
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
def __getattr__(self, name):
|
|
101
|
+
angle = 0 if name[-2:] == "_y" else 90
|
|
102
|
+
return theme(**{name: element_text(angle=angle)}) # pyright: ignore[reportArgumentType]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def tag(s, position="topleft"):
|
|
106
|
+
"""
|
|
107
|
+
Create a tag at a position
|
|
108
|
+
"""
|
|
109
|
+
return [labs(tag=s), theme(plot_tag_position=position)]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
plot = _Plot()
|
|
113
|
+
geom = _Geom()
|
|
114
|
+
legend = _Legend()
|
|
115
|
+
rotate = _Rotate()
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from ._compose import Compose
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from plotnine.ggplot import ggplot
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(repr=False)
|
|
13
|
+
class Beside(Compose):
|
|
14
|
+
"""
|
|
15
|
+
Place plots or compositions side by side
|
|
16
|
+
|
|
17
|
+
**Usage**
|
|
18
|
+
|
|
19
|
+
plot | plot
|
|
20
|
+
plot | composition
|
|
21
|
+
composition | plot
|
|
22
|
+
composition | composition
|
|
23
|
+
|
|
24
|
+
Typically, you will use this class through the `|` operator.
|
|
25
|
+
|
|
26
|
+
See Also
|
|
27
|
+
--------
|
|
28
|
+
plotnine.composition.Stack : To arrange plots vertically
|
|
29
|
+
plotnine.composition.plot_spacer : To add a blank space between plots
|
|
30
|
+
plotnine.composition.Compose : For more on composing plots
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def nrow(self) -> int:
|
|
35
|
+
return 1
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def ncol(self) -> int:
|
|
39
|
+
return len(self)
|
|
40
|
+
|
|
41
|
+
def __or__(self, rhs: ggplot | Compose) -> Compose:
|
|
42
|
+
"""
|
|
43
|
+
Add rhs as a column
|
|
44
|
+
"""
|
|
45
|
+
# This is adjacent or i.e. (OR | rhs) so we collapse the
|
|
46
|
+
# operands into a single operation
|
|
47
|
+
return Beside([*self, rhs])
|
|
48
|
+
|
|
49
|
+
def __truediv__(self, rhs: ggplot | Compose) -> Compose:
|
|
50
|
+
"""
|
|
51
|
+
Add rhs as a row
|
|
52
|
+
"""
|
|
53
|
+
from ._stack import Stack
|
|
54
|
+
|
|
55
|
+
return Stack([self, rhs])
|