scitex 2.3.0__py3-none-any.whl → 2.4.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.
Files changed (99) hide show
  1. scitex/ai/classification/reporters/reporter_utils/_Plotter.py +1 -1
  2. scitex/ai/plt/__init__.py +2 -2
  3. scitex/ai/plt/{_plot_conf_mat.py → _stx_conf_mat.py} +3 -3
  4. scitex/config/PriorityConfig.py +195 -0
  5. scitex/config/__init__.py +24 -0
  6. scitex/io/_save.py +125 -34
  7. scitex/io/_save_modules/_image.py +37 -20
  8. scitex/plt/__init__.py +470 -17
  9. scitex/plt/_subplots/_AxisWrapper.py +98 -50
  10. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +254 -124
  11. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +49 -8
  12. scitex/plt/_subplots/_SubplotsWrapper.py +76 -91
  13. scitex/plt/_subplots/_export_as_csv.py +127 -58
  14. scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +25 -16
  15. scitex/plt/_subplots/_export_as_csv_formatters/_format_contourf.py +54 -0
  16. scitex/plt/_subplots/_export_as_csv_formatters/_format_hexbin.py +41 -0
  17. scitex/plt/_subplots/_export_as_csv_formatters/_format_hist2d.py +41 -0
  18. scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow.py +59 -47
  19. scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +42 -0
  20. scitex/plt/_subplots/_export_as_csv_formatters/_format_pie.py +42 -0
  21. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +72 -35
  22. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_box.py +1 -1
  23. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +2 -2
  24. scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +53 -0
  25. scitex/plt/_subplots/_export_as_csv_formatters/_format_stem.py +42 -0
  26. scitex/plt/_subplots/_export_as_csv_formatters/_format_step.py +42 -0
  27. scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +48 -0
  28. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_conf_mat.py → _format_stx_conf_mat.py} +2 -2
  29. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_ecdf.py → _format_stx_ecdf.py} +2 -2
  30. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_fillv.py → _format_stx_fillv.py} +2 -2
  31. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_heatmap.py → _format_stx_heatmap.py} +2 -2
  32. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_image.py → _format_stx_image.py} +2 -2
  33. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_joyplot.py → _format_stx_joyplot.py} +2 -2
  34. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_line.py → _format_stx_line.py} +3 -3
  35. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_mean_ci.py → _format_stx_mean_ci.py} +2 -2
  36. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_mean_std.py → _format_stx_mean_std.py} +2 -2
  37. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_median_iqr.py → _format_stx_median_iqr.py} +2 -2
  38. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_raster.py → _format_stx_raster.py} +2 -2
  39. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_rectangle.py → _format_stx_rectangle.py} +1 -1
  40. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_scatter_hist.py → _format_stx_scatter_hist.py} +2 -2
  41. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_shaded_line.py → _format_stx_shaded_line.py} +2 -2
  42. scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_violin.py → _format_stx_violin.py} +2 -2
  43. scitex/plt/_subplots/_export_as_csv_formatters/verify_formatters.py +23 -23
  44. scitex/plt/ax/__init__.py +16 -15
  45. scitex/plt/ax/_plot/__init__.py +30 -30
  46. scitex/plt/ax/_plot/_add_fitted_line.py +65 -11
  47. scitex/plt/ax/_plot/_plot_statistical_shaded_line.py +104 -76
  48. scitex/plt/ax/_plot/{_plot_conf_mat.py → _stx_conf_mat.py} +10 -10
  49. scitex/plt/ax/_plot/_stx_ecdf.py +109 -0
  50. scitex/plt/ax/_plot/{_plot_fillv.py → _stx_fillv.py} +7 -7
  51. scitex/plt/ax/_plot/_stx_heatmap.py +366 -0
  52. scitex/plt/ax/_plot/{_plot_image.py → _stx_image.py} +1 -1
  53. scitex/plt/ax/_plot/_stx_joyplot.py +113 -0
  54. scitex/plt/ax/_plot/{_plot_raster.py → _stx_raster.py} +37 -25
  55. scitex/plt/ax/_plot/{_plot_rectangle.py → _stx_rectangle.py} +10 -9
  56. scitex/plt/ax/_plot/{_plot_scatter_hist.py → _stx_scatter_hist.py} +1 -1
  57. scitex/plt/ax/_plot/_stx_shaded_line.py +215 -0
  58. scitex/plt/ax/_plot/{_plot_violin.py → _stx_violin.py} +13 -6
  59. scitex/plt/ax/_style/__init__.py +3 -0
  60. scitex/plt/ax/_style/_style_barplot.py +13 -2
  61. scitex/plt/ax/_style/_style_boxplot.py +78 -32
  62. scitex/plt/ax/_style/_style_errorbar.py +17 -3
  63. scitex/plt/ax/_style/_style_scatter.py +17 -3
  64. scitex/plt/ax/_style/_style_violinplot.py +109 -0
  65. scitex/plt/color/_vizualize_colors.py +3 -3
  66. scitex/plt/styles/SCITEX_STYLE.yaml +104 -0
  67. scitex/plt/styles/__init__.py +57 -0
  68. scitex/plt/styles/_plot_defaults.py +209 -0
  69. scitex/plt/styles/_plot_postprocess.py +518 -0
  70. scitex/plt/styles/_style_loader.py +268 -0
  71. scitex/plt/styles/presets.py +208 -0
  72. scitex/plt/utils/_collect_figure_metadata.py +160 -18
  73. scitex/plt/utils/_colorbar.py +72 -10
  74. scitex/plt/utils/_configure_mpl.py +108 -52
  75. scitex/plt/utils/_crop.py +21 -7
  76. scitex/plt/utils/_figure_mm.py +21 -7
  77. scitex/stats/__init__.py +13 -1
  78. scitex/stats/_schema.py +578 -0
  79. scitex/stats/tests/__init__.py +13 -0
  80. scitex/stats/tests/correlation/__init__.py +13 -0
  81. scitex/stats/tests/correlation/_test_pearson.py +262 -0
  82. scitex/vis/__init__.py +6 -0
  83. scitex/vis/editor/__init__.py +23 -0
  84. scitex/vis/editor/_defaults.py +205 -0
  85. scitex/vis/editor/_edit.py +342 -0
  86. scitex/vis/editor/_mpl_editor.py +231 -0
  87. scitex/vis/editor/_tkinter_editor.py +466 -0
  88. scitex/vis/editor/_web_editor.py +1440 -0
  89. scitex/vis/model/plot_types.py +15 -15
  90. {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/METADATA +2 -1
  91. {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/RECORD +94 -67
  92. {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/WHEEL +1 -1
  93. scitex/plt/ax/_plot/_plot_ecdf.py +0 -84
  94. scitex/plt/ax/_plot/_plot_heatmap.py +0 -277
  95. scitex/plt/ax/_plot/_plot_joyplot.py +0 -77
  96. scitex/plt/ax/_plot/_plot_shaded_line.py +0 -142
  97. scitex/plt/presets.py +0 -224
  98. {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/entry_points.txt +0 -0
  99. {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,104 @@
1
+ # SciTeX Style Configuration
2
+ # ===========================
3
+ # Centralized style settings for publication-quality figures.
4
+ # Users can modify this file or create their own YAML file.
5
+ #
6
+ # Units:
7
+ # - *_mm: millimeters (converted to points internally)
8
+ # - *_pt: points (1 pt = 1/72 inch)
9
+ #
10
+ # Usage:
11
+ # from scitex.plt import load_style
12
+ # style = load_style() # Load default SCITEX_STYLE.yaml
13
+ # style = load_style("path/to/custom_style.yaml") # Load custom style
14
+ # fig, ax = stx.plt.subplots(**style)
15
+
16
+ # =============================================================================
17
+ # AXES DIMENSIONS
18
+ # =============================================================================
19
+ # Can be scalar (applies to all) or list matching axes.flat size
20
+ axes:
21
+ width_mm: 40 # Axes width in mm (scalar or list)
22
+ height_mm: 28 # Axes height in mm (scalar or list, 1:0.7 ratio)
23
+ thickness_mm: 0.2 # Spine line thickness in mm
24
+
25
+ # =============================================================================
26
+ # MARGINS AND SPACING (in mm)
27
+ # =============================================================================
28
+ margins:
29
+ left_mm: 20 # Left margin (large for labels, crop afterwards)
30
+ right_mm: 20 # Right margin (for colorbars)
31
+ bottom_mm: 20 # Bottom margin (for x-axis labels)
32
+ top_mm: 20 # Top margin (for titles)
33
+
34
+ spacing:
35
+ horizontal_mm: 8 # Horizontal spacing between axes
36
+ vertical_mm: 10 # Vertical spacing between axes
37
+
38
+ # =============================================================================
39
+ # FONT SIZES (in points)
40
+ # =============================================================================
41
+ fonts:
42
+ family: "Arial" # Font family (Arial for Nature-style)
43
+ axis_label_pt: 7 # X/Y axis label font size
44
+ tick_label_pt: 7 # Tick label font size
45
+ title_pt: 8 # Plot title font size
46
+ suptitle_pt: 8 # Super title font size
47
+ legend_pt: 6 # Legend font size
48
+ annotation_pt: 6 # Annotation text (stats, etc.)
49
+
50
+ # =============================================================================
51
+ # PADDING (in points)
52
+ # =============================================================================
53
+ padding:
54
+ label_pt: 0.5 # Axis label to axis distance (extremely tight)
55
+ tick_pt: 2.0 # Tick label to tick distance
56
+ title_pt: 1.0 # Title to axis top distance
57
+
58
+ # =============================================================================
59
+ # LINE THICKNESSES (in mm)
60
+ # =============================================================================
61
+ lines:
62
+ trace_mm: 0.2 # Plot line thickness
63
+ errorbar_mm: 0.2 # Error bar line thickness
64
+ errorbar_cap_mm: 0.8 # Error bar cap width
65
+ bar_edge_mm: 0.2 # Bar plot edge thickness
66
+ kde_mm: 0.2 # KDE line thickness
67
+ boxplot_mm: 0.2 # Boxplot line thickness
68
+ violin_mm: 0.2 # Violin plot line thickness
69
+ colorbar_mm: 0.2 # Colorbar outline thickness
70
+
71
+ # =============================================================================
72
+ # TICK MARKS (in mm)
73
+ # =============================================================================
74
+ ticks:
75
+ length_mm: 0.8 # Tick mark length
76
+ thickness_mm: 0.2 # Tick mark thickness
77
+ direction: "out" # Tick direction: "in", "out", or "inout"
78
+ n_ticks: 4 # Target number of ticks per axis (3-4)
79
+
80
+ # =============================================================================
81
+ # MARKERS (in mm)
82
+ # =============================================================================
83
+ markers:
84
+ size_mm: 0.8 # Default marker size
85
+ scatter_mm: 0.8 # Scatter plot marker size
86
+ edge_width_mm: 0.1 # Marker edge width
87
+
88
+ # =============================================================================
89
+ # OUTPUT SETTINGS
90
+ # =============================================================================
91
+ output:
92
+ dpi: 300 # Resolution for saving
93
+ transparent: true # Transparent background for cropping
94
+ format: "png" # Default output format
95
+
96
+ # =============================================================================
97
+ # BEHAVIOR FLAGS
98
+ # =============================================================================
99
+ behavior:
100
+ auto_scale_axes: true # Factor out powers of 10 from tick labels
101
+ hide_top_spine: true # Hide top spine
102
+ hide_right_spine: true # Hide right spine
103
+ grid: false # Show grid
104
+
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-12-01 21:00:00 (ywatanabe)"
4
+ # File: ./src/scitex/plt/styles/__init__.py
5
+
6
+ """SciTeX plot styling module.
7
+
8
+ This module centralizes all plot-specific default styling, including:
9
+ - Pre-processing: Default kwargs applied before matplotlib method calls
10
+ - Post-processing: Styling applied after matplotlib method calls
11
+ - Style configuration with priority resolution: direct → yaml → env → default
12
+
13
+ Usage:
14
+ from scitex.plt.styles import apply_plot_defaults, apply_plot_postprocess
15
+
16
+ # In AxisWrapper.__getattr__ wrapper:
17
+ apply_plot_defaults(method_name, kwargs, id_value, ax)
18
+ result = orig_method(*args, **kwargs)
19
+ apply_plot_postprocess(method_name, result, ax, kwargs)
20
+
21
+ # Style configuration
22
+ from scitex.plt.styles import SCITEX_STYLE, load_style
23
+ fig, ax = stx.plt.subplots(**SCITEX_STYLE)
24
+
25
+ # Custom YAML
26
+ style = load_style("path/to/my_style.yaml")
27
+ fig, ax = stx.plt.subplots(**style)
28
+ """
29
+
30
+ from ._plot_defaults import apply_plot_defaults
31
+ from ._plot_postprocess import apply_plot_postprocess
32
+ from .presets import (
33
+ SCITEX_STYLE,
34
+ STYLE,
35
+ load_style,
36
+ save_style,
37
+ set_style,
38
+ get_style,
39
+ resolve_style_value,
40
+ )
41
+
42
+ __all__ = [
43
+ # Styling functions
44
+ 'apply_plot_defaults',
45
+ 'apply_plot_postprocess',
46
+ # Style configuration
47
+ 'SCITEX_STYLE',
48
+ 'STYLE',
49
+ 'load_style',
50
+ 'save_style',
51
+ 'set_style',
52
+ 'get_style',
53
+ 'resolve_style_value',
54
+ ]
55
+
56
+
57
+ # EOF
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-12-01 10:00:00 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/plt/styles/_plot_defaults.py
5
+
6
+ """Pre-processing default kwargs for plot methods.
7
+
8
+ This module centralizes all default styling applied BEFORE matplotlib
9
+ methods are called. Each function modifies kwargs in-place.
10
+
11
+ Priority: direct kwarg → env var → YAML config → default
12
+
13
+ Style values use the key format from YAML (e.g., 'lines.trace_mm').
14
+ Env vars: SCITEX_PLT_LINES_TRACE_MM (prefix + dots→underscores + uppercase)
15
+ """
16
+
17
+ from scitex.plt.utils import mm_to_pt
18
+ from scitex.plt.styles.presets import resolve_style_value
19
+
20
+ # Default alpha for fill regions (0.3 = semi-transparent)
21
+ DEFAULT_FILL_ALPHA = 0.3
22
+
23
+
24
+ # ============================================================================
25
+ # Style helper function
26
+ # ============================================================================
27
+ def _get_style_value(key, default, style_dict=None):
28
+ """Get style value with priority: style_dict → active_style → env → yaml → default.
29
+
30
+ Args:
31
+ key: YAML-style key (e.g., 'lines.trace_mm')
32
+ default: Fallback default value
33
+ style_dict: Optional user-provided style dict (overrides all)
34
+
35
+ Returns:
36
+ Resolved style value
37
+ """
38
+ flat_key = _yaml_key_to_flat(key)
39
+
40
+ # Priority 1: User passed explicit style dict
41
+ if style_dict is not None and flat_key in style_dict:
42
+ return style_dict[flat_key]
43
+
44
+ # Priority 2: Check active style set via set_style()
45
+ from scitex.plt.styles.presets import _active_style
46
+ if _active_style is not None and flat_key in _active_style:
47
+ return _active_style[flat_key]
48
+
49
+ # Priority 3: Use resolve_style_value for: env → yaml → default
50
+ return resolve_style_value(key, None, default)
51
+
52
+
53
+ def _yaml_key_to_flat(key):
54
+ """Convert YAML key to flat SCITEX_STYLE key.
55
+
56
+ Examples:
57
+ 'lines.trace_mm' -> 'trace_thickness_mm'
58
+ 'markers.size_mm' -> 'marker_size_mm'
59
+ """
60
+ # Mapping from YAML keys to flat keys used in SCITEX_STYLE
61
+ mapping = {
62
+ 'lines.trace_mm': 'trace_thickness_mm',
63
+ 'lines.errorbar_mm': 'errorbar_thickness_mm',
64
+ 'lines.errorbar_cap_mm': 'errorbar_cap_width_mm',
65
+ 'markers.size_mm': 'marker_size_mm',
66
+ }
67
+ return mapping.get(key, key)
68
+
69
+
70
+ # ============================================================================
71
+ # Pre-processing functions
72
+ # ============================================================================
73
+ def apply_plot_defaults(method_name, kwargs, id_value=None, ax=None):
74
+ """Apply default kwargs for a plot method before calling matplotlib.
75
+
76
+ Args:
77
+ method_name: Name of the matplotlib method being called
78
+ kwargs: Keyword arguments dict (modified in-place)
79
+ id_value: Optional id passed to the method
80
+ ax: The matplotlib axes (for methods needing axis setup)
81
+
82
+ Returns:
83
+ Modified kwargs dict
84
+
85
+ Note:
86
+ Priority: direct kwarg → style dict → env var → yaml → default
87
+ Users can pass `style=dict` kwarg to override env/yaml defaults.
88
+ """
89
+ # Extract optional style dict (removes 'style' key from kwargs)
90
+ style_dict = kwargs.pop("style", None)
91
+
92
+ # Dispatch to method-specific defaults
93
+ if method_name == 'plot':
94
+ _apply_plot_line_defaults(kwargs, id_value, style_dict)
95
+ elif method_name in ('bar', 'barh'):
96
+ _apply_bar_defaults(kwargs, style_dict)
97
+ elif method_name == 'errorbar':
98
+ _apply_errorbar_defaults(kwargs, style_dict)
99
+ elif method_name in ('fill_between', 'fill_betweenx'):
100
+ _apply_fill_defaults(kwargs)
101
+ elif method_name in ('quiver', 'streamplot'):
102
+ _apply_vector_field_defaults(method_name, kwargs, ax, style_dict)
103
+ elif method_name == 'boxplot':
104
+ _apply_boxplot_defaults(kwargs)
105
+ elif method_name == 'violinplot':
106
+ _apply_violinplot_defaults(kwargs)
107
+
108
+ return kwargs
109
+
110
+
111
+ def _apply_plot_line_defaults(kwargs, id_value=None, style_dict=None):
112
+ """Apply defaults for ax.plot() method."""
113
+ line_width_mm = _get_style_value('lines.trace_mm', 0.2, style_dict)
114
+
115
+ # Default line width
116
+ if 'linewidth' not in kwargs and 'lw' not in kwargs:
117
+ kwargs['linewidth'] = mm_to_pt(line_width_mm)
118
+
119
+ # KDE-specific styling when id contains "kde"
120
+ if id_value and 'kde' in str(id_value).lower():
121
+ if 'linestyle' not in kwargs and 'ls' not in kwargs:
122
+ kwargs['linestyle'] = '--'
123
+ if 'color' not in kwargs and 'c' not in kwargs:
124
+ kwargs['color'] = 'black'
125
+
126
+
127
+ def _apply_bar_defaults(kwargs, style_dict=None):
128
+ """Apply defaults for ax.bar() and ax.barh() methods."""
129
+ line_width_mm = _get_style_value('lines.trace_mm', 0.2, style_dict)
130
+
131
+ # Set error bar line thickness
132
+ if 'error_kw' not in kwargs:
133
+ kwargs['error_kw'] = {}
134
+ if 'elinewidth' not in kwargs.get('error_kw', {}):
135
+ kwargs['error_kw']['elinewidth'] = mm_to_pt(line_width_mm)
136
+ if 'capthick' not in kwargs.get('error_kw', {}):
137
+ kwargs['error_kw']['capthick'] = mm_to_pt(line_width_mm)
138
+ # Set a temporary capsize that will be adjusted in post-processing
139
+ if 'capsize' not in kwargs:
140
+ kwargs['capsize'] = 5 # Placeholder, adjusted later to 33% of bar width
141
+
142
+
143
+ def _apply_errorbar_defaults(kwargs, style_dict=None):
144
+ """Apply defaults for ax.errorbar() method."""
145
+ line_width_mm = _get_style_value('lines.trace_mm', 0.2, style_dict)
146
+ cap_size_mm = _get_style_value('lines.errorbar_cap_mm', 0.8, style_dict)
147
+
148
+ if 'capsize' not in kwargs:
149
+ kwargs['capsize'] = mm_to_pt(cap_size_mm)
150
+ if 'capthick' not in kwargs:
151
+ kwargs['capthick'] = mm_to_pt(line_width_mm)
152
+ if 'elinewidth' not in kwargs:
153
+ kwargs['elinewidth'] = mm_to_pt(line_width_mm)
154
+
155
+
156
+ def _apply_fill_defaults(kwargs):
157
+ """Apply defaults for ax.fill_between() and ax.fill_betweenx() methods."""
158
+ if 'alpha' not in kwargs:
159
+ kwargs['alpha'] = DEFAULT_FILL_ALPHA # Transparent to see overlapping data
160
+
161
+
162
+ def _apply_vector_field_defaults(method_name, kwargs, ax, style_dict=None):
163
+ """Apply defaults for ax.quiver() and ax.streamplot() methods."""
164
+ line_width_mm = _get_style_value('lines.trace_mm', 0.2, style_dict)
165
+ marker_size_mm = _get_style_value('markers.size_mm', 0.8, style_dict)
166
+
167
+ # Set equal aspect ratio for proper vector display
168
+ if ax is not None:
169
+ ax.set_aspect('equal', adjustable='datalim')
170
+
171
+ if method_name == 'streamplot':
172
+ if 'arrowsize' not in kwargs:
173
+ # arrowsize is a scaling factor; scale relative to default
174
+ kwargs['arrowsize'] = mm_to_pt(marker_size_mm) / 3
175
+ if 'linewidth' not in kwargs:
176
+ kwargs['linewidth'] = mm_to_pt(line_width_mm)
177
+
178
+ elif method_name == 'quiver':
179
+ if 'width' not in kwargs:
180
+ kwargs['width'] = 0.003 # Narrow arrow shaft (axes fraction)
181
+ if 'headwidth' not in kwargs:
182
+ kwargs['headwidth'] = 3 # Head width relative to shaft
183
+ if 'headlength' not in kwargs:
184
+ kwargs['headlength'] = 4
185
+ if 'headaxislength' not in kwargs:
186
+ kwargs['headaxislength'] = 3.5
187
+
188
+
189
+ def _apply_boxplot_defaults(kwargs):
190
+ """Apply defaults for ax.boxplot() method."""
191
+ # Enable patch_artist for fillable boxes
192
+ if 'patch_artist' not in kwargs:
193
+ kwargs['patch_artist'] = True
194
+
195
+
196
+ def _apply_violinplot_defaults(kwargs):
197
+ """Apply defaults for ax.violinplot() method."""
198
+ # Default to showing boxplot overlay (can be disabled with boxplot=False)
199
+ # Store the boxplot setting for post-processing, then remove from kwargs
200
+ # so it doesn't get passed to matplotlib's violinplot
201
+ if 'boxplot' not in kwargs:
202
+ kwargs['boxplot'] = True # Default: add boxplot overlay
203
+
204
+ # Default to hiding extrema (min/max bars) when boxplot is shown
205
+ if 'showextrema' not in kwargs:
206
+ kwargs['showextrema'] = False
207
+
208
+
209
+ # EOF