plotnine 0.15.3__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.
Files changed (60) hide show
  1. plotnine/_mpl/gridspec.py +50 -6
  2. plotnine/_mpl/layout_manager/__init__.py +2 -5
  3. plotnine/_mpl/layout_manager/_composition_layout_items.py +98 -0
  4. plotnine/_mpl/layout_manager/_composition_side_space.py +461 -0
  5. plotnine/_mpl/layout_manager/_engine.py +19 -58
  6. plotnine/_mpl/layout_manager/_grid.py +94 -0
  7. plotnine/_mpl/layout_manager/_layout_tree.py +402 -817
  8. plotnine/_mpl/layout_manager/{_layout_items.py → _plot_layout_items.py} +55 -278
  9. plotnine/_mpl/layout_manager/{_spaces.py → _plot_side_space.py} +111 -291
  10. plotnine/_mpl/layout_manager/_side_space.py +176 -0
  11. plotnine/_mpl/utils.py +259 -1
  12. plotnine/_utils/__init__.py +23 -3
  13. plotnine/_utils/context.py +9 -13
  14. plotnine/_utils/dataclasses.py +24 -0
  15. plotnine/animation.py +13 -12
  16. plotnine/composition/__init__.py +6 -0
  17. plotnine/composition/_beside.py +13 -11
  18. plotnine/composition/_compose.py +263 -99
  19. plotnine/composition/_plot_annotation.py +75 -0
  20. plotnine/composition/_plot_layout.py +143 -0
  21. plotnine/composition/_plot_spacer.py +1 -1
  22. plotnine/composition/_stack.py +13 -11
  23. plotnine/composition/_types.py +28 -0
  24. plotnine/composition/_wrap.py +60 -0
  25. plotnine/facets/facet.py +9 -12
  26. plotnine/facets/facet_grid.py +2 -2
  27. plotnine/facets/facet_wrap.py +1 -1
  28. plotnine/geoms/geom.py +2 -2
  29. plotnine/geoms/geom_map.py +4 -5
  30. plotnine/geoms/geom_path.py +8 -7
  31. plotnine/geoms/geom_rug.py +6 -10
  32. plotnine/geoms/geom_text.py +5 -5
  33. plotnine/ggplot.py +63 -9
  34. plotnine/guides/guide.py +24 -6
  35. plotnine/guides/guide_colorbar.py +88 -46
  36. plotnine/guides/guide_legend.py +47 -20
  37. plotnine/guides/guides.py +2 -2
  38. plotnine/iapi.py +17 -1
  39. plotnine/scales/scale.py +1 -1
  40. plotnine/stats/binning.py +15 -43
  41. plotnine/stats/smoothers.py +7 -3
  42. plotnine/stats/stat.py +2 -2
  43. plotnine/stats/stat_density_2d.py +10 -6
  44. plotnine/stats/stat_pointdensity.py +8 -1
  45. plotnine/stats/stat_qq.py +5 -5
  46. plotnine/stats/stat_qq_line.py +6 -1
  47. plotnine/stats/stat_sina.py +19 -20
  48. plotnine/stats/stat_summary.py +4 -2
  49. plotnine/stats/stat_summary_bin.py +7 -1
  50. plotnine/themes/elements/element_line.py +2 -0
  51. plotnine/themes/elements/element_text.py +12 -1
  52. plotnine/themes/theme.py +18 -24
  53. plotnine/themes/themeable.py +17 -3
  54. plotnine/typing.py +6 -1
  55. {plotnine-0.15.3.dist-info → plotnine-0.16.0a1.dist-info}/METADATA +3 -3
  56. {plotnine-0.15.3.dist-info → plotnine-0.16.0a1.dist-info}/RECORD +59 -51
  57. {plotnine-0.15.3.dist-info → plotnine-0.16.0a1.dist-info}/WHEEL +1 -1
  58. plotnine/composition/_plotspec.py +0 -50
  59. {plotnine-0.15.3.dist-info → plotnine-0.16.0a1.dist-info}/licenses/LICENSE +0 -0
  60. {plotnine-0.15.3.dist-info → plotnine-0.16.0a1.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING
4
- from warnings import warn
5
4
 
6
5
  from matplotlib.layout_engine import LayoutEngine
7
6
 
8
- from ...exceptions import PlotnineWarning
9
- from ._layout_tree import LayoutTree
10
- from ._spaces import LayoutSpaces
7
+ from ._composition_side_space import CompositionSideSpaces
8
+ from ._plot_side_space import PlotSideSpaces
11
9
 
12
10
  if TYPE_CHECKING:
13
11
  from matplotlib.figure import Figure
@@ -18,70 +16,33 @@ if TYPE_CHECKING:
18
16
 
19
17
  class PlotnineLayoutEngine(LayoutEngine):
20
18
  """
21
- Implement geometry management for plotnine plots
22
-
23
- This layout manager automatically adjusts the location of
24
- objects placed around the plot panels and the subplot
25
- spacing parameters so that the plot fits cleanly within
26
- the figure area.
19
+ Geometry management for plotnine plots
20
+
21
+ It works for both singular plots (ggplot) and compositions (Compose).
22
+ For plots, it adjusts the position of objects around the panels and/or
23
+ resizes the plot to the desired aspect-ratio. For compositions, it
24
+ adjusts the position of objects (the annotations of the top-level
25
+ composition) around the plots, and also the artists around the panels
26
+ in all the contained plots.
27
27
  """
28
28
 
29
29
  _adjust_compatible = True
30
30
  _colorbar_gridspec = False
31
31
 
32
- def __init__(self, plot: ggplot):
33
- self.plot = plot
34
- self.theme = plot.theme
32
+ def __init__(self, item: ggplot | Compose):
33
+ self.item = item
35
34
 
36
35
  def execute(self, fig: Figure):
37
36
  from contextlib import nullcontext
38
37
 
39
- renderer = fig._get_renderer() # pyright: ignore[reportAttributeAccessIssue]
40
-
41
- with getattr(renderer, "_draw_disabled", nullcontext)():
42
- spaces = LayoutSpaces(self.plot)
43
-
44
- gsparams = spaces.get_gridspec_params()
45
- self.plot.facet._panels_gridspec.layout(gsparams)
46
- spaces.items._adjust_positions(spaces)
47
-
48
-
49
- class PlotnineCompositionLayoutEngine(LayoutEngine):
50
- """
51
- Layout Manager for Plotnine Composition
52
- """
53
-
54
- _adjust_compatible = True
55
- _colorbar_gridspec = False
56
-
57
- def __init__(self, composition: Compose):
58
- self.composition = composition
59
-
60
- def execute(self, fig: Figure):
61
- from contextlib import nullcontext
38
+ from plotnine import ggplot
62
39
 
40
+ item = self.item
63
41
  renderer = fig._get_renderer() # pyright: ignore[reportAttributeAccessIssue]
64
42
 
65
- # Caculate the space taken up by all plot artists
66
- lookup_spaces: dict[ggplot, LayoutSpaces] = {}
67
43
  with getattr(renderer, "_draw_disabled", nullcontext)():
68
- for ps in self.composition.plotspecs:
69
- lookup_spaces[ps.plot] = LayoutSpaces(ps.plot)
70
-
71
- # Adjust the size and placements of the plots
72
- tree = LayoutTree.create(self.composition, lookup_spaces)
73
- tree.harmonise()
74
-
75
- # Set the final positions of the artists in each plot
76
- for plot, spaces in lookup_spaces.items():
77
- gsparams = spaces.get_gridspec_params()
78
- if not gsparams.valid:
79
- warn(
80
- "The layout manager failed, the figure size is too small "
81
- "to contain all the plots. Use theme() increase the "
82
- "figure size and/or reduce the size of the texts.",
83
- PlotnineWarning,
84
- )
85
- break
86
- plot.facet._panels_gridspec.layout(gsparams)
87
- spaces.items._adjust_positions(spaces)
44
+ if isinstance(item, ggplot):
45
+ item._sidespaces = PlotSideSpaces(item)
46
+ else:
47
+ item._sidespaces = CompositionSideSpaces(item)
48
+ item._sidespaces.arrange()
@@ -0,0 +1,94 @@
1
+ from collections.abc import Iterator
2
+ from dataclasses import InitVar, dataclass
3
+ from typing import (
4
+ Generic,
5
+ Literal,
6
+ Sequence,
7
+ TypeVar,
8
+ overload,
9
+ )
10
+
11
+ import numpy as np
12
+
13
+ T = TypeVar("T")
14
+
15
+
16
+ @dataclass
17
+ class Grid(Generic[T]):
18
+ nrow: InitVar[int]
19
+ ncol: InitVar[int]
20
+ items: InitVar[Sequence[T]]
21
+ order: InitVar[Literal["row_major", "col_major"]] = "row_major"
22
+ """
23
+ Put items into the grid left->right, top->bottom starting at `start`.
24
+ Unfilled cells remain None. Returns the number of items written.
25
+ """
26
+
27
+ def __post_init__(
28
+ self,
29
+ nrow: int,
30
+ ncol: int,
31
+ items: Sequence[T],
32
+ order: Literal["row_major", "col_major"],
33
+ ):
34
+ self._grid = np.empty((nrow, ncol), dtype=object)
35
+
36
+ r, c = 0, 0
37
+ if order == "row_major":
38
+ for item in items:
39
+ self[r, c] = item
40
+ c += 1
41
+ if c >= ncol:
42
+ r, c = r + 1, 0
43
+ else:
44
+ for item in items:
45
+ self[r, c] = item
46
+ r += 1
47
+ if r >= nrow:
48
+ r, c = 0, c + 1
49
+
50
+ @overload
51
+ def __getitem__(self, index: tuple[int, int]) -> T | None: ...
52
+
53
+ @overload
54
+ def __getitem__(self, index: tuple[int, slice]) -> list[T | None]: ...
55
+
56
+ @overload
57
+ def __getitem__(self, index: tuple[slice, int]) -> list[T | None]: ...
58
+
59
+ @overload
60
+ def __getitem__(
61
+ self,
62
+ index: tuple[slice, slice],
63
+ ) -> list[list[T | None]]: ...
64
+
65
+ def __getitem__(
66
+ self, index: tuple[int | slice, int | slice]
67
+ ) -> T | None | list[T | None] | list[list[T | None]]:
68
+ """
69
+ Access grid items with 2D indexing:
70
+ """
71
+ return self._grid[index] # pyright: ignore[reportReturnType]
72
+
73
+ def __setitem__(
74
+ self,
75
+ index: tuple[int | slice, slice | int],
76
+ value: T | None | list[T | None] | list[list[T | None]],
77
+ ) -> None:
78
+ self._grid[index] = value
79
+
80
+ def iter_rows(self) -> Iterator[list[T | None]]:
81
+ """
82
+ Row by row
83
+ """
84
+ n = self._grid.shape[0]
85
+ for row in range(n):
86
+ yield self[row, :]
87
+
88
+ def iter_cols(self) -> Iterator[list[T | None]]:
89
+ """
90
+ Column by column
91
+ """
92
+ n = self._grid.shape[1]
93
+ for col in range(n):
94
+ yield self[:, col]