ggh4x-python 0.3.1.9000__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.
- ggh4x/__init__.py +140 -0
- ggh4x/_aimed_text_grob.py +432 -0
- ggh4x/_borrowed_ggplot2.py +273 -0
- ggh4x/_cli.py +84 -0
- ggh4x/_datasets.py +106 -0
- ggh4x/_download.py +111 -0
- ggh4x/_facet_helpers.py +313 -0
- ggh4x/_facet_utils.py +649 -0
- ggh4x/_gap_grobs.py +606 -0
- ggh4x/_registry.py +10 -0
- ggh4x/_rlang.py +93 -0
- ggh4x/_utils.py +150 -0
- ggh4x/_vctrs.py +233 -0
- ggh4x/conveniences.py +601 -0
- ggh4x/coord_axes_inside.py +380 -0
- ggh4x/element_part_rect.py +545 -0
- ggh4x/facet_grid2.py +1018 -0
- ggh4x/facet_manual.py +901 -0
- ggh4x/facet_nested.py +776 -0
- ggh4x/facet_nested_wrap.py +193 -0
- ggh4x/facet_wrap2.py +896 -0
- ggh4x/geom_box.py +536 -0
- ggh4x/geom_outline_point.py +444 -0
- ggh4x/geom_pointpath.py +259 -0
- ggh4x/geom_polygonraster.py +252 -0
- ggh4x/geom_rectrug.py +489 -0
- ggh4x/geom_text_aimed.py +279 -0
- ggh4x/guide_stringlegend.py +354 -0
- ggh4x/help_secondary.py +549 -0
- ggh4x/multiscale/__init__.py +51 -0
- ggh4x/multiscale/_multiscale_add.py +207 -0
- ggh4x/multiscale/scale_listed.py +167 -0
- ggh4x/multiscale/scale_manual.py +478 -0
- ggh4x/multiscale/scale_multi.py +393 -0
- ggh4x/panel_scales/__init__.py +58 -0
- ggh4x/panel_scales/at_panel.py +115 -0
- ggh4x/panel_scales/facetted_pos_scales.py +647 -0
- ggh4x/panel_scales/force_panelsize.py +411 -0
- ggh4x/panel_scales/scale_facet.py +222 -0
- ggh4x/position_disjoint_ranges.py +229 -0
- ggh4x/position_lineartrans.py +242 -0
- ggh4x/py.typed +0 -0
- ggh4x/resources/faithful.csv +273 -0
- ggh4x/resources/iris.csv +151 -0
- ggh4x/resources/mtcars.csv +33 -0
- ggh4x/resources/pressure.csv +20 -0
- ggh4x/resources/volcano.csv +87 -0
- ggh4x/save.py +255 -0
- ggh4x/stat_difference.py +388 -0
- ggh4x/stat_funxy.py +436 -0
- ggh4x/stat_rle.py +290 -0
- ggh4x/stat_rollingkernel.py +369 -0
- ggh4x/stat_theodensity.py +681 -0
- ggh4x/strip_nested.py +448 -0
- ggh4x/strip_split.py +687 -0
- ggh4x/strip_tag.py +636 -0
- ggh4x/strip_themed.py +232 -0
- ggh4x/strip_vanilla.py +1464 -0
- ggh4x/themes.py +31 -0
- ggh4x/themes_ggh4x.py +67 -0
- ggh4x_python-0.3.1.9000.dist-info/METADATA +40 -0
- ggh4x_python-0.3.1.9000.dist-info/RECORD +64 -0
- ggh4x_python-0.3.1.9000.dist-info/WHEEL +4 -0
- ggh4x_python-0.3.1.9000.dist-info/licenses/LICENSE +3 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
"""Cartesian coordinates with interior axes (port of ggh4x ``coord_axes_inside.R``).
|
|
2
|
+
|
|
3
|
+
This module ports the R ggh4x ``coord_axes_inside()`` constructor, the
|
|
4
|
+
``CoordAxesInside`` ggproto class and the ``replace_vp_coord()`` helper. The
|
|
5
|
+
coordinate system places the plot axes at interior positions (controlled by
|
|
6
|
+
``xintercept``/``yintercept``); otherwise it behaves like
|
|
7
|
+
:func:`ggplot2_py.coord_cartesian` (or :func:`ggplot2_py.coord_fixed` when
|
|
8
|
+
``ratio`` is set).
|
|
9
|
+
|
|
10
|
+
R source: ``ggh4x/R/coord_axes_inside.R``.
|
|
11
|
+
|
|
12
|
+
Notes
|
|
13
|
+
-----
|
|
14
|
+
* The constructor builds two :class:`~ggplot2_py.theme.Theme` objects:
|
|
15
|
+
``outer_axes`` blanks the axis lines/ticks (and, when labels go inside, the
|
|
16
|
+
axis text + tick length) in the panel gutters, while ``inner_axes`` blanks the
|
|
17
|
+
axis text that should *not* be drawn inside the panel.
|
|
18
|
+
* :meth:`CoordAxesInside.render_bg` is the load-bearing override: it renders the
|
|
19
|
+
*inner* axes (with un-blanked content) and re-positions their viewports to the
|
|
20
|
+
interior NPC coordinate of the origin, then composites them into the panel
|
|
21
|
+
background grob. The *outer* (blanked) axes still occupy the gutters via the
|
|
22
|
+
:meth:`render_axis_h` / :meth:`render_axis_v` overrides.
|
|
23
|
+
* :func:`_replace_vp_coord` mirrors R's ``replace_vp_coord``: when a grob carries
|
|
24
|
+
no viewport it is returned unchanged; otherwise the single coordinate
|
|
25
|
+
(``x`` or ``y``) of its viewport is replaced. The axis grobs returned by
|
|
26
|
+
:func:`ggplot2_py._guide_axis.draw_axis` already carry a viewport, so the
|
|
27
|
+
coordinate replacement applies directly (via :func:`grid_py.edit_viewport`,
|
|
28
|
+
since :class:`grid_py.Viewport` coordinates are immutable).
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
from typing import Any, Dict, Optional, Sequence, Union
|
|
34
|
+
|
|
35
|
+
import numpy as np
|
|
36
|
+
import pandas as pd
|
|
37
|
+
|
|
38
|
+
from ggplot2_py import ggproto_parent
|
|
39
|
+
from ggplot2_py.coord import CoordCartesian
|
|
40
|
+
from ggplot2_py.theme import theme
|
|
41
|
+
from ggplot2_py.theme_elements import element_blank
|
|
42
|
+
|
|
43
|
+
from grid_py import Unit, edit_viewport, grob_tree
|
|
44
|
+
|
|
45
|
+
from scales import oob_squish
|
|
46
|
+
|
|
47
|
+
from ggh4x._rlang import arg_match0
|
|
48
|
+
|
|
49
|
+
__all__ = [
|
|
50
|
+
"coord_axes_inside",
|
|
51
|
+
"CoordAxesInside",
|
|
52
|
+
"_replace_vp_coord",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ---------------------------------------------------------------------------
|
|
57
|
+
# Helper
|
|
58
|
+
# ---------------------------------------------------------------------------
|
|
59
|
+
def _replace_vp_coord(grob: Any, param: str = "x", value: Any = None) -> Any:
|
|
60
|
+
"""Replace a single coordinate of a grob's viewport.
|
|
61
|
+
|
|
62
|
+
Port of R ``replace_vp_coord`` (``coord_axes_inside.R:164-170``). When the
|
|
63
|
+
grob carries no viewport (``grob.vp is None``) it is returned unchanged;
|
|
64
|
+
otherwise the ``param`` coordinate (``"x"`` or ``"y"``) of its viewport is
|
|
65
|
+
replaced with *value*.
|
|
66
|
+
|
|
67
|
+
Because :class:`grid_py.Viewport` coordinates are immutable, the replacement
|
|
68
|
+
is performed by :func:`grid_py.edit_viewport`, which returns an edited copy
|
|
69
|
+
of the viewport. The edited viewport is then re-attached to *grob*.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
grob : grid_py.Grob
|
|
74
|
+
A grob, typically an axis grob from
|
|
75
|
+
:func:`ggplot2_py._guide_axis.draw_axis`.
|
|
76
|
+
param : {"x", "y"}, default "x"
|
|
77
|
+
Which viewport coordinate to replace.
|
|
78
|
+
value : grid_py.Unit
|
|
79
|
+
The replacement coordinate (an NPC :class:`~grid_py.Unit`).
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
grid_py.Grob
|
|
84
|
+
*grob* with its viewport's ``param`` coordinate replaced, or *grob*
|
|
85
|
+
unchanged when it carries no viewport.
|
|
86
|
+
"""
|
|
87
|
+
vp = getattr(grob, "vp", None)
|
|
88
|
+
if vp is None:
|
|
89
|
+
return grob
|
|
90
|
+
grob.vp = edit_viewport(vp, **{param: value})
|
|
91
|
+
return grob
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
# CoordAxesInside ggproto class
|
|
96
|
+
# ---------------------------------------------------------------------------
|
|
97
|
+
class CoordAxesInside(CoordCartesian):
|
|
98
|
+
"""Cartesian coordinate system with interior axes.
|
|
99
|
+
|
|
100
|
+
Subclass of :class:`ggplot2_py.coord.CoordCartesian` ported from R
|
|
101
|
+
``CoordAxesInside`` (``coord_axes_inside.R:122-160``).
|
|
102
|
+
|
|
103
|
+
Attributes
|
|
104
|
+
----------
|
|
105
|
+
origin : pandas.DataFrame
|
|
106
|
+
A 1-row frame ``{"x": [xintercept], "y": [yintercept]}`` giving the
|
|
107
|
+
interior position where the axes meet.
|
|
108
|
+
outer_axes : ggplot2_py.theme.Theme
|
|
109
|
+
Theme additions blanking the gutter axis lines/ticks (and text/tick
|
|
110
|
+
length when labels are drawn inside).
|
|
111
|
+
inner_axes : ggplot2_py.theme.Theme
|
|
112
|
+
Theme additions blanking the axis text that should not appear inside the
|
|
113
|
+
panel.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
def render_axis_h(self, panel_params: Dict[str, Any], theme: Any) -> Dict[str, Any]:
|
|
117
|
+
"""Render the horizontal (top/bottom) gutter axes, blanked.
|
|
118
|
+
|
|
119
|
+
Port of R ``CoordAxesInside$render_axis_h``
|
|
120
|
+
(``coord_axes_inside.R:124-126``): delegate to
|
|
121
|
+
``CoordCartesian$render_axis_h`` after adding ``self.outer_axes`` to the
|
|
122
|
+
theme so the gutter axis lines/ticks (and text, if labels are inside)
|
|
123
|
+
are blank.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
panel_params : dict
|
|
128
|
+
Panel parameters from :meth:`setup_panel_params`.
|
|
129
|
+
theme : ggplot2_py.theme.Theme
|
|
130
|
+
The active theme.
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
dict
|
|
135
|
+
``{"top": grob, "bottom": grob}``.
|
|
136
|
+
"""
|
|
137
|
+
return ggproto_parent(CoordCartesian, self).render_axis_h(
|
|
138
|
+
panel_params, theme + self.outer_axes
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def render_axis_v(self, panel_params: Dict[str, Any], theme: Any) -> Dict[str, Any]:
|
|
142
|
+
"""Render the vertical (left/right) gutter axes, blanked.
|
|
143
|
+
|
|
144
|
+
Port of R ``CoordAxesInside$render_axis_v``
|
|
145
|
+
(``coord_axes_inside.R:127-129``): as :meth:`render_axis_h` but for the
|
|
146
|
+
vertical axes.
|
|
147
|
+
|
|
148
|
+
Parameters
|
|
149
|
+
----------
|
|
150
|
+
panel_params : dict
|
|
151
|
+
Panel parameters from :meth:`setup_panel_params`.
|
|
152
|
+
theme : ggplot2_py.theme.Theme
|
|
153
|
+
The active theme.
|
|
154
|
+
|
|
155
|
+
Returns
|
|
156
|
+
-------
|
|
157
|
+
dict
|
|
158
|
+
``{"left": grob, "right": grob}``.
|
|
159
|
+
"""
|
|
160
|
+
return ggproto_parent(CoordCartesian, self).render_axis_v(
|
|
161
|
+
panel_params, theme + self.outer_axes
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def render_bg(self, panel_params: Dict[str, Any], theme: Any) -> Any:
|
|
165
|
+
"""Render the panel background with the interior axes injected.
|
|
166
|
+
|
|
167
|
+
Port of R ``CoordAxesInside$render_bg``
|
|
168
|
+
(``coord_axes_inside.R:130-152``). The *inner* axes are rendered here
|
|
169
|
+
(so their un-blanked content lands inside the panel background) and each
|
|
170
|
+
axis viewport is re-positioned to the interior NPC coordinate of the
|
|
171
|
+
transformed origin. The repositioned axes are composited into the
|
|
172
|
+
background grob with the grid/axis-b/axis-t/axis-l/axis-r names.
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
panel_params : dict
|
|
177
|
+
Panel parameters from :meth:`setup_panel_params`.
|
|
178
|
+
theme : ggplot2_py.theme.Theme
|
|
179
|
+
The active theme.
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
-------
|
|
183
|
+
grid_py.Grob
|
|
184
|
+
A grob tree containing the grid background and the four repositioned
|
|
185
|
+
interior axes.
|
|
186
|
+
"""
|
|
187
|
+
theme = theme + self.inner_axes
|
|
188
|
+
grid_grob = ggproto_parent(CoordCartesian, self).render_bg(panel_params, theme)
|
|
189
|
+
xaxes = ggproto_parent(CoordCartesian, self).render_axis_h(panel_params, theme)
|
|
190
|
+
yaxes = ggproto_parent(CoordCartesian, self).render_axis_v(panel_params, theme)
|
|
191
|
+
|
|
192
|
+
origin = self.transform(self.origin, panel_params)
|
|
193
|
+
|
|
194
|
+
x = Unit(oob_squish(float(origin["x"].iloc[0])), "npc")
|
|
195
|
+
y = Unit(oob_squish(float(origin["y"].iloc[0])), "npc")
|
|
196
|
+
|
|
197
|
+
xaxes["bottom"] = _replace_vp_coord(xaxes["bottom"], "y", y)
|
|
198
|
+
xaxes["top"] = _replace_vp_coord(xaxes["top"], "y", y)
|
|
199
|
+
yaxes["left"] = _replace_vp_coord(yaxes["left"], "x", x)
|
|
200
|
+
yaxes["right"] = _replace_vp_coord(yaxes["right"], "x", x)
|
|
201
|
+
|
|
202
|
+
# R grobTree names each child for later grid-path edits; mirror that by
|
|
203
|
+
# setting each grob's .name before assembling the tree (draw order:
|
|
204
|
+
# grid, axis-b, axis-t, axis-l, axis-r).
|
|
205
|
+
children = [
|
|
206
|
+
("grid", grid_grob),
|
|
207
|
+
("axis-b", xaxes["bottom"]),
|
|
208
|
+
("axis-t", xaxes["top"]),
|
|
209
|
+
("axis-l", yaxes["left"]),
|
|
210
|
+
("axis-r", yaxes["right"]),
|
|
211
|
+
]
|
|
212
|
+
for name, child in children:
|
|
213
|
+
if hasattr(child, "name"):
|
|
214
|
+
child.name = name
|
|
215
|
+
|
|
216
|
+
return grob_tree(*(child for _, child in children))
|
|
217
|
+
|
|
218
|
+
def is_free(self) -> bool:
|
|
219
|
+
"""Whether the aspect ratio is free.
|
|
220
|
+
|
|
221
|
+
Port of R ``CoordAxesInside$is_free`` (``coord_axes_inside.R:154``):
|
|
222
|
+
``self.ratio is None``. (Identical to
|
|
223
|
+
:meth:`CoordCartesian.is_free`; re-declared for parity.)
|
|
224
|
+
|
|
225
|
+
Returns
|
|
226
|
+
-------
|
|
227
|
+
bool
|
|
228
|
+
``True`` when ``self.ratio`` is ``None``.
|
|
229
|
+
"""
|
|
230
|
+
return self.ratio is None
|
|
231
|
+
|
|
232
|
+
def aspect(self, ranges: Any) -> Optional[float]:
|
|
233
|
+
"""Compute the fixed aspect ratio, if any.
|
|
234
|
+
|
|
235
|
+
Port of R ``CoordAxesInside$aspect`` (``coord_axes_inside.R:156-159``):
|
|
236
|
+
``None`` when ``ratio`` is ``None``, else
|
|
237
|
+
``diff(y.range) / diff(x.range) * ratio``.
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
240
|
+
----------
|
|
241
|
+
ranges : dict
|
|
242
|
+
Must expose ``y.range`` / ``x.range`` (or ``y_range`` / ``x_range``).
|
|
243
|
+
|
|
244
|
+
Returns
|
|
245
|
+
-------
|
|
246
|
+
float or None
|
|
247
|
+
The aspect ratio, or ``None`` when ``ratio`` is unset.
|
|
248
|
+
"""
|
|
249
|
+
if self.ratio is None:
|
|
250
|
+
return None
|
|
251
|
+
y_range = ranges.get("y.range") or ranges.get("y_range", [0, 1])
|
|
252
|
+
x_range = ranges.get("x.range") or ranges.get("x_range", [0, 1])
|
|
253
|
+
return (y_range[1] - y_range[0]) / (x_range[1] - x_range[0]) * self.ratio
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# ---------------------------------------------------------------------------
|
|
257
|
+
# Constructor
|
|
258
|
+
# ---------------------------------------------------------------------------
|
|
259
|
+
def coord_axes_inside(
|
|
260
|
+
xlim: Optional[Sequence[float]] = None,
|
|
261
|
+
ylim: Optional[Sequence[float]] = None,
|
|
262
|
+
xintercept: float = 0,
|
|
263
|
+
yintercept: float = 0,
|
|
264
|
+
labels_inside: Union[bool, str] = False,
|
|
265
|
+
ratio: Optional[float] = None,
|
|
266
|
+
expand: bool = True,
|
|
267
|
+
default: bool = False,
|
|
268
|
+
clip: str = "on",
|
|
269
|
+
) -> CoordAxesInside:
|
|
270
|
+
"""Create a Cartesian coordinate system with interior axes.
|
|
271
|
+
|
|
272
|
+
Port of R ``coord_axes_inside()`` (``coord_axes_inside.R:49-114``). Other
|
|
273
|
+
than placing the axes at interior positions, this behaves like
|
|
274
|
+
:func:`ggplot2_py.coord_cartesian` (or :func:`ggplot2_py.coord_fixed` when
|
|
275
|
+
``ratio`` is set).
|
|
276
|
+
|
|
277
|
+
Parameters
|
|
278
|
+
----------
|
|
279
|
+
xlim, ylim : sequence of float, optional
|
|
280
|
+
Coordinate limits (zoom, does not filter data).
|
|
281
|
+
xintercept, yintercept : float, optional
|
|
282
|
+
Positions where the orthogonal axes should be placed. When outside the
|
|
283
|
+
limits, the axes snap to the nearest extreme. Default ``0``.
|
|
284
|
+
labels_inside : bool or {"x", "y", "both", "none"}, optional
|
|
285
|
+
The axes whose labels are placed inside the panel. ``True`` maps to
|
|
286
|
+
``"both"`` and ``False`` (default) maps to ``"none"``.
|
|
287
|
+
ratio : float, optional
|
|
288
|
+
Fixed aspect ratio expressed as ``y / x``, or ``None`` for a free ratio.
|
|
289
|
+
expand : bool, default True
|
|
290
|
+
Whether to expand limits to avoid data/axis overlap.
|
|
291
|
+
default : bool, default False
|
|
292
|
+
Whether this is the plot's default coordinate system.
|
|
293
|
+
clip : str, default "on"
|
|
294
|
+
Clipping: ``"on"`` or ``"off"``.
|
|
295
|
+
|
|
296
|
+
Returns
|
|
297
|
+
-------
|
|
298
|
+
CoordAxesInside
|
|
299
|
+
A coordinate object that can be added to a plot.
|
|
300
|
+
|
|
301
|
+
Examples
|
|
302
|
+
--------
|
|
303
|
+
>>> isinstance(coord_axes_inside(xintercept=1), CoordAxesInside)
|
|
304
|
+
True
|
|
305
|
+
"""
|
|
306
|
+
if isinstance(labels_inside, str):
|
|
307
|
+
labels_inside = arg_match0(
|
|
308
|
+
labels_inside, ("x", "y", "none", "both"), arg_name="labels_inside"
|
|
309
|
+
)
|
|
310
|
+
else:
|
|
311
|
+
labels_inside = "both" if labels_inside is True else "none"
|
|
312
|
+
|
|
313
|
+
inner_axes = theme()
|
|
314
|
+
outer_axes = theme(
|
|
315
|
+
**{
|
|
316
|
+
"axis.line.x.bottom": element_blank(),
|
|
317
|
+
"axis.line.x.top": element_blank(),
|
|
318
|
+
"axis.ticks.x.bottom": element_blank(),
|
|
319
|
+
"axis.ticks.x.top": element_blank(),
|
|
320
|
+
"axis.line.y.left": element_blank(),
|
|
321
|
+
"axis.line.y.right": element_blank(),
|
|
322
|
+
"axis.ticks.y.left": element_blank(),
|
|
323
|
+
"axis.ticks.y.right": element_blank(),
|
|
324
|
+
}
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
if labels_inside in ("x", "both"):
|
|
328
|
+
outer_axes = outer_axes + theme(
|
|
329
|
+
**{
|
|
330
|
+
"axis.text.x.bottom": element_blank(),
|
|
331
|
+
"axis.text.x.top": element_blank(),
|
|
332
|
+
"axis.ticks.length.x.bottom": Unit(0, "pt"),
|
|
333
|
+
"axis.ticks.length.x.top": Unit(0, "pt"),
|
|
334
|
+
}
|
|
335
|
+
)
|
|
336
|
+
else:
|
|
337
|
+
inner_axes = inner_axes + theme(
|
|
338
|
+
**{
|
|
339
|
+
"axis.text.x.bottom": element_blank(),
|
|
340
|
+
"axis.text.x.top": element_blank(),
|
|
341
|
+
}
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
if labels_inside in ("y", "both"):
|
|
345
|
+
outer_axes = outer_axes + theme(
|
|
346
|
+
**{
|
|
347
|
+
"axis.text.y.left": element_blank(),
|
|
348
|
+
"axis.text.y.right": element_blank(),
|
|
349
|
+
"axis.ticks.length.y.left": Unit(0, "pt"),
|
|
350
|
+
"axis.ticks.length.y.right": Unit(0, "pt"),
|
|
351
|
+
}
|
|
352
|
+
)
|
|
353
|
+
else:
|
|
354
|
+
inner_axes = inner_axes + theme(
|
|
355
|
+
**{
|
|
356
|
+
"axis.text.y.left": element_blank(),
|
|
357
|
+
"axis.text.y.right": element_blank(),
|
|
358
|
+
}
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
return CoordAxesInside(
|
|
362
|
+
limits={"x": list(xlim) if xlim is not None else None,
|
|
363
|
+
"y": list(ylim) if ylim is not None else None},
|
|
364
|
+
expand=expand,
|
|
365
|
+
default=default,
|
|
366
|
+
clip=clip,
|
|
367
|
+
ratio=ratio,
|
|
368
|
+
# R: data_frame0(x = xintercept[1], y = yintercept[1]) takes the FIRST
|
|
369
|
+
# element of a (possibly vector) intercept; np.atleast_1d handles both a
|
|
370
|
+
# scalar and a vector uniformly (previously a vector was stored verbatim
|
|
371
|
+
# and crashed downstream in float(origin["x"])).
|
|
372
|
+
origin=pd.DataFrame(
|
|
373
|
+
{
|
|
374
|
+
"x": [np.atleast_1d(xintercept)[0]],
|
|
375
|
+
"y": [np.atleast_1d(yintercept)[0]],
|
|
376
|
+
}
|
|
377
|
+
),
|
|
378
|
+
outer_axes=outer_axes,
|
|
379
|
+
inner_axes=inner_axes,
|
|
380
|
+
)
|