pylocuszoom 0.1.0__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.
- pylocuszoom/__init__.py +120 -0
- pylocuszoom/backends/__init__.py +52 -0
- pylocuszoom/backends/base.py +341 -0
- pylocuszoom/backends/bokeh_backend.py +441 -0
- pylocuszoom/backends/matplotlib_backend.py +288 -0
- pylocuszoom/backends/plotly_backend.py +474 -0
- pylocuszoom/colors.py +107 -0
- pylocuszoom/eqtl.py +218 -0
- pylocuszoom/gene_track.py +311 -0
- pylocuszoom/labels.py +118 -0
- pylocuszoom/ld.py +209 -0
- pylocuszoom/logging.py +153 -0
- pylocuszoom/plotter.py +733 -0
- pylocuszoom/recombination.py +432 -0
- pylocuszoom/reference_data/__init__.py +4 -0
- pylocuszoom/utils.py +194 -0
- pylocuszoom-0.1.0.dist-info/METADATA +367 -0
- pylocuszoom-0.1.0.dist-info/RECORD +20 -0
- pylocuszoom-0.1.0.dist-info/WHEEL +4 -0
- pylocuszoom-0.1.0.dist-info/licenses/LICENSE.md +17 -0
pylocuszoom/__init__.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""pyLocusZoom - Regional association plots for GWAS results.
|
|
2
|
+
|
|
3
|
+
This package provides LocusZoom-style regional association plots with:
|
|
4
|
+
- LD coloring based on R² with lead variant
|
|
5
|
+
- Gene and exon tracks
|
|
6
|
+
- Recombination rate overlays (dog built-in, or user-provided)
|
|
7
|
+
- Automatic SNP labeling
|
|
8
|
+
- Multiple backends: matplotlib (static), plotly (interactive), bokeh (dashboards)
|
|
9
|
+
- eQTL overlay support
|
|
10
|
+
- PySpark DataFrame support for large-scale data
|
|
11
|
+
|
|
12
|
+
Example:
|
|
13
|
+
>>> from pylocuszoom import LocusZoomPlotter
|
|
14
|
+
>>> plotter = LocusZoomPlotter(species="dog")
|
|
15
|
+
>>> fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
|
|
16
|
+
>>> fig.savefig("regional_plot.png", dpi=150)
|
|
17
|
+
|
|
18
|
+
Interactive example:
|
|
19
|
+
>>> plotter = LocusZoomPlotter(species="dog", backend="plotly")
|
|
20
|
+
>>> fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
|
|
21
|
+
>>> fig.write_html("regional_plot.html")
|
|
22
|
+
|
|
23
|
+
Stacked plots:
|
|
24
|
+
>>> fig = plotter.plot_stacked(
|
|
25
|
+
... [gwas_height, gwas_bmi],
|
|
26
|
+
... chrom=1, start=1000000, end=2000000,
|
|
27
|
+
... panel_labels=["Height", "BMI"],
|
|
28
|
+
... )
|
|
29
|
+
|
|
30
|
+
Species Support:
|
|
31
|
+
- Dog (Canis lupus familiaris): Full features including built-in recombination maps
|
|
32
|
+
- Cat (Felis catus): LD coloring and gene tracks (user provides recombination data)
|
|
33
|
+
- Custom: User provides all reference data
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
__version__ = "0.1.0"
|
|
37
|
+
|
|
38
|
+
# Main plotter class
|
|
39
|
+
from .plotter import LocusZoomPlotter
|
|
40
|
+
|
|
41
|
+
# Backend types
|
|
42
|
+
from .backends import BackendType, get_backend
|
|
43
|
+
|
|
44
|
+
# Colors and LD
|
|
45
|
+
from .colors import LEAD_SNP_COLOR, get_ld_bin, get_ld_color, get_ld_color_palette
|
|
46
|
+
|
|
47
|
+
# Gene track
|
|
48
|
+
from .gene_track import get_nearest_gene, plot_gene_track
|
|
49
|
+
|
|
50
|
+
# Labels
|
|
51
|
+
from .labels import add_snp_labels
|
|
52
|
+
|
|
53
|
+
# LD calculation
|
|
54
|
+
from .ld import calculate_ld
|
|
55
|
+
|
|
56
|
+
# Logging configuration
|
|
57
|
+
from .logging import disable_logging, enable_logging
|
|
58
|
+
|
|
59
|
+
# Reference data management
|
|
60
|
+
from .recombination import (
|
|
61
|
+
add_recombination_overlay,
|
|
62
|
+
download_dog_recombination_maps,
|
|
63
|
+
get_recombination_rate_for_region,
|
|
64
|
+
load_recombination_map,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# eQTL support
|
|
68
|
+
from .eqtl import (
|
|
69
|
+
EQTLValidationError,
|
|
70
|
+
calculate_colocalization_overlap,
|
|
71
|
+
filter_eqtl_by_gene,
|
|
72
|
+
filter_eqtl_by_region,
|
|
73
|
+
get_eqtl_genes,
|
|
74
|
+
prepare_eqtl_for_plotting,
|
|
75
|
+
validate_eqtl_df,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Validation utilities
|
|
79
|
+
from .utils import ValidationError, to_pandas
|
|
80
|
+
|
|
81
|
+
__all__ = [
|
|
82
|
+
# Core
|
|
83
|
+
"__version__",
|
|
84
|
+
"LocusZoomPlotter",
|
|
85
|
+
# Backends
|
|
86
|
+
"BackendType",
|
|
87
|
+
"get_backend",
|
|
88
|
+
# Reference data
|
|
89
|
+
"download_dog_recombination_maps",
|
|
90
|
+
# Colors
|
|
91
|
+
"get_ld_color",
|
|
92
|
+
"get_ld_bin",
|
|
93
|
+
"get_ld_color_palette",
|
|
94
|
+
"LEAD_SNP_COLOR",
|
|
95
|
+
# Gene track
|
|
96
|
+
"get_nearest_gene",
|
|
97
|
+
"plot_gene_track",
|
|
98
|
+
# LD
|
|
99
|
+
"calculate_ld",
|
|
100
|
+
# Labels
|
|
101
|
+
"add_snp_labels",
|
|
102
|
+
# Recombination
|
|
103
|
+
"add_recombination_overlay",
|
|
104
|
+
"get_recombination_rate_for_region",
|
|
105
|
+
"load_recombination_map",
|
|
106
|
+
# eQTL
|
|
107
|
+
"validate_eqtl_df",
|
|
108
|
+
"filter_eqtl_by_gene",
|
|
109
|
+
"filter_eqtl_by_region",
|
|
110
|
+
"prepare_eqtl_for_plotting",
|
|
111
|
+
"get_eqtl_genes",
|
|
112
|
+
"calculate_colocalization_overlap",
|
|
113
|
+
"EQTLValidationError",
|
|
114
|
+
# Logging
|
|
115
|
+
"enable_logging",
|
|
116
|
+
"disable_logging",
|
|
117
|
+
# Validation & Utils
|
|
118
|
+
"ValidationError",
|
|
119
|
+
"to_pandas",
|
|
120
|
+
]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Pluggable plotting backends for pyLocusZoom.
|
|
2
|
+
|
|
3
|
+
Supports matplotlib (default), plotly, and bokeh backends.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import TYPE_CHECKING, Literal
|
|
7
|
+
|
|
8
|
+
from .base import PlotBackend
|
|
9
|
+
from .matplotlib_backend import MatplotlibBackend
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from .bokeh_backend import BokehBackend
|
|
13
|
+
from .plotly_backend import PlotlyBackend
|
|
14
|
+
|
|
15
|
+
BackendType = Literal["matplotlib", "plotly", "bokeh"]
|
|
16
|
+
|
|
17
|
+
_BACKENDS: dict[str, type[PlotBackend]] = {
|
|
18
|
+
"matplotlib": MatplotlibBackend,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_backend(name: BackendType) -> PlotBackend:
|
|
23
|
+
"""Get a backend instance by name.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
name: Backend name ('matplotlib', 'plotly', or 'bokeh').
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Instantiated backend.
|
|
30
|
+
|
|
31
|
+
Raises:
|
|
32
|
+
ValueError: If backend name is invalid.
|
|
33
|
+
ImportError: If backend dependencies are not installed.
|
|
34
|
+
"""
|
|
35
|
+
if name == "plotly":
|
|
36
|
+
from .plotly_backend import PlotlyBackend
|
|
37
|
+
|
|
38
|
+
_BACKENDS["plotly"] = PlotlyBackend
|
|
39
|
+
elif name == "bokeh":
|
|
40
|
+
from .bokeh_backend import BokehBackend
|
|
41
|
+
|
|
42
|
+
_BACKENDS["bokeh"] = BokehBackend
|
|
43
|
+
|
|
44
|
+
if name not in _BACKENDS:
|
|
45
|
+
raise ValueError(
|
|
46
|
+
f"Unknown backend: {name}. Available: matplotlib, plotly, bokeh"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return _BACKENDS[name]()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
__all__ = ["PlotBackend", "BackendType", "get_backend", "MatplotlibBackend"]
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
"""Base protocol for plotting backends.
|
|
2
|
+
|
|
3
|
+
Defines the interface that matplotlib, plotly, and bokeh backends must implement.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any, Dict, List, Optional, Protocol, Tuple, Union
|
|
7
|
+
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PlotBackend(Protocol):
|
|
12
|
+
"""Protocol defining the backend interface for LocusZoom plots.
|
|
13
|
+
|
|
14
|
+
All backends (matplotlib, plotly, bokeh) must implement these methods
|
|
15
|
+
to enable consistent plotting across different rendering engines.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def create_figure(
|
|
19
|
+
self,
|
|
20
|
+
n_panels: int,
|
|
21
|
+
height_ratios: List[float],
|
|
22
|
+
figsize: Tuple[float, float],
|
|
23
|
+
sharex: bool = True,
|
|
24
|
+
) -> Tuple[Any, List[Any]]:
|
|
25
|
+
"""Create a figure with multiple panels (subplots).
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
n_panels: Number of vertical panels.
|
|
29
|
+
height_ratios: Relative heights for each panel.
|
|
30
|
+
figsize: Figure size as (width, height).
|
|
31
|
+
sharex: Whether panels share the x-axis.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Tuple of (figure, list of axes/panels).
|
|
35
|
+
"""
|
|
36
|
+
...
|
|
37
|
+
|
|
38
|
+
def scatter(
|
|
39
|
+
self,
|
|
40
|
+
ax: Any,
|
|
41
|
+
x: pd.Series,
|
|
42
|
+
y: pd.Series,
|
|
43
|
+
colors: Union[str, List[str], pd.Series],
|
|
44
|
+
sizes: Union[float, List[float], pd.Series] = 60,
|
|
45
|
+
marker: str = "o",
|
|
46
|
+
edgecolor: str = "black",
|
|
47
|
+
linewidth: float = 0.5,
|
|
48
|
+
zorder: int = 2,
|
|
49
|
+
hover_data: Optional[pd.DataFrame] = None,
|
|
50
|
+
label: Optional[str] = None,
|
|
51
|
+
) -> Any:
|
|
52
|
+
"""Create a scatter plot on the given axes.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
ax: Axes or panel to plot on.
|
|
56
|
+
x: X-axis values (positions).
|
|
57
|
+
y: Y-axis values (-log10 p-values).
|
|
58
|
+
colors: Point colors (single color or per-point).
|
|
59
|
+
sizes: Point sizes.
|
|
60
|
+
marker: Marker style.
|
|
61
|
+
edgecolor: Marker edge color.
|
|
62
|
+
linewidth: Marker edge width.
|
|
63
|
+
zorder: Drawing order.
|
|
64
|
+
hover_data: DataFrame with columns for hover tooltips.
|
|
65
|
+
label: Legend label.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
The scatter plot object.
|
|
69
|
+
"""
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
def line(
|
|
73
|
+
self,
|
|
74
|
+
ax: Any,
|
|
75
|
+
x: pd.Series,
|
|
76
|
+
y: pd.Series,
|
|
77
|
+
color: str = "blue",
|
|
78
|
+
linewidth: float = 1.5,
|
|
79
|
+
alpha: float = 1.0,
|
|
80
|
+
linestyle: str = "-",
|
|
81
|
+
zorder: int = 1,
|
|
82
|
+
label: Optional[str] = None,
|
|
83
|
+
) -> Any:
|
|
84
|
+
"""Create a line plot on the given axes.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
ax: Axes or panel to plot on.
|
|
88
|
+
x: X-axis values.
|
|
89
|
+
y: Y-axis values.
|
|
90
|
+
color: Line color.
|
|
91
|
+
linewidth: Line width.
|
|
92
|
+
alpha: Transparency.
|
|
93
|
+
linestyle: Line style ('-', '--', ':', '-.').
|
|
94
|
+
zorder: Drawing order.
|
|
95
|
+
label: Legend label.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
The line plot object.
|
|
99
|
+
"""
|
|
100
|
+
...
|
|
101
|
+
|
|
102
|
+
def fill_between(
|
|
103
|
+
self,
|
|
104
|
+
ax: Any,
|
|
105
|
+
x: pd.Series,
|
|
106
|
+
y1: Union[float, pd.Series],
|
|
107
|
+
y2: Union[float, pd.Series],
|
|
108
|
+
color: str = "blue",
|
|
109
|
+
alpha: float = 0.3,
|
|
110
|
+
zorder: int = 0,
|
|
111
|
+
) -> Any:
|
|
112
|
+
"""Fill area between two y-values.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
ax: Axes or panel to plot on.
|
|
116
|
+
x: X-axis values.
|
|
117
|
+
y1: Lower y boundary.
|
|
118
|
+
y2: Upper y boundary.
|
|
119
|
+
color: Fill color.
|
|
120
|
+
alpha: Transparency.
|
|
121
|
+
zorder: Drawing order.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
The fill object.
|
|
125
|
+
"""
|
|
126
|
+
...
|
|
127
|
+
|
|
128
|
+
def axhline(
|
|
129
|
+
self,
|
|
130
|
+
ax: Any,
|
|
131
|
+
y: float,
|
|
132
|
+
color: str = "grey",
|
|
133
|
+
linestyle: str = "--",
|
|
134
|
+
linewidth: float = 1.0,
|
|
135
|
+
zorder: int = 1,
|
|
136
|
+
) -> Any:
|
|
137
|
+
"""Add a horizontal line across the axes.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
ax: Axes or panel.
|
|
141
|
+
y: Y-value for the line.
|
|
142
|
+
color: Line color.
|
|
143
|
+
linestyle: Line style.
|
|
144
|
+
linewidth: Line width.
|
|
145
|
+
zorder: Drawing order.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
The line object.
|
|
149
|
+
"""
|
|
150
|
+
...
|
|
151
|
+
|
|
152
|
+
def add_text(
|
|
153
|
+
self,
|
|
154
|
+
ax: Any,
|
|
155
|
+
x: float,
|
|
156
|
+
y: float,
|
|
157
|
+
text: str,
|
|
158
|
+
fontsize: int = 10,
|
|
159
|
+
ha: str = "center",
|
|
160
|
+
va: str = "bottom",
|
|
161
|
+
rotation: float = 0,
|
|
162
|
+
color: str = "black",
|
|
163
|
+
) -> Any:
|
|
164
|
+
"""Add text annotation to axes.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
ax: Axes or panel.
|
|
168
|
+
x: X position.
|
|
169
|
+
y: Y position.
|
|
170
|
+
text: Text content.
|
|
171
|
+
fontsize: Font size.
|
|
172
|
+
ha: Horizontal alignment.
|
|
173
|
+
va: Vertical alignment.
|
|
174
|
+
rotation: Text rotation in degrees.
|
|
175
|
+
color: Text color.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
The text object.
|
|
179
|
+
"""
|
|
180
|
+
...
|
|
181
|
+
|
|
182
|
+
def add_rectangle(
|
|
183
|
+
self,
|
|
184
|
+
ax: Any,
|
|
185
|
+
xy: Tuple[float, float],
|
|
186
|
+
width: float,
|
|
187
|
+
height: float,
|
|
188
|
+
facecolor: str = "blue",
|
|
189
|
+
edgecolor: str = "black",
|
|
190
|
+
linewidth: float = 0.5,
|
|
191
|
+
zorder: int = 2,
|
|
192
|
+
) -> Any:
|
|
193
|
+
"""Add a rectangle patch to axes.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
ax: Axes or panel.
|
|
197
|
+
xy: Bottom-left corner coordinates.
|
|
198
|
+
width: Rectangle width.
|
|
199
|
+
height: Rectangle height.
|
|
200
|
+
facecolor: Fill color.
|
|
201
|
+
edgecolor: Edge color.
|
|
202
|
+
linewidth: Edge width.
|
|
203
|
+
zorder: Drawing order.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
The rectangle object.
|
|
207
|
+
"""
|
|
208
|
+
...
|
|
209
|
+
|
|
210
|
+
def set_xlim(self, ax: Any, left: float, right: float) -> None:
|
|
211
|
+
"""Set x-axis limits.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
ax: Axes or panel.
|
|
215
|
+
left: Minimum x value.
|
|
216
|
+
right: Maximum x value.
|
|
217
|
+
"""
|
|
218
|
+
...
|
|
219
|
+
|
|
220
|
+
def set_ylim(self, ax: Any, bottom: float, top: float) -> None:
|
|
221
|
+
"""Set y-axis limits.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
ax: Axes or panel.
|
|
225
|
+
bottom: Minimum y value.
|
|
226
|
+
top: Maximum y value.
|
|
227
|
+
"""
|
|
228
|
+
...
|
|
229
|
+
|
|
230
|
+
def set_xlabel(self, ax: Any, label: str, fontsize: int = 12) -> None:
|
|
231
|
+
"""Set x-axis label.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
ax: Axes or panel.
|
|
235
|
+
label: Label text.
|
|
236
|
+
fontsize: Font size.
|
|
237
|
+
"""
|
|
238
|
+
...
|
|
239
|
+
|
|
240
|
+
def set_ylabel(self, ax: Any, label: str, fontsize: int = 12) -> None:
|
|
241
|
+
"""Set y-axis label.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
ax: Axes or panel.
|
|
245
|
+
label: Label text.
|
|
246
|
+
fontsize: Font size.
|
|
247
|
+
"""
|
|
248
|
+
...
|
|
249
|
+
|
|
250
|
+
def set_title(self, ax: Any, title: str, fontsize: int = 14) -> None:
|
|
251
|
+
"""Set panel title.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
ax: Axes or panel.
|
|
255
|
+
title: Title text.
|
|
256
|
+
fontsize: Font size.
|
|
257
|
+
"""
|
|
258
|
+
...
|
|
259
|
+
|
|
260
|
+
def create_twin_axis(self, ax: Any) -> Any:
|
|
261
|
+
"""Create a secondary y-axis sharing the same x-axis.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
ax: Primary axes.
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
Secondary axes for overlay (e.g., recombination rate).
|
|
268
|
+
"""
|
|
269
|
+
...
|
|
270
|
+
|
|
271
|
+
def add_legend(
|
|
272
|
+
self,
|
|
273
|
+
ax: Any,
|
|
274
|
+
handles: List[Any],
|
|
275
|
+
labels: List[str],
|
|
276
|
+
loc: str = "upper left",
|
|
277
|
+
title: Optional[str] = None,
|
|
278
|
+
) -> Any:
|
|
279
|
+
"""Add a legend to the axes.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
ax: Axes or panel.
|
|
283
|
+
handles: Legend handle objects.
|
|
284
|
+
labels: Legend labels.
|
|
285
|
+
loc: Legend location.
|
|
286
|
+
title: Legend title.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
The legend object.
|
|
290
|
+
"""
|
|
291
|
+
...
|
|
292
|
+
|
|
293
|
+
def hide_spines(self, ax: Any, spines: List[str]) -> None:
|
|
294
|
+
"""Hide specified axis spines.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
ax: Axes or panel.
|
|
298
|
+
spines: List of spine names ('top', 'right', 'bottom', 'left').
|
|
299
|
+
"""
|
|
300
|
+
...
|
|
301
|
+
|
|
302
|
+
def format_xaxis_mb(self, ax: Any) -> None:
|
|
303
|
+
"""Format x-axis to show megabase values.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
ax: Axes or panel.
|
|
307
|
+
"""
|
|
308
|
+
...
|
|
309
|
+
|
|
310
|
+
def save(
|
|
311
|
+
self,
|
|
312
|
+
fig: Any,
|
|
313
|
+
path: str,
|
|
314
|
+
dpi: int = 150,
|
|
315
|
+
bbox_inches: str = "tight",
|
|
316
|
+
) -> None:
|
|
317
|
+
"""Save figure to file.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
fig: Figure object.
|
|
321
|
+
path: Output file path (.png, .pdf, .html).
|
|
322
|
+
dpi: Resolution for raster formats.
|
|
323
|
+
bbox_inches: Bounding box adjustment.
|
|
324
|
+
"""
|
|
325
|
+
...
|
|
326
|
+
|
|
327
|
+
def show(self, fig: Any) -> None:
|
|
328
|
+
"""Display the figure.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
fig: Figure object.
|
|
332
|
+
"""
|
|
333
|
+
...
|
|
334
|
+
|
|
335
|
+
def close(self, fig: Any) -> None:
|
|
336
|
+
"""Close the figure and free resources.
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
fig: Figure object.
|
|
340
|
+
"""
|
|
341
|
+
...
|