figrecipe 0.5.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 +220 -819
- 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 +29 -0
- figrecipe/_dev/_plotters.py +76 -0
- figrecipe/_dev/_run_demos.py +56 -0
- figrecipe/_dev/demo_plotters/__init__.py +64 -0
- 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/bar_categorical/plot_bar.py +25 -0
- figrecipe/_dev/demo_plotters/bar_categorical/plot_barh.py +25 -0
- figrecipe/_dev/demo_plotters/contour_surface/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_contour.py +30 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_contourf.py +29 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_tricontour.py +28 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_tricontourf.py +28 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_tripcolor.py +29 -0
- figrecipe/_dev/demo_plotters/contour_surface/plot_triplot.py +25 -0
- figrecipe/_dev/demo_plotters/distribution/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/distribution/plot_boxplot.py +24 -0
- figrecipe/_dev/demo_plotters/distribution/plot_ecdf.py +24 -0
- figrecipe/_dev/demo_plotters/distribution/plot_hist.py +24 -0
- figrecipe/_dev/demo_plotters/distribution/plot_hist2d.py +25 -0
- figrecipe/_dev/demo_plotters/distribution/plot_violinplot.py +25 -0
- figrecipe/_dev/demo_plotters/image_matrix/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_hexbin.py +25 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_imshow.py +23 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_matshow.py +23 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_pcolor.py +29 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_pcolormesh.py +29 -0
- figrecipe/_dev/demo_plotters/image_matrix/plot_spy.py +29 -0
- figrecipe/_dev/demo_plotters/line_curve/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_errorbar.py +28 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_fill.py +29 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_fill_between.py +30 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_fill_betweenx.py +28 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_plot.py +28 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_stackplot.py +29 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_stairs.py +27 -0
- figrecipe/_dev/demo_plotters/line_curve/plot_step.py +27 -0
- figrecipe/_dev/demo_plotters/scatter_points/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/scatter_points/plot_scatter.py +24 -0
- figrecipe/_dev/demo_plotters/special/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/special/plot_eventplot.py +25 -0
- figrecipe/_dev/demo_plotters/special/plot_loglog.py +27 -0
- figrecipe/_dev/demo_plotters/special/plot_pie.py +27 -0
- figrecipe/_dev/demo_plotters/special/plot_semilogx.py +27 -0
- figrecipe/_dev/demo_plotters/special/plot_semilogy.py +27 -0
- figrecipe/_dev/demo_plotters/special/plot_stem.py +27 -0
- figrecipe/_dev/demo_plotters/spectral_signal/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_acorr.py +24 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_angle_spectrum.py +28 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_cohere.py +29 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_csd.py +29 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_magnitude_spectrum.py +28 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_phase_spectrum.py +28 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_psd.py +29 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_specgram.py +30 -0
- figrecipe/_dev/demo_plotters/spectral_signal/plot_xcorr.py +25 -0
- figrecipe/_dev/demo_plotters/vector_flow/__init__.py +4 -0
- figrecipe/_dev/demo_plotters/vector_flow/plot_barbs.py +30 -0
- figrecipe/_dev/demo_plotters/vector_flow/plot_quiver.py +30 -0
- figrecipe/_dev/demo_plotters/vector_flow/plot_streamplot.py +30 -0
- figrecipe/_editor/__init__.py +278 -0
- 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 +258 -0
- 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/_overrides.py +318 -0
- figrecipe/_editor/_preferences.py +135 -0
- figrecipe/_editor/_render_overrides.py +480 -0
- figrecipe/_editor/_renderer.py +199 -0
- 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 +152 -0
- figrecipe/_editor/_templates/_html.py +502 -0
- 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 +33 -0
- figrecipe/_params/_PLOTTING_METHODS.py +58 -0
- figrecipe/_params/__init__.py +9 -0
- figrecipe/_recorder.py +92 -110
- 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/_seaborn.py +14 -9
- figrecipe/_serializer.py +2 -2
- figrecipe/_signatures/README.md +68 -0
- figrecipe/_signatures/__init__.py +12 -2
- figrecipe/_signatures/_kwargs.py +273 -0
- figrecipe/_signatures/_loader.py +114 -57
- figrecipe/_signatures/_parsing.py +147 -0
- figrecipe/_utils/__init__.py +6 -4
- figrecipe/_utils/_crop.py +10 -4
- figrecipe/_utils/_image_diff.py +37 -33
- figrecipe/_utils/_numpy_io.py +0 -1
- figrecipe/_utils/_units.py +11 -3
- figrecipe/_validator.py +12 -3
- figrecipe/_wrappers/_axes.py +193 -170
- 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 +277 -18
- figrecipe/_wrappers/_panel_labels.py +127 -0
- figrecipe/_wrappers/_plot_helpers.py +143 -0
- figrecipe/_wrappers/_violin_helpers.py +180 -0
- figrecipe/plt.py +0 -1
- figrecipe/pyplot.py +2 -1
- figrecipe/styles/__init__.py +12 -11
- 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 +60 -202
- figrecipe/styles/_style_loader.py +73 -121
- figrecipe/styles/_themes.py +151 -0
- figrecipe/styles/presets/MATPLOTLIB.yaml +95 -0
- figrecipe/styles/presets/SCITEX.yaml +181 -0
- figrecipe-0.7.4.dist-info/METADATA +429 -0
- figrecipe-0.7.4.dist-info/RECORD +188 -0
- figrecipe/_reproducer.py +0 -358
- figrecipe-0.5.0.dist-info/METADATA +0 -336
- figrecipe-0.5.0.dist-info/RECORD +0 -26
- {figrecipe-0.5.0.dist-info → figrecipe-0.7.4.dist-info}/WHEEL +0 -0
- {figrecipe-0.5.0.dist-info → figrecipe-0.7.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -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
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""bar: bar chart demo."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_bar(plt, rng, ax=None):
|
|
7
|
+
"""Bar chart demo.
|
|
8
|
+
|
|
9
|
+
Demonstrates: ax.bar()
|
|
10
|
+
"""
|
|
11
|
+
if ax is None:
|
|
12
|
+
fig, ax = plt.subplots()
|
|
13
|
+
else:
|
|
14
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
15
|
+
|
|
16
|
+
categories = ["A", "B", "C", "D", "E"]
|
|
17
|
+
values = rng.integers(1, 10, 5)
|
|
18
|
+
ax.bar(categories, values, id="bar")
|
|
19
|
+
ax.set_xlabel("Category")
|
|
20
|
+
ax.set_ylabel("Value")
|
|
21
|
+
ax.set_title("bar")
|
|
22
|
+
return fig, ax
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# EOF
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""barh: horizontal bar chart demo."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_barh(plt, rng, ax=None):
|
|
7
|
+
"""Horizontal bar chart demo.
|
|
8
|
+
|
|
9
|
+
Demonstrates: ax.barh()
|
|
10
|
+
"""
|
|
11
|
+
if ax is None:
|
|
12
|
+
fig, ax = plt.subplots()
|
|
13
|
+
else:
|
|
14
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
15
|
+
|
|
16
|
+
categories = ["A", "B", "C", "D", "E"]
|
|
17
|
+
values = rng.integers(1, 10, 5)
|
|
18
|
+
ax.barh(categories, values, id="barh")
|
|
19
|
+
ax.set_xlabel("Value")
|
|
20
|
+
ax.set_ylabel("Category")
|
|
21
|
+
ax.set_title("barh")
|
|
22
|
+
return fig, ax
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# EOF
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""contour: contour plot demo."""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def plot_contour(plt, rng, ax=None):
|
|
9
|
+
"""Contour plot demo.
|
|
10
|
+
|
|
11
|
+
Demonstrates: ax.contour()
|
|
12
|
+
"""
|
|
13
|
+
if ax is None:
|
|
14
|
+
fig, ax = plt.subplots()
|
|
15
|
+
else:
|
|
16
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
17
|
+
|
|
18
|
+
x = np.linspace(-3, 3, 50)
|
|
19
|
+
y = np.linspace(-3, 3, 50)
|
|
20
|
+
X, Y = np.meshgrid(x, y)
|
|
21
|
+
Z = np.exp(-(X**2 + Y**2))
|
|
22
|
+
cs = ax.contour(X, Y, Z, id="contour")
|
|
23
|
+
ax.clabel(cs)
|
|
24
|
+
ax.set_xlabel("X")
|
|
25
|
+
ax.set_ylabel("Y")
|
|
26
|
+
ax.set_title("contour")
|
|
27
|
+
return fig, ax
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# EOF
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""contourf: filled contour plot demo."""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def plot_contourf(plt, rng, ax=None):
|
|
9
|
+
"""Filled contour plot demo.
|
|
10
|
+
|
|
11
|
+
Demonstrates: ax.contourf()
|
|
12
|
+
"""
|
|
13
|
+
if ax is None:
|
|
14
|
+
fig, ax = plt.subplots()
|
|
15
|
+
else:
|
|
16
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
17
|
+
|
|
18
|
+
x = np.linspace(-3, 3, 50)
|
|
19
|
+
y = np.linspace(-3, 3, 50)
|
|
20
|
+
X, Y = np.meshgrid(x, y)
|
|
21
|
+
Z = np.exp(-(X**2 + Y**2))
|
|
22
|
+
ax.contourf(X, Y, Z, id="contourf")
|
|
23
|
+
ax.set_xlabel("X")
|
|
24
|
+
ax.set_ylabel("Y")
|
|
25
|
+
ax.set_title("contourf")
|
|
26
|
+
return fig, ax
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# EOF
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""tricontour: triangular contour demo."""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def plot_tricontour(plt, rng, ax=None):
|
|
9
|
+
"""Triangular contour demo.
|
|
10
|
+
|
|
11
|
+
Demonstrates: ax.tricontour()
|
|
12
|
+
"""
|
|
13
|
+
if ax is None:
|
|
14
|
+
fig, ax = plt.subplots()
|
|
15
|
+
else:
|
|
16
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
17
|
+
|
|
18
|
+
x = rng.uniform(0, 1, 50)
|
|
19
|
+
y = rng.uniform(0, 1, 50)
|
|
20
|
+
z = np.sin(x * 2 * np.pi) * np.cos(y * 2 * np.pi)
|
|
21
|
+
ax.tricontour(x, y, z, id="tricontour")
|
|
22
|
+
ax.set_xlabel("X")
|
|
23
|
+
ax.set_ylabel("Y")
|
|
24
|
+
ax.set_title("tricontour")
|
|
25
|
+
return fig, ax
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# EOF
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""tricontourf: filled triangular contour demo."""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def plot_tricontourf(plt, rng, ax=None):
|
|
9
|
+
"""Filled triangular contour demo.
|
|
10
|
+
|
|
11
|
+
Demonstrates: ax.tricontourf()
|
|
12
|
+
"""
|
|
13
|
+
if ax is None:
|
|
14
|
+
fig, ax = plt.subplots()
|
|
15
|
+
else:
|
|
16
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
17
|
+
|
|
18
|
+
x = rng.uniform(0, 1, 50)
|
|
19
|
+
y = rng.uniform(0, 1, 50)
|
|
20
|
+
z = np.sin(x * 2 * np.pi) * np.cos(y * 2 * np.pi)
|
|
21
|
+
ax.tricontourf(x, y, z, id="tricontourf")
|
|
22
|
+
ax.set_xlabel("X")
|
|
23
|
+
ax.set_ylabel("Y")
|
|
24
|
+
ax.set_title("tricontourf")
|
|
25
|
+
return fig, ax
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# EOF
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""tripcolor: unstructured triangular grid demo."""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def plot_tripcolor(plt, rng, ax=None):
|
|
9
|
+
"""Unstructured triangular grid demo.
|
|
10
|
+
|
|
11
|
+
Demonstrates: ax.tripcolor()
|
|
12
|
+
"""
|
|
13
|
+
if ax is None:
|
|
14
|
+
fig, ax = plt.subplots()
|
|
15
|
+
else:
|
|
16
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
17
|
+
|
|
18
|
+
# Create random triangulation
|
|
19
|
+
x = rng.uniform(0, 1, 30)
|
|
20
|
+
y = rng.uniform(0, 1, 30)
|
|
21
|
+
z = np.sin(x * 2 * np.pi) * np.cos(y * 2 * np.pi)
|
|
22
|
+
ax.tripcolor(x, y, z, id="tripcolor")
|
|
23
|
+
ax.set_xlabel("X")
|
|
24
|
+
ax.set_ylabel("Y")
|
|
25
|
+
ax.set_title("tripcolor")
|
|
26
|
+
return fig, ax
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# EOF
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""triplot: triangular mesh plot demo."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_triplot(plt, rng, ax=None):
|
|
7
|
+
"""Triangular mesh plot demo.
|
|
8
|
+
|
|
9
|
+
Demonstrates: ax.triplot()
|
|
10
|
+
"""
|
|
11
|
+
if ax is None:
|
|
12
|
+
fig, ax = plt.subplots()
|
|
13
|
+
else:
|
|
14
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
15
|
+
|
|
16
|
+
x = rng.uniform(0, 1, 20)
|
|
17
|
+
y = rng.uniform(0, 1, 20)
|
|
18
|
+
ax.triplot(x, y, id="triplot")
|
|
19
|
+
ax.set_xlabel("X")
|
|
20
|
+
ax.set_ylabel("Y")
|
|
21
|
+
ax.set_title("triplot")
|
|
22
|
+
return fig, ax
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# EOF
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""boxplot: box plot demo."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_boxplot(plt, rng, ax=None):
|
|
7
|
+
"""Box plot demo.
|
|
8
|
+
|
|
9
|
+
Demonstrates: ax.boxplot()
|
|
10
|
+
"""
|
|
11
|
+
if ax is None:
|
|
12
|
+
fig, ax = plt.subplots()
|
|
13
|
+
else:
|
|
14
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
15
|
+
|
|
16
|
+
data = [rng.normal(i, 1, 100) for i in range(4)]
|
|
17
|
+
ax.boxplot(data, tick_labels=["A", "B", "C", "D"], id="boxplot")
|
|
18
|
+
ax.set_xlabel("Group")
|
|
19
|
+
ax.set_ylabel("Value")
|
|
20
|
+
ax.set_title("boxplot")
|
|
21
|
+
return fig, ax
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# EOF
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""ecdf: empirical CDF demo."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_ecdf(plt, rng, ax=None):
|
|
7
|
+
"""Empirical CDF demo.
|
|
8
|
+
|
|
9
|
+
Demonstrates: ax.ecdf()
|
|
10
|
+
"""
|
|
11
|
+
if ax is None:
|
|
12
|
+
fig, ax = plt.subplots()
|
|
13
|
+
else:
|
|
14
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
15
|
+
|
|
16
|
+
data = rng.normal(0, 1, 100)
|
|
17
|
+
ax.ecdf(data, id="ecdf")
|
|
18
|
+
ax.set_xlabel("Value")
|
|
19
|
+
ax.set_ylabel("Cumulative Probability")
|
|
20
|
+
ax.set_title("ecdf")
|
|
21
|
+
return fig, ax
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# EOF
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""hist: histogram demo."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_hist(plt, rng, ax=None):
|
|
7
|
+
"""Histogram demo.
|
|
8
|
+
|
|
9
|
+
Demonstrates: ax.hist()
|
|
10
|
+
"""
|
|
11
|
+
if ax is None:
|
|
12
|
+
fig, ax = plt.subplots()
|
|
13
|
+
else:
|
|
14
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
15
|
+
|
|
16
|
+
data = rng.normal(0, 1, 500)
|
|
17
|
+
ax.hist(data, bins=30, id="hist")
|
|
18
|
+
ax.set_xlabel("Value")
|
|
19
|
+
ax.set_ylabel("Frequency")
|
|
20
|
+
ax.set_title("hist")
|
|
21
|
+
return fig, ax
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# EOF
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""hist2d: 2D histogram demo."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_hist2d(plt, rng, ax=None):
|
|
7
|
+
"""2D histogram demo.
|
|
8
|
+
|
|
9
|
+
Demonstrates: ax.hist2d()
|
|
10
|
+
"""
|
|
11
|
+
if ax is None:
|
|
12
|
+
fig, ax = plt.subplots()
|
|
13
|
+
else:
|
|
14
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
15
|
+
|
|
16
|
+
x = rng.normal(0, 1, 1000)
|
|
17
|
+
y = rng.normal(0, 1, 1000)
|
|
18
|
+
ax.hist2d(x, y, id="hist2d")
|
|
19
|
+
ax.set_xlabel("X")
|
|
20
|
+
ax.set_ylabel("Y")
|
|
21
|
+
ax.set_title("hist2d")
|
|
22
|
+
return fig, ax
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# EOF
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""violinplot: violin plot demo."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_violinplot(plt, rng, ax=None):
|
|
7
|
+
"""Violin plot demo.
|
|
8
|
+
|
|
9
|
+
Demonstrates: ax.violinplot()
|
|
10
|
+
"""
|
|
11
|
+
if ax is None:
|
|
12
|
+
fig, ax = plt.subplots()
|
|
13
|
+
else:
|
|
14
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
15
|
+
|
|
16
|
+
data = [rng.normal(i, 1, 100) for i in range(4)]
|
|
17
|
+
# Modern style: show box inside (default from SCITEX style)
|
|
18
|
+
ax.violinplot(data, id="violinplot")
|
|
19
|
+
ax.set_xlabel("Group")
|
|
20
|
+
ax.set_ylabel("Value")
|
|
21
|
+
ax.set_title("violinplot")
|
|
22
|
+
return fig, ax
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# EOF
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""hexbin: hexagonal binning demo."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def plot_hexbin(plt, rng, ax=None):
|
|
7
|
+
"""Hexagonal binning demo.
|
|
8
|
+
|
|
9
|
+
Demonstrates: ax.hexbin()
|
|
10
|
+
"""
|
|
11
|
+
if ax is None:
|
|
12
|
+
fig, ax = plt.subplots()
|
|
13
|
+
else:
|
|
14
|
+
fig = ax.get_figure() if hasattr(ax, "get_figure") else ax.fig
|
|
15
|
+
|
|
16
|
+
x = rng.normal(0, 1, 1000)
|
|
17
|
+
y = rng.normal(0, 1, 1000)
|
|
18
|
+
ax.hexbin(x, y, id="hexbin")
|
|
19
|
+
ax.set_xlabel("X")
|
|
20
|
+
ax.set_ylabel("Y")
|
|
21
|
+
ax.set_title("hexbin")
|
|
22
|
+
return fig, ax
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# EOF
|