figrecipe 0.6.0__py3-none-any.whl → 0.7.4__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.
- figrecipe/__init__.py +106 -973
- figrecipe/_api/__init__.py +48 -0
- figrecipe/_api/_extract.py +108 -0
- figrecipe/_api/_notebook.py +61 -0
- figrecipe/_api/_panel.py +46 -0
- figrecipe/_api/_save.py +191 -0
- figrecipe/_api/_seaborn_proxy.py +34 -0
- figrecipe/_api/_style_manager.py +153 -0
- figrecipe/_api/_subplots.py +333 -0
- figrecipe/_api/_validate.py +82 -0
- figrecipe/_dev/__init__.py +2 -93
- figrecipe/_dev/_plotters.py +76 -0
- figrecipe/_dev/_run_demos.py +56 -0
- figrecipe/_dev/demo_plotters/__init__.py +35 -166
- figrecipe/_dev/demo_plotters/_categories.py +81 -0
- figrecipe/_dev/demo_plotters/_figure_creators.py +119 -0
- figrecipe/_dev/demo_plotters/_helpers.py +31 -0
- figrecipe/_dev/demo_plotters/_registry.py +50 -0
- figrecipe/_dev/demo_plotters/bar_categorical/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/contour_surface/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/distribution/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/image_matrix/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/line_curve/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/{plot_plot.py → line_curve/plot_plot.py} +3 -2
- figrecipe/_dev/demo_plotters/scatter_points/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/special/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/{plot_pie.py → special/plot_pie.py} +5 -1
- figrecipe/_dev/demo_plotters/spectral_signal/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/vector_flow/__init__.py +4 -0
- figrecipe/_editor/__init__.py +57 -9
- figrecipe/_editor/_bbox/__init__.py +43 -0
- figrecipe/_editor/_bbox/_collections.py +177 -0
- figrecipe/_editor/_bbox/_elements.py +159 -0
- figrecipe/_editor/_bbox/_extract.py +256 -0
- figrecipe/_editor/_bbox/_extract_axes.py +370 -0
- figrecipe/_editor/_bbox/_extract_text.py +342 -0
- figrecipe/_editor/_bbox/_lines.py +173 -0
- figrecipe/_editor/_bbox/_transforms.py +146 -0
- figrecipe/_editor/_flask_app.py +68 -1039
- figrecipe/_editor/_helpers.py +242 -0
- figrecipe/_editor/_hitmap/__init__.py +76 -0
- figrecipe/_editor/_hitmap/_artists/__init__.py +21 -0
- figrecipe/_editor/_hitmap/_artists/_collections.py +345 -0
- figrecipe/_editor/_hitmap/_artists/_images.py +68 -0
- figrecipe/_editor/_hitmap/_artists/_lines.py +107 -0
- figrecipe/_editor/_hitmap/_artists/_patches.py +163 -0
- figrecipe/_editor/_hitmap/_artists/_text.py +190 -0
- figrecipe/_editor/_hitmap/_colors.py +181 -0
- figrecipe/_editor/_hitmap/_detect.py +137 -0
- figrecipe/_editor/_hitmap/_restore.py +154 -0
- figrecipe/_editor/_hitmap_main.py +182 -0
- figrecipe/_editor/_preferences.py +135 -0
- figrecipe/_editor/_render_overrides.py +480 -0
- figrecipe/_editor/_renderer.py +35 -185
- figrecipe/_editor/_routes_axis.py +453 -0
- figrecipe/_editor/_routes_core.py +284 -0
- figrecipe/_editor/_routes_element.py +317 -0
- figrecipe/_editor/_routes_style.py +223 -0
- figrecipe/_editor/_templates/__init__.py +78 -1
- figrecipe/_editor/_templates/_html.py +109 -13
- figrecipe/_editor/_templates/_scripts/__init__.py +120 -0
- figrecipe/_editor/_templates/_scripts/_api.py +228 -0
- figrecipe/_editor/_templates/_scripts/_colors.py +485 -0
- figrecipe/_editor/_templates/_scripts/_core.py +436 -0
- figrecipe/_editor/_templates/_scripts/_debug_snapshot.py +186 -0
- figrecipe/_editor/_templates/_scripts/_element_editor.py +310 -0
- figrecipe/_editor/_templates/_scripts/_files.py +195 -0
- figrecipe/_editor/_templates/_scripts/_hitmap.py +509 -0
- figrecipe/_editor/_templates/_scripts/_inspector.py +315 -0
- figrecipe/_editor/_templates/_scripts/_labels.py +464 -0
- figrecipe/_editor/_templates/_scripts/_legend_drag.py +265 -0
- figrecipe/_editor/_templates/_scripts/_modals.py +226 -0
- figrecipe/_editor/_templates/_scripts/_overlays.py +292 -0
- figrecipe/_editor/_templates/_scripts/_panel_drag.py +334 -0
- figrecipe/_editor/_templates/_scripts/_panel_position.py +279 -0
- figrecipe/_editor/_templates/_scripts/_selection.py +237 -0
- figrecipe/_editor/_templates/_scripts/_tabs.py +89 -0
- figrecipe/_editor/_templates/_scripts/_view_mode.py +107 -0
- figrecipe/_editor/_templates/_scripts/_zoom.py +179 -0
- figrecipe/_editor/_templates/_styles/__init__.py +69 -0
- figrecipe/_editor/_templates/_styles/_base.py +64 -0
- figrecipe/_editor/_templates/_styles/_buttons.py +206 -0
- figrecipe/_editor/_templates/_styles/_color_input.py +123 -0
- figrecipe/_editor/_templates/_styles/_controls.py +265 -0
- figrecipe/_editor/_templates/_styles/_dynamic_props.py +144 -0
- figrecipe/_editor/_templates/_styles/_forms.py +126 -0
- figrecipe/_editor/_templates/_styles/_hitmap.py +184 -0
- figrecipe/_editor/_templates/_styles/_inspector.py +90 -0
- figrecipe/_editor/_templates/_styles/_labels.py +118 -0
- figrecipe/_editor/_templates/_styles/_modals.py +98 -0
- figrecipe/_editor/_templates/_styles/_overlays.py +130 -0
- figrecipe/_editor/_templates/_styles/_preview.py +225 -0
- figrecipe/_editor/_templates/_styles/_selection.py +73 -0
- figrecipe/_params/_DECORATION_METHODS.py +6 -0
- figrecipe/_recorder.py +35 -106
- figrecipe/_recorder_utils.py +124 -0
- figrecipe/_reproducer/__init__.py +18 -0
- figrecipe/_reproducer/_core.py +498 -0
- figrecipe/_reproducer/_custom_plots.py +279 -0
- figrecipe/_reproducer/_seaborn.py +100 -0
- figrecipe/_reproducer/_violin.py +186 -0
- figrecipe/_signatures/_kwargs.py +273 -0
- figrecipe/_signatures/_loader.py +21 -423
- figrecipe/_signatures/_parsing.py +147 -0
- figrecipe/_wrappers/_axes.py +119 -910
- figrecipe/_wrappers/_axes_helpers.py +136 -0
- figrecipe/_wrappers/_axes_plots.py +418 -0
- figrecipe/_wrappers/_axes_seaborn.py +157 -0
- figrecipe/_wrappers/_figure.py +162 -0
- figrecipe/_wrappers/_panel_labels.py +127 -0
- figrecipe/_wrappers/_plot_helpers.py +143 -0
- figrecipe/_wrappers/_violin_helpers.py +180 -0
- figrecipe/styles/__init__.py +8 -6
- figrecipe/styles/_dotdict.py +72 -0
- figrecipe/styles/_finalize.py +134 -0
- figrecipe/styles/_fonts.py +77 -0
- figrecipe/styles/_kwargs_converter.py +178 -0
- figrecipe/styles/_plot_styles.py +209 -0
- figrecipe/styles/_style_applier.py +32 -478
- figrecipe/styles/_style_loader.py +16 -192
- figrecipe/styles/_themes.py +151 -0
- figrecipe/styles/presets/MATPLOTLIB.yaml +2 -1
- figrecipe/styles/presets/SCITEX.yaml +29 -24
- {figrecipe-0.6.0.dist-info → figrecipe-0.7.4.dist-info}/METADATA +37 -2
- figrecipe-0.7.4.dist-info/RECORD +188 -0
- figrecipe/_editor/_bbox.py +0 -978
- figrecipe/_editor/_hitmap.py +0 -937
- figrecipe/_editor/_templates/_scripts.py +0 -2778
- figrecipe/_editor/_templates/_styles.py +0 -1326
- figrecipe/_reproducer.py +0 -975
- figrecipe-0.6.0.dist-info/RECORD +0 -90
- /figrecipe/_dev/demo_plotters/{plot_bar.py → bar_categorical/plot_bar.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_barh.py → bar_categorical/plot_barh.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_contour.py → contour_surface/plot_contour.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_contourf.py → contour_surface/plot_contourf.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_tricontour.py → contour_surface/plot_tricontour.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_tricontourf.py → contour_surface/plot_tricontourf.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_tripcolor.py → contour_surface/plot_tripcolor.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_triplot.py → contour_surface/plot_triplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_boxplot.py → distribution/plot_boxplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_ecdf.py → distribution/plot_ecdf.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_hist.py → distribution/plot_hist.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_hist2d.py → distribution/plot_hist2d.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_violinplot.py → distribution/plot_violinplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_hexbin.py → image_matrix/plot_hexbin.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_imshow.py → image_matrix/plot_imshow.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_matshow.py → image_matrix/plot_matshow.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_pcolor.py → image_matrix/plot_pcolor.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_pcolormesh.py → image_matrix/plot_pcolormesh.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_spy.py → image_matrix/plot_spy.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_errorbar.py → line_curve/plot_errorbar.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_fill.py → line_curve/plot_fill.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_fill_between.py → line_curve/plot_fill_between.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_fill_betweenx.py → line_curve/plot_fill_betweenx.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_stackplot.py → line_curve/plot_stackplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_stairs.py → line_curve/plot_stairs.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_step.py → line_curve/plot_step.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_scatter.py → scatter_points/plot_scatter.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_eventplot.py → special/plot_eventplot.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_loglog.py → special/plot_loglog.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_semilogx.py → special/plot_semilogx.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_semilogy.py → special/plot_semilogy.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_stem.py → special/plot_stem.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_acorr.py → spectral_signal/plot_acorr.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_angle_spectrum.py → spectral_signal/plot_angle_spectrum.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_cohere.py → spectral_signal/plot_cohere.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_csd.py → spectral_signal/plot_csd.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_magnitude_spectrum.py → spectral_signal/plot_magnitude_spectrum.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_phase_spectrum.py → spectral_signal/plot_phase_spectrum.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_psd.py → spectral_signal/plot_psd.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_specgram.py → spectral_signal/plot_specgram.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_xcorr.py → spectral_signal/plot_xcorr.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_barbs.py → vector_flow/plot_barbs.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_quiver.py → vector_flow/plot_quiver.py} +0 -0
- /figrecipe/_dev/demo_plotters/{plot_streamplot.py → vector_flow/plot_streamplot.py} +0 -0
- {figrecipe-0.6.0.dist-info → figrecipe-0.7.4.dist-info}/WHEEL +0 -0
- {figrecipe-0.6.0.dist-info → figrecipe-0.7.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -9,6 +9,11 @@ Usage
|
|
|
9
9
|
>>> # List all available plot types
|
|
10
10
|
>>> print(list(REGISTRY.keys()))
|
|
11
11
|
>>>
|
|
12
|
+
>>> # List by category
|
|
13
|
+
>>> from figrecipe._dev.demo_plotters import CATEGORIES
|
|
14
|
+
>>> for cat, plots in CATEGORIES.items():
|
|
15
|
+
... print(f"{cat}: {plots}")
|
|
16
|
+
>>>
|
|
12
17
|
>>> # Create a single figure with all plot types
|
|
13
18
|
>>> fig, axes = create_all_plots_figure(fr)
|
|
14
19
|
>>>
|
|
@@ -16,180 +21,44 @@ Usage
|
|
|
16
21
|
>>> fig, ax = REGISTRY['plot'](fr, rng, ax)
|
|
17
22
|
"""
|
|
18
23
|
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# Import all demo functions into registry
|
|
34
|
-
for _file in _demo_files:
|
|
35
|
-
_module_name = _file.stem # e.g., plot_scatter
|
|
36
|
-
_plot_name = _module_name.replace("plot_", "") # e.g., scatter
|
|
37
|
-
_func_name = _module_name # e.g., plot_scatter
|
|
38
|
-
try:
|
|
39
|
-
_module = importlib.import_module(f".{_module_name}", package=__name__)
|
|
40
|
-
if hasattr(_module, _func_name):
|
|
41
|
-
REGISTRY[_plot_name] = getattr(_module, _func_name)
|
|
42
|
-
except ImportError as e:
|
|
43
|
-
print(f"Warning: Could not import {_module_name}: {e}")
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def list_plots():
|
|
47
|
-
"""List all available plot types.
|
|
48
|
-
|
|
49
|
-
Returns
|
|
50
|
-
-------
|
|
51
|
-
list of str
|
|
52
|
-
Names of available plot types.
|
|
53
|
-
"""
|
|
54
|
-
return list(REGISTRY.keys())
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def get_plotter(name: str) -> Optional[Callable]:
|
|
58
|
-
"""Get plotter function by name.
|
|
59
|
-
|
|
60
|
-
Parameters
|
|
61
|
-
----------
|
|
62
|
-
name : str
|
|
63
|
-
Plot type name (e.g., 'scatter', 'bar', 'hist').
|
|
64
|
-
|
|
65
|
-
Returns
|
|
66
|
-
-------
|
|
67
|
-
callable or None
|
|
68
|
-
Plotter function or None if not found.
|
|
69
|
-
"""
|
|
70
|
-
return REGISTRY.get(name)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def create_all_plots_figure(plt, seed: int = 42) -> Tuple:
|
|
74
|
-
"""Create a single figure with all supported plot types.
|
|
75
|
-
|
|
76
|
-
Parameters
|
|
77
|
-
----------
|
|
78
|
-
plt : module
|
|
79
|
-
figrecipe module (import figrecipe as fr).
|
|
80
|
-
seed : int
|
|
81
|
-
Random seed for reproducibility.
|
|
82
|
-
|
|
83
|
-
Returns
|
|
84
|
-
-------
|
|
85
|
-
tuple
|
|
86
|
-
(fig, axes) where fig is RecordingFigure and axes is array of RecordingAxes.
|
|
87
|
-
"""
|
|
88
|
-
rng = np.random.default_rng(seed)
|
|
89
|
-
|
|
90
|
-
n_plots = len(REGISTRY)
|
|
91
|
-
ncols = 7
|
|
92
|
-
nrows = math.ceil(n_plots / ncols)
|
|
93
|
-
|
|
94
|
-
fig, axes = plt.subplots(nrows=nrows, ncols=ncols)
|
|
95
|
-
axes_flat = axes.flatten()
|
|
96
|
-
|
|
97
|
-
results = {}
|
|
98
|
-
for i, (name, plotter) in enumerate(REGISTRY.items()):
|
|
99
|
-
ax = axes_flat[i]
|
|
100
|
-
try:
|
|
101
|
-
plotter(plt, rng, ax=ax)
|
|
102
|
-
results[name] = {"success": True, "error": None}
|
|
103
|
-
except Exception as e:
|
|
104
|
-
ax.set_title(f"{name}\n(ERROR)")
|
|
105
|
-
ax.text(
|
|
106
|
-
0.5,
|
|
107
|
-
0.5,
|
|
108
|
-
str(e)[:50],
|
|
109
|
-
ha="center",
|
|
110
|
-
va="center",
|
|
111
|
-
transform=ax.transAxes,
|
|
112
|
-
fontsize=6,
|
|
113
|
-
wrap=True,
|
|
114
|
-
)
|
|
115
|
-
results[name] = {"success": False, "error": str(e)}
|
|
116
|
-
|
|
117
|
-
# Hide unused axes
|
|
118
|
-
for i in range(n_plots, len(axes_flat)):
|
|
119
|
-
axes_flat[i].set_visible(False)
|
|
120
|
-
|
|
121
|
-
# Add panel labels
|
|
122
|
-
panel_labels = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" * 2 # 52 labels
|
|
123
|
-
for i, ax in enumerate(axes_flat[:n_plots]):
|
|
124
|
-
if i < len(panel_labels):
|
|
125
|
-
plt.panel_label(ax, panel_labels[i])
|
|
126
|
-
|
|
127
|
-
fig.suptitle(f"All {n_plots} Supported Plot Types")
|
|
128
|
-
|
|
129
|
-
return fig, axes, results
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def run_individual_demos(plt, output_dir=None, show=False):
|
|
133
|
-
"""Run all demo plotters individually and optionally save outputs.
|
|
134
|
-
|
|
135
|
-
Parameters
|
|
136
|
-
----------
|
|
137
|
-
plt : module
|
|
138
|
-
figrecipe or matplotlib.pyplot module.
|
|
139
|
-
output_dir : Path, optional
|
|
140
|
-
Directory to save output images.
|
|
141
|
-
show : bool
|
|
142
|
-
Whether to show figures.
|
|
143
|
-
|
|
144
|
-
Returns
|
|
145
|
-
-------
|
|
146
|
-
dict
|
|
147
|
-
Results for each demo: {name: {'success': bool, 'error': str or None}}
|
|
148
|
-
"""
|
|
149
|
-
rng = np.random.default_rng(42)
|
|
150
|
-
results = {}
|
|
151
|
-
|
|
152
|
-
if output_dir:
|
|
153
|
-
output_dir = Path(output_dir)
|
|
154
|
-
output_dir.mkdir(parents=True, exist_ok=True)
|
|
155
|
-
|
|
156
|
-
for name, plotter in REGISTRY.items():
|
|
157
|
-
try:
|
|
158
|
-
fig, ax = plotter(plt, rng)
|
|
159
|
-
if output_dir:
|
|
160
|
-
out_path = output_dir / f"plot_{name}.png"
|
|
161
|
-
if hasattr(fig, "fig"):
|
|
162
|
-
fig.fig.savefig(out_path, dpi=100, bbox_inches="tight")
|
|
163
|
-
else:
|
|
164
|
-
fig.savefig(out_path, dpi=100, bbox_inches="tight")
|
|
165
|
-
if show:
|
|
166
|
-
plt.show()
|
|
167
|
-
else:
|
|
168
|
-
if hasattr(fig, "fig"):
|
|
169
|
-
plt.close(fig.fig)
|
|
170
|
-
else:
|
|
171
|
-
plt.close(fig)
|
|
172
|
-
results[name] = {"success": True, "error": None}
|
|
173
|
-
except Exception as e:
|
|
174
|
-
results[name] = {"success": False, "error": str(e)}
|
|
175
|
-
|
|
176
|
-
return results
|
|
177
|
-
|
|
24
|
+
from ._categories import CATEGORIES, CATEGORY_DISPLAY_NAMES, REPRESENTATIVES
|
|
25
|
+
from ._figure_creators import (
|
|
26
|
+
create_all_plots_figure,
|
|
27
|
+
run_all_demos,
|
|
28
|
+
run_individual_demos,
|
|
29
|
+
)
|
|
30
|
+
from ._helpers import (
|
|
31
|
+
get_plotter,
|
|
32
|
+
get_representative_plots,
|
|
33
|
+
list_plots,
|
|
34
|
+
list_plots_by_category,
|
|
35
|
+
)
|
|
36
|
+
from ._registry import REGISTRY
|
|
178
37
|
|
|
179
38
|
# Legacy exports for backwards compatibility
|
|
180
|
-
__all__ = [
|
|
39
|
+
__all__ = [
|
|
40
|
+
"REGISTRY",
|
|
41
|
+
"CATEGORIES",
|
|
42
|
+
"CATEGORY_DISPLAY_NAMES",
|
|
43
|
+
"REPRESENTATIVES",
|
|
44
|
+
"list_plots",
|
|
45
|
+
"list_plots_by_category",
|
|
46
|
+
"get_representative_plots",
|
|
47
|
+
"get_plotter",
|
|
48
|
+
"create_all_plots_figure",
|
|
49
|
+
"run_individual_demos",
|
|
50
|
+
"run_all_demos",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
# Legacy: export plot_* functions to globals
|
|
181
54
|
for _name, _func in REGISTRY.items():
|
|
182
55
|
globals()[f"plot_{_name}"] = _func
|
|
56
|
+
__all__.append(f"plot_{_name}")
|
|
183
57
|
|
|
184
58
|
|
|
185
59
|
def list_demos():
|
|
186
60
|
"""Legacy: List all available demo functions."""
|
|
187
|
-
return
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
def run_all_demos(plt, output_dir=None, show=False):
|
|
191
|
-
"""Legacy: Alias for run_individual_demos."""
|
|
192
|
-
return run_individual_demos(plt, output_dir, show)
|
|
61
|
+
return [f"plot_{name}" for name in REGISTRY.keys()]
|
|
193
62
|
|
|
194
63
|
|
|
195
64
|
# EOF
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Plot categories for organized display."""
|
|
4
|
+
|
|
5
|
+
from typing import Dict, List
|
|
6
|
+
|
|
7
|
+
from ._registry import REGISTRY
|
|
8
|
+
|
|
9
|
+
# Plot categories for organized display
|
|
10
|
+
# Keys match directory names in demo_plotters/
|
|
11
|
+
_CATEGORIES_RAW: Dict[str, List[str]] = {
|
|
12
|
+
"line_curve": [
|
|
13
|
+
"plot",
|
|
14
|
+
"step",
|
|
15
|
+
"fill",
|
|
16
|
+
"fill_between",
|
|
17
|
+
"fill_betweenx",
|
|
18
|
+
"errorbar",
|
|
19
|
+
"stackplot",
|
|
20
|
+
"stairs",
|
|
21
|
+
],
|
|
22
|
+
"scatter_points": ["scatter"],
|
|
23
|
+
"bar_categorical": ["bar", "barh"],
|
|
24
|
+
"distribution": ["hist", "hist2d", "boxplot", "violinplot", "ecdf"],
|
|
25
|
+
"image_matrix": ["imshow", "matshow", "pcolor", "pcolormesh", "hexbin", "spy"],
|
|
26
|
+
"contour_surface": [
|
|
27
|
+
"contour",
|
|
28
|
+
"contourf",
|
|
29
|
+
"tricontour",
|
|
30
|
+
"tricontourf",
|
|
31
|
+
"tripcolor",
|
|
32
|
+
"triplot",
|
|
33
|
+
],
|
|
34
|
+
"spectral_signal": [
|
|
35
|
+
"specgram",
|
|
36
|
+
"psd",
|
|
37
|
+
"csd",
|
|
38
|
+
"cohere",
|
|
39
|
+
"angle_spectrum",
|
|
40
|
+
"magnitude_spectrum",
|
|
41
|
+
"phase_spectrum",
|
|
42
|
+
"acorr",
|
|
43
|
+
"xcorr",
|
|
44
|
+
],
|
|
45
|
+
"vector_flow": ["quiver", "barbs", "streamplot"],
|
|
46
|
+
"special": ["pie", "stem", "eventplot", "loglog", "semilogx", "semilogy"],
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Display names for categories (for UI/documentation)
|
|
50
|
+
CATEGORY_DISPLAY_NAMES: Dict[str, str] = {
|
|
51
|
+
"line_curve": "Line & Curve",
|
|
52
|
+
"scatter_points": "Scatter & Points",
|
|
53
|
+
"bar_categorical": "Bar & Categorical",
|
|
54
|
+
"distribution": "Distribution",
|
|
55
|
+
"image_matrix": "2D Image & Matrix",
|
|
56
|
+
"contour_surface": "Contour & Surface",
|
|
57
|
+
"spectral_signal": "Spectral & Signal",
|
|
58
|
+
"vector_flow": "Vector & Flow",
|
|
59
|
+
"special": "Special",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Filter categories to only include available plots
|
|
63
|
+
CATEGORIES: Dict[str, List[str]] = {
|
|
64
|
+
cat: [p for p in plots if p in REGISTRY] for cat, plots in _CATEGORIES_RAW.items()
|
|
65
|
+
}
|
|
66
|
+
CATEGORIES = {cat: plots for cat, plots in CATEGORIES.items() if plots}
|
|
67
|
+
|
|
68
|
+
# Representative plots (one per category)
|
|
69
|
+
REPRESENTATIVES: Dict[str, str] = {
|
|
70
|
+
"line_curve": "plot",
|
|
71
|
+
"scatter_points": "scatter",
|
|
72
|
+
"bar_categorical": "bar",
|
|
73
|
+
"distribution": "hist",
|
|
74
|
+
"image_matrix": "imshow",
|
|
75
|
+
"contour_surface": "contourf",
|
|
76
|
+
"spectral_signal": "specgram",
|
|
77
|
+
"vector_flow": "quiver",
|
|
78
|
+
"special": "pie",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# EOF
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Figure creation functions for demo plotters."""
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, Tuple
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from ._registry import REGISTRY
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def create_all_plots_figure(plt, seed: int = 42) -> Tuple:
|
|
15
|
+
"""Create a single figure with all supported plot types.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
plt : module
|
|
20
|
+
figrecipe module (import figrecipe as fr).
|
|
21
|
+
seed : int
|
|
22
|
+
Random seed for reproducibility.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
tuple
|
|
27
|
+
(fig, axes, results) where results maps name to success/error.
|
|
28
|
+
"""
|
|
29
|
+
rng = np.random.default_rng(seed)
|
|
30
|
+
|
|
31
|
+
n_plots = len(REGISTRY)
|
|
32
|
+
ncols = 7
|
|
33
|
+
nrows = math.ceil(n_plots / ncols)
|
|
34
|
+
|
|
35
|
+
fig, axes = plt.subplots(nrows=nrows, ncols=ncols)
|
|
36
|
+
axes_flat = axes.flatten()
|
|
37
|
+
|
|
38
|
+
results = {}
|
|
39
|
+
for i, (name, plotter) in enumerate(REGISTRY.items()):
|
|
40
|
+
ax = axes_flat[i]
|
|
41
|
+
try:
|
|
42
|
+
plotter(plt, rng, ax=ax)
|
|
43
|
+
results[name] = {"success": True, "error": None}
|
|
44
|
+
except Exception as e:
|
|
45
|
+
ax.set_title(f"{name}\n(ERROR)")
|
|
46
|
+
ax.text(
|
|
47
|
+
0.5,
|
|
48
|
+
0.5,
|
|
49
|
+
str(e)[:50],
|
|
50
|
+
ha="center",
|
|
51
|
+
va="center",
|
|
52
|
+
transform=ax.transAxes,
|
|
53
|
+
fontsize=6,
|
|
54
|
+
wrap=True,
|
|
55
|
+
)
|
|
56
|
+
results[name] = {"success": False, "error": str(e)}
|
|
57
|
+
|
|
58
|
+
# Hide unused axes
|
|
59
|
+
for i in range(n_plots, len(axes_flat)):
|
|
60
|
+
axes_flat[i].set_visible(False)
|
|
61
|
+
|
|
62
|
+
# Add panel labels
|
|
63
|
+
panel_labels = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" * 2
|
|
64
|
+
for i, ax in enumerate(axes_flat[:n_plots]):
|
|
65
|
+
if i < len(panel_labels):
|
|
66
|
+
plt.panel_label(ax, panel_labels[i])
|
|
67
|
+
|
|
68
|
+
fig.suptitle(f"All {n_plots} Supported Plot Types")
|
|
69
|
+
|
|
70
|
+
return fig, axes, results
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def run_individual_demos(plt, output_dir=None, show=False) -> Dict:
|
|
74
|
+
"""Run all demo plotters individually and optionally save outputs.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
plt : module
|
|
79
|
+
figrecipe or matplotlib.pyplot module.
|
|
80
|
+
output_dir : Path, optional
|
|
81
|
+
Directory to save output images.
|
|
82
|
+
show : bool
|
|
83
|
+
Whether to show figures.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
dict
|
|
88
|
+
Results for each demo: {name: {'success': bool, 'error': str or None}}
|
|
89
|
+
"""
|
|
90
|
+
rng = np.random.default_rng(42)
|
|
91
|
+
results = {}
|
|
92
|
+
|
|
93
|
+
if output_dir:
|
|
94
|
+
output_dir = Path(output_dir)
|
|
95
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
96
|
+
|
|
97
|
+
for name, plotter in REGISTRY.items():
|
|
98
|
+
try:
|
|
99
|
+
fig, ax = plotter(plt, rng)
|
|
100
|
+
if output_dir:
|
|
101
|
+
out_path = output_dir / f"plot_{name}.png"
|
|
102
|
+
mpl_fig = fig.fig if hasattr(fig, "fig") else fig
|
|
103
|
+
mpl_fig.savefig(out_path, dpi=100, bbox_inches="tight")
|
|
104
|
+
if show:
|
|
105
|
+
plt.show()
|
|
106
|
+
else:
|
|
107
|
+
mpl_fig = fig.fig if hasattr(fig, "fig") else fig
|
|
108
|
+
plt.close(mpl_fig)
|
|
109
|
+
results[name] = {"success": True, "error": None}
|
|
110
|
+
except Exception as e:
|
|
111
|
+
results[name] = {"success": False, "error": str(e)}
|
|
112
|
+
|
|
113
|
+
return results
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# Legacy alias
|
|
117
|
+
run_all_demos = run_individual_demos
|
|
118
|
+
|
|
119
|
+
# EOF
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Helper functions for demo plotters."""
|
|
4
|
+
|
|
5
|
+
from typing import Callable, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from ._categories import CATEGORIES, REPRESENTATIVES
|
|
8
|
+
from ._registry import REGISTRY
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def list_plots() -> List[str]:
|
|
12
|
+
"""List all available plot types."""
|
|
13
|
+
return list(REGISTRY.keys())
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def list_plots_by_category() -> Dict[str, List[str]]:
|
|
17
|
+
"""List all available plot types organized by category."""
|
|
18
|
+
return CATEGORIES.copy()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_representative_plots() -> List[str]:
|
|
22
|
+
"""Get one representative plot from each category for demos."""
|
|
23
|
+
return [p for p in REPRESENTATIVES.values() if p in REGISTRY]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_plotter(name: str) -> Optional[Callable]:
|
|
27
|
+
"""Get plotter function by name."""
|
|
28
|
+
return REGISTRY.get(name)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# EOF
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Registry for demo plotter functions."""
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Callable, Dict
|
|
8
|
+
|
|
9
|
+
# Registry: plot_name -> plotter function
|
|
10
|
+
REGISTRY: Dict[str, Callable] = {}
|
|
11
|
+
|
|
12
|
+
# Get demo directory
|
|
13
|
+
_demo_dir = Path(__file__).parent
|
|
14
|
+
|
|
15
|
+
# Category subdirectories
|
|
16
|
+
_category_dirs = [
|
|
17
|
+
"line_curve",
|
|
18
|
+
"scatter_points",
|
|
19
|
+
"bar_categorical",
|
|
20
|
+
"distribution",
|
|
21
|
+
"image_matrix",
|
|
22
|
+
"contour_surface",
|
|
23
|
+
"spectral_signal",
|
|
24
|
+
"vector_flow",
|
|
25
|
+
"special",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
# Collect all plot_*.py files from subdirectories
|
|
29
|
+
_demo_files = []
|
|
30
|
+
for _cat_dir in _category_dirs:
|
|
31
|
+
_cat_path = _demo_dir / _cat_dir
|
|
32
|
+
if _cat_path.is_dir():
|
|
33
|
+
_demo_files.extend(sorted(_cat_path.glob("plot_*.py")))
|
|
34
|
+
|
|
35
|
+
# Import all demo functions into registry
|
|
36
|
+
for _file in _demo_files:
|
|
37
|
+
_module_name = _file.stem # e.g., plot_scatter
|
|
38
|
+
_plot_name = _module_name.replace("plot_", "") # e.g., scatter
|
|
39
|
+
_func_name = _module_name # e.g., plot_scatter
|
|
40
|
+
_cat_dir = _file.parent.name # e.g., scatter_points
|
|
41
|
+
try:
|
|
42
|
+
_module = importlib.import_module(
|
|
43
|
+
f".{_cat_dir}.{_module_name}", package=__name__.rsplit(".", 1)[0]
|
|
44
|
+
)
|
|
45
|
+
if hasattr(_module, _func_name):
|
|
46
|
+
REGISTRY[_plot_name] = getattr(_module, _func_name)
|
|
47
|
+
except ImportError as e:
|
|
48
|
+
print(f"Warning: Could not import {_cat_dir}.{_module_name}: {e}")
|
|
49
|
+
|
|
50
|
+
# EOF
|
|
@@ -16,8 +16,9 @@ def plot_plot(plt, rng, ax=None):
|
|
|
16
16
|
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
17
17
|
|
|
18
18
|
x = np.linspace(0, 2 * np.pi, 100)
|
|
19
|
-
ax.plot(x, np.sin(x), id="sin")
|
|
20
|
-
ax.plot(x, np.cos(x), id="cos")
|
|
19
|
+
ax.plot(x, np.sin(x), label="sin", id="sin")
|
|
20
|
+
ax.plot(x, np.cos(x), label="cos", id="cos")
|
|
21
|
+
ax.legend()
|
|
21
22
|
ax.set_xlabel("X")
|
|
22
23
|
ax.set_ylabel("Y")
|
|
23
24
|
ax.set_title("plot")
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
"""pie: pie chart demo."""
|
|
4
4
|
|
|
5
|
+
import matplotlib.pyplot as mpl_plt
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
def plot_pie(plt, rng, ax=None):
|
|
7
9
|
"""Pie chart demo.
|
|
@@ -15,7 +17,9 @@ def plot_pie(plt, rng, ax=None):
|
|
|
15
17
|
|
|
16
18
|
sizes = [35, 25, 20, 20]
|
|
17
19
|
labels = ["A", "B", "C", "D"]
|
|
18
|
-
|
|
20
|
+
# Get colors from current style's color cycle
|
|
21
|
+
colors = mpl_plt.rcParams["axes.prop_cycle"].by_key()["color"][:4]
|
|
22
|
+
ax.pie(sizes, labels=labels, colors=colors, id="pie")
|
|
19
23
|
ax.set_title("pie")
|
|
20
24
|
return fig, ax
|
|
21
25
|
|