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,178 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Convert style DotDict to subplots kwargs."""
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from ._dotdict import DotDict
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def to_subplots_kwargs(style: Optional["DotDict"] = None) -> Dict[str, Any]:
|
|
12
|
+
"""Convert style DotDict to kwargs for ps.subplots().
|
|
13
|
+
|
|
14
|
+
Uses YAML-compatible flattened key names as the single source of truth.
|
|
15
|
+
For example, YAML `fonts.axis_label_pt` becomes `fonts_axis_label_pt`.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
style : DotDict, optional
|
|
20
|
+
Style configuration. If None, uses current loaded style.
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
dict
|
|
25
|
+
Keyword arguments for ps.subplots() with YAML-compatible flattened keys.
|
|
26
|
+
|
|
27
|
+
Examples
|
|
28
|
+
--------
|
|
29
|
+
>>> style = load_style()
|
|
30
|
+
>>> kwargs = to_subplots_kwargs(style)
|
|
31
|
+
>>> fig, ax = ps.subplots(**kwargs)
|
|
32
|
+
"""
|
|
33
|
+
if style is None:
|
|
34
|
+
from ._style_loader import get_style
|
|
35
|
+
|
|
36
|
+
style = get_style()
|
|
37
|
+
|
|
38
|
+
# YAML-compatible flattened keys (single source of truth)
|
|
39
|
+
result = {
|
|
40
|
+
# Axes (axes.* in YAML)
|
|
41
|
+
"axes_width_mm": style.axes.width_mm,
|
|
42
|
+
"axes_height_mm": style.axes.height_mm,
|
|
43
|
+
"axes_thickness_mm": style.axes.thickness_mm,
|
|
44
|
+
# Margins (margins.* in YAML)
|
|
45
|
+
"margins_left_mm": style.margins.left_mm,
|
|
46
|
+
"margins_right_mm": style.margins.right_mm,
|
|
47
|
+
"margins_bottom_mm": style.margins.bottom_mm,
|
|
48
|
+
"margins_top_mm": style.margins.top_mm,
|
|
49
|
+
# Spacing (spacing.* in YAML)
|
|
50
|
+
"spacing_horizontal_mm": style.spacing.horizontal_mm,
|
|
51
|
+
"spacing_vertical_mm": style.spacing.vertical_mm,
|
|
52
|
+
# Ticks (ticks.* in YAML)
|
|
53
|
+
"ticks_length_mm": style.ticks.length_mm,
|
|
54
|
+
"ticks_thickness_mm": style.ticks.thickness_mm,
|
|
55
|
+
"ticks_direction": style.ticks.get("direction", "out"),
|
|
56
|
+
"ticks_n_ticks_min": style.ticks.get("n_ticks_min", 3),
|
|
57
|
+
"ticks_n_ticks_max": style.ticks.get("n_ticks_max", 4),
|
|
58
|
+
# Lines (lines.* in YAML)
|
|
59
|
+
"lines_trace_mm": style.lines.trace_mm,
|
|
60
|
+
"lines_errorbar_mm": style.lines.get("errorbar_mm", 0.2),
|
|
61
|
+
"lines_errorbar_cap_mm": style.lines.get("errorbar_cap_mm", 0.8),
|
|
62
|
+
# Markers (markers.* in YAML)
|
|
63
|
+
"markers_size_mm": style.markers.size_mm,
|
|
64
|
+
"markers_scatter_mm": style.markers.get("scatter_mm", style.markers.size_mm),
|
|
65
|
+
"markers_flier_mm": style.markers.get("flier_mm", style.markers.size_mm),
|
|
66
|
+
"markers_edge_width_mm": style.markers.get("edge_width_mm"),
|
|
67
|
+
# Boxplot (boxplot.* in YAML)
|
|
68
|
+
"boxplot_line_mm": style.get("boxplot", {}).get("line_mm", 0.2),
|
|
69
|
+
"boxplot_whisker_mm": style.get("boxplot", {}).get("whisker_mm", 0.2),
|
|
70
|
+
"boxplot_cap_mm": style.get("boxplot", {}).get("cap_mm", 0.2),
|
|
71
|
+
"boxplot_median_mm": style.get("boxplot", {}).get("median_mm", 0.2),
|
|
72
|
+
"boxplot_median_color": style.get("boxplot", {}).get("median_color", "black"),
|
|
73
|
+
"boxplot_flier_edge_mm": style.get("boxplot", {}).get("flier_edge_mm", 0.2),
|
|
74
|
+
# Violinplot (violinplot.* in YAML)
|
|
75
|
+
"violinplot_line_mm": style.get("violinplot", {}).get("line_mm", 0.2),
|
|
76
|
+
"violinplot_inner": style.get("violinplot", {}).get("inner", "box"),
|
|
77
|
+
"violinplot_box_width_mm": style.get("violinplot", {}).get("box_width_mm", 1.5),
|
|
78
|
+
"violinplot_whisker_mm": style.get("violinplot", {}).get("whisker_mm", 0.2),
|
|
79
|
+
"violinplot_median_mm": style.get("violinplot", {}).get("median_mm", 0.8),
|
|
80
|
+
# Barplot (barplot.* in YAML)
|
|
81
|
+
"barplot_edge_mm": style.get("barplot", {}).get("edge_mm", 0.2),
|
|
82
|
+
# Histogram (histogram.* in YAML)
|
|
83
|
+
"histogram_edge_mm": style.get("histogram", {}).get("edge_mm", 0.2),
|
|
84
|
+
# Pie chart (pie.* in YAML)
|
|
85
|
+
"pie_text_pt": style.get("pie", {}).get("text_pt", 6),
|
|
86
|
+
"pie_show_axes": style.get("pie", {}).get("show_axes", False),
|
|
87
|
+
# Imshow (imshow.* in YAML)
|
|
88
|
+
"imshow_show_axes": style.get("imshow", {}).get("show_axes", False),
|
|
89
|
+
"imshow_show_labels": style.get("imshow", {}).get("show_labels", False),
|
|
90
|
+
# Fonts (fonts.* in YAML)
|
|
91
|
+
"fonts_family": style.fonts.family,
|
|
92
|
+
"fonts_axis_label_pt": style.fonts.axis_label_pt,
|
|
93
|
+
"fonts_tick_label_pt": style.fonts.tick_label_pt,
|
|
94
|
+
"fonts_title_pt": style.fonts.title_pt,
|
|
95
|
+
"fonts_suptitle_pt": style.fonts.suptitle_pt,
|
|
96
|
+
"fonts_legend_pt": style.fonts.legend_pt,
|
|
97
|
+
"fonts_annotation_pt": style.fonts.get("annotation_pt", 6),
|
|
98
|
+
# Padding (padding.* in YAML)
|
|
99
|
+
"padding_label_pt": style.padding.label_pt,
|
|
100
|
+
"padding_tick_pt": style.padding.tick_pt,
|
|
101
|
+
"padding_title_pt": style.padding.title_pt,
|
|
102
|
+
# Output (output.* in YAML)
|
|
103
|
+
"output_dpi": style.output.dpi,
|
|
104
|
+
"output_transparent": style.output.get("transparent", True),
|
|
105
|
+
"output_format": style.output.get("format", "pdf"),
|
|
106
|
+
# Theme (theme.* in YAML)
|
|
107
|
+
"theme_mode": style.theme.mode,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# Add theme colors from preset if available
|
|
111
|
+
theme_mode = style.theme.mode
|
|
112
|
+
if "theme" in style and theme_mode in style.theme:
|
|
113
|
+
result["theme_colors"] = dict(style.theme[theme_mode])
|
|
114
|
+
|
|
115
|
+
# Add color palette if available
|
|
116
|
+
if "colors" in style and "palette" in style.colors:
|
|
117
|
+
result["color_palette"] = list(style.colors.palette)
|
|
118
|
+
|
|
119
|
+
# Add behavior settings (behavior.* in YAML)
|
|
120
|
+
if "behavior" in style:
|
|
121
|
+
behavior = style.behavior
|
|
122
|
+
if hasattr(behavior, "hide_top_spine"):
|
|
123
|
+
result["behavior_hide_top_spine"] = behavior.hide_top_spine
|
|
124
|
+
if hasattr(behavior, "hide_right_spine"):
|
|
125
|
+
result["behavior_hide_right_spine"] = behavior.hide_right_spine
|
|
126
|
+
if hasattr(behavior, "grid"):
|
|
127
|
+
result["behavior_grid"] = behavior.grid
|
|
128
|
+
if hasattr(behavior, "auto_scale_axes"):
|
|
129
|
+
result["behavior_auto_scale_axes"] = behavior.auto_scale_axes
|
|
130
|
+
if hasattr(behavior, "constrained_layout"):
|
|
131
|
+
result["behavior_constrained_layout"] = behavior.constrained_layout
|
|
132
|
+
|
|
133
|
+
# Legacy key aliases for backwards compatibility
|
|
134
|
+
result.update(_get_legacy_aliases(result))
|
|
135
|
+
|
|
136
|
+
return result
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _get_legacy_aliases(result: Dict[str, Any]) -> Dict[str, Any]:
|
|
140
|
+
"""Get legacy key aliases for backwards compatibility.
|
|
141
|
+
|
|
142
|
+
These allow existing code using old keys to still work.
|
|
143
|
+
"""
|
|
144
|
+
return {
|
|
145
|
+
"margin_left_mm": result["margins_left_mm"],
|
|
146
|
+
"margin_right_mm": result["margins_right_mm"],
|
|
147
|
+
"margin_bottom_mm": result["margins_bottom_mm"],
|
|
148
|
+
"margin_top_mm": result["margins_top_mm"],
|
|
149
|
+
"space_w_mm": result["spacing_horizontal_mm"],
|
|
150
|
+
"space_h_mm": result["spacing_vertical_mm"],
|
|
151
|
+
"tick_length_mm": result["ticks_length_mm"],
|
|
152
|
+
"tick_thickness_mm": result["ticks_thickness_mm"],
|
|
153
|
+
"n_ticks_min": result["ticks_n_ticks_min"],
|
|
154
|
+
"n_ticks_max": result["ticks_n_ticks_max"],
|
|
155
|
+
"trace_thickness_mm": result["lines_trace_mm"],
|
|
156
|
+
"marker_size_mm": result["markers_size_mm"],
|
|
157
|
+
"font_family": result["fonts_family"],
|
|
158
|
+
"axis_font_size_pt": result["fonts_axis_label_pt"],
|
|
159
|
+
"tick_font_size_pt": result["fonts_tick_label_pt"],
|
|
160
|
+
"title_font_size_pt": result["fonts_title_pt"],
|
|
161
|
+
"suptitle_font_size_pt": result["fonts_suptitle_pt"],
|
|
162
|
+
"legend_font_size_pt": result["fonts_legend_pt"],
|
|
163
|
+
"label_pad_pt": result["padding_label_pt"],
|
|
164
|
+
"tick_pad_pt": result["padding_tick_pt"],
|
|
165
|
+
"title_pad_pt": result["padding_title_pt"],
|
|
166
|
+
"dpi": result["output_dpi"],
|
|
167
|
+
"theme": result["theme_mode"],
|
|
168
|
+
"hide_top_spine": result.get("behavior_hide_top_spine", True),
|
|
169
|
+
"hide_right_spine": result.get("behavior_hide_right_spine", True),
|
|
170
|
+
"grid": result.get("behavior_grid", False),
|
|
171
|
+
"auto_scale_axes": result.get("behavior_auto_scale_axes", True),
|
|
172
|
+
"constrained_layout": result.get("behavior_constrained_layout", False),
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
__all__ = ["to_subplots_kwargs"]
|
|
177
|
+
|
|
178
|
+
# EOF
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Plot-specific style application for figrecipe."""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict
|
|
6
|
+
|
|
7
|
+
from matplotlib.axes import Axes
|
|
8
|
+
|
|
9
|
+
from .._utils._units import mm_to_pt
|
|
10
|
+
from ._fonts import check_font
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def apply_boxplot_style(ax: Axes, style: Dict[str, Any]) -> None:
|
|
14
|
+
"""Apply boxplot line width styling to existing boxplot elements.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
ax : matplotlib.axes.Axes
|
|
19
|
+
Target axes containing boxplot elements.
|
|
20
|
+
style : dict
|
|
21
|
+
Style dictionary with boxplot_* keys.
|
|
22
|
+
"""
|
|
23
|
+
from matplotlib.lines import Line2D
|
|
24
|
+
from matplotlib.patches import PathPatch
|
|
25
|
+
|
|
26
|
+
box_lw = mm_to_pt(style.get("boxplot_line_mm", 0.2))
|
|
27
|
+
whisker_lw = mm_to_pt(style.get("boxplot_whisker_mm", 0.2))
|
|
28
|
+
cap_lw = mm_to_pt(style.get("boxplot_cap_mm", 0.2))
|
|
29
|
+
median_lw = mm_to_pt(style.get("boxplot_median_mm", 0.2))
|
|
30
|
+
median_color = style.get("boxplot_median_color", "black")
|
|
31
|
+
flier_edge_lw = mm_to_pt(style.get("boxplot_flier_edge_mm", 0.2))
|
|
32
|
+
|
|
33
|
+
for child in ax.get_children():
|
|
34
|
+
if isinstance(child, PathPatch):
|
|
35
|
+
if child.get_edgecolor() is not None:
|
|
36
|
+
child.set_linewidth(box_lw)
|
|
37
|
+
|
|
38
|
+
elif isinstance(child, Line2D):
|
|
39
|
+
xdata = child.get_xdata()
|
|
40
|
+
ydata = child.get_ydata()
|
|
41
|
+
|
|
42
|
+
marker = child.get_marker()
|
|
43
|
+
linestyle = child.get_linestyle()
|
|
44
|
+
if marker and marker != "None" and linestyle in ("None", "", " "):
|
|
45
|
+
child.set_markeredgewidth(flier_edge_lw)
|
|
46
|
+
elif len(xdata) == 2 and len(ydata) == 2:
|
|
47
|
+
if ydata[0] == ydata[1]:
|
|
48
|
+
if linestyle == "-":
|
|
49
|
+
child.set_linewidth(median_lw)
|
|
50
|
+
if median_color:
|
|
51
|
+
child.set_color(median_color)
|
|
52
|
+
else:
|
|
53
|
+
child.set_linewidth(cap_lw)
|
|
54
|
+
elif xdata[0] == xdata[1]:
|
|
55
|
+
child.set_linewidth(whisker_lw)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def apply_violinplot_style(ax: Axes, style: Dict[str, Any]) -> None:
|
|
59
|
+
"""Apply violinplot line width styling to existing violinplot elements.
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
ax : matplotlib.axes.Axes
|
|
64
|
+
Target axes containing violinplot elements.
|
|
65
|
+
style : dict
|
|
66
|
+
Style dictionary with violinplot_* keys.
|
|
67
|
+
"""
|
|
68
|
+
from matplotlib.collections import LineCollection, PolyCollection
|
|
69
|
+
|
|
70
|
+
body_lw = mm_to_pt(style.get("violinplot_line_mm", 0.2))
|
|
71
|
+
whisker_lw = mm_to_pt(style.get("violinplot_whisker_mm", 0.2))
|
|
72
|
+
|
|
73
|
+
for child in ax.get_children():
|
|
74
|
+
if isinstance(child, PolyCollection):
|
|
75
|
+
child.set_linewidth(body_lw)
|
|
76
|
+
elif isinstance(child, LineCollection):
|
|
77
|
+
child.set_linewidth(whisker_lw)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def apply_barplot_style(ax: Axes, style: Dict[str, Any]) -> None:
|
|
81
|
+
"""Apply barplot edge styling to existing bar elements.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
ax : matplotlib.axes.Axes
|
|
86
|
+
Target axes containing bar elements.
|
|
87
|
+
style : dict
|
|
88
|
+
Style dictionary with barplot_* keys.
|
|
89
|
+
"""
|
|
90
|
+
from matplotlib.patches import Rectangle
|
|
91
|
+
|
|
92
|
+
edge_lw = mm_to_pt(style.get("barplot_edge_mm", 0.2))
|
|
93
|
+
|
|
94
|
+
for patch in ax.patches:
|
|
95
|
+
if isinstance(patch, Rectangle):
|
|
96
|
+
patch.set_linewidth(edge_lw)
|
|
97
|
+
patch.set_edgecolor("black")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def apply_histogram_style(ax: Axes, style: Dict[str, Any]) -> None:
|
|
101
|
+
"""Apply histogram edge styling to existing histogram elements.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
ax : matplotlib.axes.Axes
|
|
106
|
+
Target axes containing histogram elements.
|
|
107
|
+
style : dict
|
|
108
|
+
Style dictionary with histogram_* keys.
|
|
109
|
+
"""
|
|
110
|
+
from matplotlib.patches import Rectangle
|
|
111
|
+
|
|
112
|
+
edge_lw = mm_to_pt(style.get("histogram_edge_mm", 0.2))
|
|
113
|
+
|
|
114
|
+
for patch in ax.patches:
|
|
115
|
+
if isinstance(patch, Rectangle):
|
|
116
|
+
patch.set_linewidth(edge_lw)
|
|
117
|
+
patch.set_edgecolor("black")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def apply_pie_style(ax: Axes, style: Dict[str, Any]) -> None:
|
|
121
|
+
"""Apply pie chart styling to existing pie elements.
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
ax : matplotlib.axes.Axes
|
|
126
|
+
Target axes containing pie chart elements.
|
|
127
|
+
style : dict
|
|
128
|
+
Style dictionary with pie_* keys.
|
|
129
|
+
"""
|
|
130
|
+
from matplotlib.patches import Wedge
|
|
131
|
+
|
|
132
|
+
has_pie = any(isinstance(p, Wedge) for p in ax.patches)
|
|
133
|
+
if not has_pie:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
text_pt = style.get("pie_text_pt", 6)
|
|
137
|
+
show_axes = style.get("pie_show_axes", False)
|
|
138
|
+
font_family = check_font(style.get("font_family", "Arial"))
|
|
139
|
+
|
|
140
|
+
for text in ax.texts:
|
|
141
|
+
transform = text.get_transform()
|
|
142
|
+
if transform == ax.transAxes:
|
|
143
|
+
x, y = text.get_position()
|
|
144
|
+
if y > 1.0 or y < 0.0:
|
|
145
|
+
continue
|
|
146
|
+
text.set_fontsize(text_pt)
|
|
147
|
+
text.set_fontfamily(font_family)
|
|
148
|
+
|
|
149
|
+
if not show_axes:
|
|
150
|
+
ax.set_xticks([])
|
|
151
|
+
ax.set_yticks([])
|
|
152
|
+
ax.set_xticklabels([])
|
|
153
|
+
ax.set_yticklabels([])
|
|
154
|
+
for spine in ax.spines.values():
|
|
155
|
+
spine.set_visible(False)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def apply_matrix_style(ax: Axes, style: Dict[str, Any]) -> None:
|
|
159
|
+
"""Apply imshow/matshow/spy styling (hide axes if configured).
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
ax : matplotlib.axes.Axes
|
|
164
|
+
Target axes containing matrix plot elements.
|
|
165
|
+
style : dict
|
|
166
|
+
Style dictionary with imshow_*, matshow_*, spy_* keys.
|
|
167
|
+
"""
|
|
168
|
+
from matplotlib.image import AxesImage
|
|
169
|
+
|
|
170
|
+
has_image = any(isinstance(c, AxesImage) for c in ax.get_children())
|
|
171
|
+
if not has_image:
|
|
172
|
+
return
|
|
173
|
+
|
|
174
|
+
# Check if this is specgram (has xlabel or ylabel)
|
|
175
|
+
# Specgram typically has "Time" and "Frequency" labels
|
|
176
|
+
xlabel = ax.get_xlabel()
|
|
177
|
+
ylabel = ax.get_ylabel()
|
|
178
|
+
is_specgram = bool(xlabel or ylabel)
|
|
179
|
+
|
|
180
|
+
# Don't hide axes for specgram - it needs visible ticks
|
|
181
|
+
if is_specgram:
|
|
182
|
+
return
|
|
183
|
+
|
|
184
|
+
show_axes = style.get("imshow_show_axes", True)
|
|
185
|
+
show_labels = style.get("imshow_show_labels", True)
|
|
186
|
+
|
|
187
|
+
if not show_axes:
|
|
188
|
+
ax.set_xticks([])
|
|
189
|
+
ax.set_yticks([])
|
|
190
|
+
ax.set_xticklabels([])
|
|
191
|
+
ax.set_yticklabels([])
|
|
192
|
+
for spine in ax.spines.values():
|
|
193
|
+
spine.set_visible(False)
|
|
194
|
+
|
|
195
|
+
if not show_labels:
|
|
196
|
+
ax.set_xlabel("")
|
|
197
|
+
ax.set_ylabel("")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
__all__ = [
|
|
201
|
+
"apply_boxplot_style",
|
|
202
|
+
"apply_violinplot_style",
|
|
203
|
+
"apply_barplot_style",
|
|
204
|
+
"apply_histogram_style",
|
|
205
|
+
"apply_pie_style",
|
|
206
|
+
"apply_matrix_style",
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
# EOF
|