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.
- scitex/ai/classification/reporters/reporter_utils/_Plotter.py +1 -1
- scitex/ai/plt/__init__.py +2 -2
- scitex/ai/plt/{_plot_conf_mat.py → _stx_conf_mat.py} +3 -3
- scitex/config/PriorityConfig.py +195 -0
- scitex/config/__init__.py +24 -0
- scitex/io/_save.py +125 -34
- scitex/io/_save_modules/_image.py +37 -20
- scitex/plt/__init__.py +470 -17
- scitex/plt/_subplots/_AxisWrapper.py +98 -50
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +254 -124
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +49 -8
- scitex/plt/_subplots/_SubplotsWrapper.py +76 -91
- scitex/plt/_subplots/_export_as_csv.py +127 -58
- scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +25 -16
- scitex/plt/_subplots/_export_as_csv_formatters/_format_contourf.py +54 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_hexbin.py +41 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_hist2d.py +41 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow.py +59 -47
- scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +42 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_pie.py +42 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +72 -35
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_box.py +1 -1
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +53 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stem.py +42 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_step.py +42 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +48 -0
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_conf_mat.py → _format_stx_conf_mat.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_ecdf.py → _format_stx_ecdf.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_fillv.py → _format_stx_fillv.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_heatmap.py → _format_stx_heatmap.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_image.py → _format_stx_image.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_joyplot.py → _format_stx_joyplot.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_line.py → _format_stx_line.py} +3 -3
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_mean_ci.py → _format_stx_mean_ci.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_mean_std.py → _format_stx_mean_std.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_median_iqr.py → _format_stx_median_iqr.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_raster.py → _format_stx_raster.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_rectangle.py → _format_stx_rectangle.py} +1 -1
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_scatter_hist.py → _format_stx_scatter_hist.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_shaded_line.py → _format_stx_shaded_line.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/{_format_plot_violin.py → _format_stx_violin.py} +2 -2
- scitex/plt/_subplots/_export_as_csv_formatters/verify_formatters.py +23 -23
- scitex/plt/ax/__init__.py +16 -15
- scitex/plt/ax/_plot/__init__.py +30 -30
- scitex/plt/ax/_plot/_add_fitted_line.py +65 -11
- scitex/plt/ax/_plot/_plot_statistical_shaded_line.py +104 -76
- scitex/plt/ax/_plot/{_plot_conf_mat.py → _stx_conf_mat.py} +10 -10
- scitex/plt/ax/_plot/_stx_ecdf.py +109 -0
- scitex/plt/ax/_plot/{_plot_fillv.py → _stx_fillv.py} +7 -7
- scitex/plt/ax/_plot/_stx_heatmap.py +366 -0
- scitex/plt/ax/_plot/{_plot_image.py → _stx_image.py} +1 -1
- scitex/plt/ax/_plot/_stx_joyplot.py +113 -0
- scitex/plt/ax/_plot/{_plot_raster.py → _stx_raster.py} +37 -25
- scitex/plt/ax/_plot/{_plot_rectangle.py → _stx_rectangle.py} +10 -9
- scitex/plt/ax/_plot/{_plot_scatter_hist.py → _stx_scatter_hist.py} +1 -1
- scitex/plt/ax/_plot/_stx_shaded_line.py +215 -0
- scitex/plt/ax/_plot/{_plot_violin.py → _stx_violin.py} +13 -6
- scitex/plt/ax/_style/__init__.py +3 -0
- scitex/plt/ax/_style/_style_barplot.py +13 -2
- scitex/plt/ax/_style/_style_boxplot.py +78 -32
- scitex/plt/ax/_style/_style_errorbar.py +17 -3
- scitex/plt/ax/_style/_style_scatter.py +17 -3
- scitex/plt/ax/_style/_style_violinplot.py +109 -0
- scitex/plt/color/_vizualize_colors.py +3 -3
- scitex/plt/styles/SCITEX_STYLE.yaml +104 -0
- scitex/plt/styles/__init__.py +57 -0
- scitex/plt/styles/_plot_defaults.py +209 -0
- scitex/plt/styles/_plot_postprocess.py +518 -0
- scitex/plt/styles/_style_loader.py +268 -0
- scitex/plt/styles/presets.py +208 -0
- scitex/plt/utils/_collect_figure_metadata.py +160 -18
- scitex/plt/utils/_colorbar.py +72 -10
- scitex/plt/utils/_configure_mpl.py +108 -52
- scitex/plt/utils/_crop.py +21 -7
- scitex/plt/utils/_figure_mm.py +21 -7
- scitex/stats/__init__.py +13 -1
- scitex/stats/_schema.py +578 -0
- scitex/stats/tests/__init__.py +13 -0
- scitex/stats/tests/correlation/__init__.py +13 -0
- scitex/stats/tests/correlation/_test_pearson.py +262 -0
- scitex/vis/__init__.py +6 -0
- scitex/vis/editor/__init__.py +23 -0
- scitex/vis/editor/_defaults.py +205 -0
- scitex/vis/editor/_edit.py +342 -0
- scitex/vis/editor/_mpl_editor.py +231 -0
- scitex/vis/editor/_tkinter_editor.py +466 -0
- scitex/vis/editor/_web_editor.py +1440 -0
- scitex/vis/model/plot_types.py +15 -15
- {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/METADATA +2 -1
- {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/RECORD +94 -67
- {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/WHEEL +1 -1
- scitex/plt/ax/_plot/_plot_ecdf.py +0 -84
- scitex/plt/ax/_plot/_plot_heatmap.py +0 -277
- scitex/plt/ax/_plot/_plot_joyplot.py +0 -77
- scitex/plt/ax/_plot/_plot_shaded_line.py +0 -142
- scitex/plt/presets.py +0 -224
- {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/entry_points.txt +0 -0
- {scitex-2.3.0.dist-info → scitex-2.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -24,6 +24,7 @@ def sns_copy_doc(func):
|
|
|
24
24
|
def wrapper(self, *args, **kwargs):
|
|
25
25
|
return func(self, *args, **kwargs)
|
|
26
26
|
|
|
27
|
+
# Extract the seaborn method name (e.g., sns_boxplot -> boxplot)
|
|
27
28
|
wrapper.__doc__ = getattr(sns, func.__name__.split("sns_")[-1]).__doc__
|
|
28
29
|
return wrapper
|
|
29
30
|
|
|
@@ -33,6 +34,7 @@ class SeabornMixin:
|
|
|
33
34
|
def _sns_base(
|
|
34
35
|
self, method_name, *args, track=True, track_obj=None, id=None, **kwargs
|
|
35
36
|
):
|
|
37
|
+
# Extract seaborn method name (e.g., sns_boxplot -> boxplot)
|
|
36
38
|
sns_method_name = method_name.split("sns_")[-1]
|
|
37
39
|
|
|
38
40
|
with self._no_tracking():
|
|
@@ -54,19 +56,34 @@ class SeabornMixin:
|
|
|
54
56
|
|
|
55
57
|
try:
|
|
56
58
|
with warnings.catch_warnings():
|
|
57
|
-
warnings.filterwarnings('ignore',
|
|
59
|
+
warnings.filterwarnings('ignore',
|
|
58
60
|
message='.*categorical units.*parsable as floats or dates.*',
|
|
59
61
|
category=UserWarning)
|
|
60
62
|
warnings.filterwarnings('ignore',
|
|
61
63
|
message='.*Using categorical units.*',
|
|
62
64
|
module='matplotlib.*')
|
|
63
65
|
warnings.simplefilter('ignore', UserWarning)
|
|
64
|
-
|
|
66
|
+
|
|
65
67
|
self._axis_mpl = sns_plot_fn(ax=self._axis_mpl, *args, **kwargs)
|
|
66
68
|
finally:
|
|
67
69
|
# Restore original logging level
|
|
68
70
|
mpl_logger.setLevel(original_level)
|
|
69
71
|
|
|
72
|
+
# Post-processing: Set KDE line style for histplot with kde=True
|
|
73
|
+
if sns_method_name == 'histplot' and kwargs.get('kde', False):
|
|
74
|
+
from scitex.plt.utils import mm_to_pt
|
|
75
|
+
kde_lw = mm_to_pt(0.2) # 0.2mm for KDE lines
|
|
76
|
+
# KDE lines are added as Line2D objects after the histogram
|
|
77
|
+
for line in self._axis_mpl.get_lines():
|
|
78
|
+
line.set_linewidth(kde_lw)
|
|
79
|
+
line.set_color('black') # Black KDE line
|
|
80
|
+
line.set_linestyle('--') # Dashed line
|
|
81
|
+
|
|
82
|
+
# Post-processing: Set alpha to 1.0 for histplot bars if not specified
|
|
83
|
+
if sns_method_name == 'histplot' and 'alpha' not in kwargs:
|
|
84
|
+
for patch in self._axis_mpl.patches:
|
|
85
|
+
patch.set_alpha(1.0)
|
|
86
|
+
|
|
70
87
|
# Track the plot if required
|
|
71
88
|
track_obj = track_obj if track_obj is not None else args
|
|
72
89
|
# Create a tracked_dict with appropriate structure
|
|
@@ -80,7 +97,7 @@ class SeabornMixin:
|
|
|
80
97
|
"""Formats data passed to sns functions with (data=data, x=x, y=y) keyword arguments"""
|
|
81
98
|
df = kwargs.get("data")
|
|
82
99
|
x, y, hue = kwargs.get("x"), kwargs.get("y"), kwargs.get("hue")
|
|
83
|
-
|
|
100
|
+
|
|
84
101
|
track_obj = self._sns_prepare_xyhue(df, x, y, hue) if df is not None else None
|
|
85
102
|
self._sns_base(
|
|
86
103
|
method_name,
|
|
@@ -160,6 +177,27 @@ class SeabornMixin:
|
|
|
160
177
|
self._sns_base_xyhue(
|
|
161
178
|
"sns_boxplot", data=data, x=x, y=y, track=track, id=id, **kwargs
|
|
162
179
|
)
|
|
180
|
+
|
|
181
|
+
# Post-processing: Style boxplot with black medians
|
|
182
|
+
from scitex.plt.utils import mm_to_pt
|
|
183
|
+
lw_pt = mm_to_pt(0.2)
|
|
184
|
+
|
|
185
|
+
# Find and style boxplot lines (medians are typically the lines inside boxes)
|
|
186
|
+
for line in self._axis_mpl.get_lines():
|
|
187
|
+
# Style all lines to have consistent width
|
|
188
|
+
line.set_linewidth(lw_pt)
|
|
189
|
+
# Medians in seaborn boxplots are colored by default
|
|
190
|
+
# Check if this is a median line (horizontal, short)
|
|
191
|
+
xdata = line.get_xdata()
|
|
192
|
+
ydata = line.get_ydata()
|
|
193
|
+
if len(xdata) == 2 and len(ydata) == 2:
|
|
194
|
+
# Horizontal line (median or whisker cap)
|
|
195
|
+
if ydata[0] == ydata[1]:
|
|
196
|
+
x_span = abs(xdata[1] - xdata[0])
|
|
197
|
+
# Medians have smaller span than whisker caps
|
|
198
|
+
if x_span < 0.4: # Typical median line span
|
|
199
|
+
line.set_color('black')
|
|
200
|
+
|
|
163
201
|
if strip:
|
|
164
202
|
strip_kwargs = kwargs.copy()
|
|
165
203
|
strip_kwargs.pop("notch", None) # Remove boxplot-specific kwargs
|
|
@@ -280,27 +318,30 @@ class SeabornMixin:
|
|
|
280
318
|
id=None,
|
|
281
319
|
**kwargs,
|
|
282
320
|
):
|
|
283
|
-
|
|
284
|
-
|
|
321
|
+
# Remove hue from kwargs before passing to stx_kde
|
|
322
|
+
hue_col = kwargs.pop("hue", None)
|
|
323
|
+
|
|
324
|
+
if hue_col:
|
|
325
|
+
hues = data[hue_col]
|
|
285
326
|
|
|
286
327
|
if x is not None:
|
|
287
328
|
lim = xlim
|
|
288
329
|
for hue in np.unique(hues):
|
|
289
330
|
_data = data.loc[hues == hue, x]
|
|
290
|
-
self.
|
|
331
|
+
self.stx_kde(_data, xlim=lim, label=hue, id=hue, **kwargs)
|
|
291
332
|
|
|
292
333
|
if y is not None:
|
|
293
334
|
lim = ylim
|
|
294
335
|
for hue in np.unique(hues):
|
|
295
336
|
_data = data.loc[hues == hue, y]
|
|
296
|
-
self.
|
|
337
|
+
self.stx_kde(_data, xlim=lim, label=hue, id=hue, **kwargs)
|
|
297
338
|
|
|
298
339
|
else:
|
|
299
340
|
if x is not None:
|
|
300
341
|
_data, lim = data[x], xlim
|
|
301
342
|
if y is not None:
|
|
302
343
|
_data, lim = data[y], ylim
|
|
303
|
-
self.
|
|
344
|
+
self.stx_kde(_data, xlim=lim, **kwargs)
|
|
304
345
|
|
|
305
346
|
@sns_copy_doc
|
|
306
347
|
def sns_pairplot(self, *args, track=True, id=None, **kwargs):
|
|
@@ -93,18 +93,19 @@ class SubplotsWrapper:
|
|
|
93
93
|
sharey=False,
|
|
94
94
|
constrained_layout=None,
|
|
95
95
|
# MM-control parameters (unified style system)
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
axes_width_mm=None,
|
|
97
|
+
axes_height_mm=None,
|
|
98
98
|
margin_left_mm=None,
|
|
99
99
|
margin_right_mm=None,
|
|
100
100
|
margin_bottom_mm=None,
|
|
101
101
|
margin_top_mm=None,
|
|
102
102
|
space_w_mm=None,
|
|
103
103
|
space_h_mm=None,
|
|
104
|
-
|
|
104
|
+
axes_thickness_mm=None,
|
|
105
105
|
tick_length_mm=None,
|
|
106
106
|
tick_thickness_mm=None,
|
|
107
107
|
trace_thickness_mm=None,
|
|
108
|
+
marker_size_mm=None,
|
|
108
109
|
axis_font_size_pt=None,
|
|
109
110
|
tick_font_size_pt=None,
|
|
110
111
|
title_font_size_pt=None,
|
|
@@ -114,7 +115,7 @@ class SubplotsWrapper:
|
|
|
114
115
|
mode=None,
|
|
115
116
|
dpi=None,
|
|
116
117
|
styles=None, # List of style dicts for per-axes control
|
|
117
|
-
transparent=
|
|
118
|
+
transparent=None, # Transparent background (default: from SCITEX_STYLE.yaml)
|
|
118
119
|
**kwargs
|
|
119
120
|
):
|
|
120
121
|
"""
|
|
@@ -133,9 +134,9 @@ class SubplotsWrapper:
|
|
|
133
134
|
|
|
134
135
|
MM-Control Parameters (Unified Style System)
|
|
135
136
|
---------------------------------------------
|
|
136
|
-
|
|
137
|
+
axes_width_mm : float or list, optional
|
|
137
138
|
Axes width in mm (single value for all, or list for each)
|
|
138
|
-
|
|
139
|
+
axes_height_mm : float or list, optional
|
|
139
140
|
Axes height in mm (single value for all, or list for each)
|
|
140
141
|
margin_left_mm : float, optional
|
|
141
142
|
Left margin in mm (default: 5.0)
|
|
@@ -149,7 +150,7 @@ class SubplotsWrapper:
|
|
|
149
150
|
Horizontal spacing between axes in mm (default: 3.0)
|
|
150
151
|
space_h_mm : float, optional
|
|
151
152
|
Vertical spacing between axes in mm (default: 3.0)
|
|
152
|
-
|
|
153
|
+
axes_thickness_mm : float, optional
|
|
153
154
|
Axes spine thickness in mm
|
|
154
155
|
tick_length_mm : float, optional
|
|
155
156
|
Tick length in mm
|
|
@@ -185,9 +186,9 @@ class SubplotsWrapper:
|
|
|
185
186
|
Single axes with style:
|
|
186
187
|
|
|
187
188
|
>>> fig, ax = stx.plt.subplots(
|
|
188
|
-
...
|
|
189
|
-
...
|
|
190
|
-
...
|
|
189
|
+
... axes_width_mm=30,
|
|
190
|
+
... axes_height_mm=21,
|
|
191
|
+
... axes_thickness_mm=0.2,
|
|
191
192
|
... tick_length_mm=0.8,
|
|
192
193
|
... mode='publication'
|
|
193
194
|
... )
|
|
@@ -196,8 +197,8 @@ class SubplotsWrapper:
|
|
|
196
197
|
|
|
197
198
|
>>> fig, axes = stx.plt.subplots(
|
|
198
199
|
... nrows=2, ncols=3,
|
|
199
|
-
...
|
|
200
|
-
...
|
|
200
|
+
... axes_width_mm=30,
|
|
201
|
+
... axes_height_mm=21,
|
|
201
202
|
... space_w_mm=3,
|
|
202
203
|
... space_h_mm=3,
|
|
203
204
|
... mode='publication'
|
|
@@ -206,41 +207,65 @@ class SubplotsWrapper:
|
|
|
206
207
|
Using style preset:
|
|
207
208
|
|
|
208
209
|
>>> NATURE_STYLE = {
|
|
209
|
-
... '
|
|
210
|
-
... '
|
|
211
|
-
... '
|
|
210
|
+
... 'axes_width_mm': 30,
|
|
211
|
+
... 'axes_height_mm': 21,
|
|
212
|
+
... 'axes_thickness_mm': 0.2,
|
|
212
213
|
... 'tick_length_mm': 0.8,
|
|
213
214
|
... }
|
|
214
215
|
>>> fig, ax = stx.plt.subplots(**NATURE_STYLE)
|
|
215
216
|
"""
|
|
216
217
|
|
|
217
|
-
#
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
218
|
+
# Use resolve_style_value for priority: direct → yaml → env → default
|
|
219
|
+
from scitex.plt.styles import resolve_style_value as _resolve, SCITEX_STYLE as _S
|
|
220
|
+
|
|
221
|
+
# Resolve all style values with proper priority chain
|
|
222
|
+
axes_width_mm = _resolve('axes.width_mm', axes_width_mm, _S.get('axes_width_mm'))
|
|
223
|
+
axes_height_mm = _resolve('axes.height_mm', axes_height_mm, _S.get('axes_height_mm'))
|
|
224
|
+
margin_left_mm = _resolve('margins.left_mm', margin_left_mm, _S.get('margin_left_mm'))
|
|
225
|
+
margin_right_mm = _resolve('margins.right_mm', margin_right_mm, _S.get('margin_right_mm'))
|
|
226
|
+
margin_bottom_mm = _resolve('margins.bottom_mm', margin_bottom_mm, _S.get('margin_bottom_mm'))
|
|
227
|
+
margin_top_mm = _resolve('margins.top_mm', margin_top_mm, _S.get('margin_top_mm'))
|
|
228
|
+
space_w_mm = _resolve('spacing.horizontal_mm', space_w_mm, _S.get('space_w_mm'))
|
|
229
|
+
space_h_mm = _resolve('spacing.vertical_mm', space_h_mm, _S.get('space_h_mm'))
|
|
230
|
+
axes_thickness_mm = _resolve('axes.thickness_mm', axes_thickness_mm, _S.get('axes_thickness_mm'))
|
|
231
|
+
tick_length_mm = _resolve('ticks.length_mm', tick_length_mm, _S.get('tick_length_mm'))
|
|
232
|
+
tick_thickness_mm = _resolve('ticks.thickness_mm', tick_thickness_mm, _S.get('tick_thickness_mm'))
|
|
233
|
+
trace_thickness_mm = _resolve('lines.trace_mm', trace_thickness_mm, _S.get('trace_thickness_mm'))
|
|
234
|
+
marker_size_mm = _resolve('markers.size_mm', marker_size_mm, _S.get('marker_size_mm'))
|
|
235
|
+
axis_font_size_pt = _resolve('fonts.axis_label_pt', axis_font_size_pt, _S.get('axis_font_size_pt'))
|
|
236
|
+
tick_font_size_pt = _resolve('fonts.tick_label_pt', tick_font_size_pt, _S.get('tick_font_size_pt'))
|
|
237
|
+
title_font_size_pt = _resolve('fonts.title_pt', title_font_size_pt, _S.get('title_font_size_pt'))
|
|
238
|
+
legend_font_size_pt = _resolve('fonts.legend_pt', legend_font_size_pt, _S.get('legend_font_size_pt'))
|
|
239
|
+
suptitle_font_size_pt = _resolve('fonts.suptitle_pt', suptitle_font_size_pt, _S.get('suptitle_font_size_pt'))
|
|
240
|
+
n_ticks = _resolve('ticks.n_ticks', n_ticks, _S.get('n_ticks'), int)
|
|
241
|
+
dpi = _resolve('output.dpi', dpi, _S.get('dpi'), int)
|
|
242
|
+
# Resolve transparent from YAML (default: True in SCITEX_STYLE.yaml)
|
|
243
|
+
if transparent is None:
|
|
244
|
+
transparent = _S.get('transparent', True)
|
|
245
|
+
if mode is None:
|
|
246
|
+
mode = _S.get('mode', 'publication')
|
|
247
|
+
|
|
248
|
+
# Always use mm-control pathway with SCITEX_STYLE defaults
|
|
249
|
+
if True:
|
|
226
250
|
# Use mm-control pathway
|
|
227
251
|
return self._create_with_mm_control(
|
|
228
252
|
*args,
|
|
229
253
|
track=track,
|
|
230
254
|
sharex=sharex,
|
|
231
255
|
sharey=sharey,
|
|
232
|
-
|
|
233
|
-
|
|
256
|
+
axes_width_mm=axes_width_mm,
|
|
257
|
+
axes_height_mm=axes_height_mm,
|
|
234
258
|
margin_left_mm=margin_left_mm,
|
|
235
259
|
margin_right_mm=margin_right_mm,
|
|
236
260
|
margin_bottom_mm=margin_bottom_mm,
|
|
237
261
|
margin_top_mm=margin_top_mm,
|
|
238
262
|
space_w_mm=space_w_mm,
|
|
239
263
|
space_h_mm=space_h_mm,
|
|
240
|
-
|
|
264
|
+
axes_thickness_mm=axes_thickness_mm,
|
|
241
265
|
tick_length_mm=tick_length_mm,
|
|
242
266
|
tick_thickness_mm=tick_thickness_mm,
|
|
243
267
|
trace_thickness_mm=trace_thickness_mm,
|
|
268
|
+
marker_size_mm=marker_size_mm,
|
|
244
269
|
axis_font_size_pt=axis_font_size_pt,
|
|
245
270
|
tick_font_size_pt=tick_font_size_pt,
|
|
246
271
|
title_font_size_pt=title_font_size_pt,
|
|
@@ -254,67 +279,25 @@ class SubplotsWrapper:
|
|
|
254
279
|
**kwargs
|
|
255
280
|
)
|
|
256
281
|
|
|
257
|
-
# Standard matplotlib pathway (existing behavior)
|
|
258
|
-
# If constrained_layout is not specified, use it by default for better colorbar handling
|
|
259
|
-
if constrained_layout is None and 'layout' not in kwargs:
|
|
260
|
-
# Use a dict to set padding parameters for better spacing
|
|
261
|
-
# Increased w_pad to prevent colorbar overlap
|
|
262
|
-
kwargs['constrained_layout'] = {'w_pad': 0.1, 'h_pad': 0.1, 'wspace': 0.05, 'hspace': 0.05}
|
|
263
|
-
|
|
264
|
-
# Start from the original matplotlib figure and axes
|
|
265
|
-
self._fig_mpl, self._axes_mpl = self._counter_part(
|
|
266
|
-
*args, sharex=sharex, sharey=sharey, **kwargs
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
# Wrap the figure
|
|
270
|
-
self._fig_scitex = FigWrapper(self._fig_mpl)
|
|
271
|
-
|
|
272
|
-
# Ensure axes_mpl is always an array
|
|
273
|
-
axes_array_mpl = np.atleast_1d(self._axes_mpl)
|
|
274
|
-
axes_shape_mpl = axes_array_mpl.shape
|
|
275
|
-
|
|
276
|
-
# Handle single axis case
|
|
277
|
-
if axes_array_mpl.size == 1:
|
|
278
|
-
# Use squeeze() to get the scalar Axes object if it's a 0-d array
|
|
279
|
-
ax_mpl_scalar = (
|
|
280
|
-
axes_array_mpl.item() if axes_array_mpl.ndim == 0 else axes_array_mpl[0]
|
|
281
|
-
)
|
|
282
|
-
self._axis_scitex = AxisWrapper(self._fig_scitex, ax_mpl_scalar, track)
|
|
283
|
-
self._fig_scitex.axes = np.atleast_1d([self._axis_scitex])
|
|
284
|
-
return self._fig_scitex, self._axis_scitex
|
|
285
|
-
|
|
286
|
-
# Handle multiple axes case
|
|
287
|
-
axes_flat_mpl = axes_array_mpl.ravel()
|
|
288
|
-
axes_flat_scitex_list = [
|
|
289
|
-
AxisWrapper(self._fig_scitex, ax_, track) for ax_ in axes_flat_mpl
|
|
290
|
-
]
|
|
291
|
-
|
|
292
|
-
# Reshape the axes_flat_scitex_list axes to match the original layout
|
|
293
|
-
axes_array_scitex = np.array(axes_flat_scitex_list).reshape(axes_shape_mpl)
|
|
294
|
-
|
|
295
|
-
# Wrap the array of axes
|
|
296
|
-
self._axes_scitex = AxesWrapper(self._fig_scitex, axes_array_scitex)
|
|
297
|
-
self._fig_scitex.axes = self._axes_scitex
|
|
298
|
-
return self._fig_scitex, self._axes_scitex
|
|
299
|
-
|
|
300
282
|
def _create_with_mm_control(
|
|
301
283
|
self,
|
|
302
284
|
*args,
|
|
303
285
|
track=True,
|
|
304
286
|
sharex=False,
|
|
305
287
|
sharey=False,
|
|
306
|
-
|
|
307
|
-
|
|
288
|
+
axes_width_mm=None,
|
|
289
|
+
axes_height_mm=None,
|
|
308
290
|
margin_left_mm=None,
|
|
309
291
|
margin_right_mm=None,
|
|
310
292
|
margin_bottom_mm=None,
|
|
311
293
|
margin_top_mm=None,
|
|
312
294
|
space_w_mm=None,
|
|
313
295
|
space_h_mm=None,
|
|
314
|
-
|
|
296
|
+
axes_thickness_mm=None,
|
|
315
297
|
tick_length_mm=None,
|
|
316
298
|
tick_thickness_mm=None,
|
|
317
299
|
trace_thickness_mm=None,
|
|
300
|
+
marker_size_mm=None,
|
|
318
301
|
axis_font_size_pt=None,
|
|
319
302
|
tick_font_size_pt=None,
|
|
320
303
|
title_font_size_pt=None,
|
|
@@ -328,7 +311,7 @@ class SubplotsWrapper:
|
|
|
328
311
|
mode=None,
|
|
329
312
|
dpi=None,
|
|
330
313
|
styles=None,
|
|
331
|
-
transparent=
|
|
314
|
+
transparent=None, # Resolved from caller
|
|
332
315
|
**kwargs
|
|
333
316
|
):
|
|
334
317
|
"""Create figure with mm-based control over axes dimensions."""
|
|
@@ -352,15 +335,15 @@ class SubplotsWrapper:
|
|
|
352
335
|
dpi = dpi or 300
|
|
353
336
|
|
|
354
337
|
# Set defaults - if value is provided, apply scaling; if not, use scaled default
|
|
355
|
-
if
|
|
356
|
-
|
|
338
|
+
if axes_width_mm is None:
|
|
339
|
+
axes_width_mm = 30.0 * scale_factor
|
|
357
340
|
elif mode == 'display':
|
|
358
|
-
|
|
341
|
+
axes_width_mm = axes_width_mm * scale_factor
|
|
359
342
|
|
|
360
|
-
if
|
|
361
|
-
|
|
343
|
+
if axes_height_mm is None:
|
|
344
|
+
axes_height_mm = 21.0 * scale_factor
|
|
362
345
|
elif mode == 'display':
|
|
363
|
-
|
|
346
|
+
axes_height_mm = axes_height_mm * scale_factor
|
|
364
347
|
|
|
365
348
|
margin_left_mm = margin_left_mm if margin_left_mm is not None else (5.0 * scale_factor)
|
|
366
349
|
margin_right_mm = margin_right_mm if margin_right_mm is not None else (2.0 * scale_factor)
|
|
@@ -369,20 +352,20 @@ class SubplotsWrapper:
|
|
|
369
352
|
space_w_mm = space_w_mm if space_w_mm is not None else (3.0 * scale_factor)
|
|
370
353
|
space_h_mm = space_h_mm if space_h_mm is not None else (3.0 * scale_factor)
|
|
371
354
|
|
|
372
|
-
# Handle list vs scalar for
|
|
373
|
-
if isinstance(
|
|
374
|
-
ax_widths_mm = list(
|
|
355
|
+
# Handle list vs scalar for axes_width_mm and axes_height_mm
|
|
356
|
+
if isinstance(axes_width_mm, (list, tuple)):
|
|
357
|
+
ax_widths_mm = list(axes_width_mm)
|
|
375
358
|
if len(ax_widths_mm) != n_axes:
|
|
376
|
-
raise ValueError(f"
|
|
359
|
+
raise ValueError(f"axes_width_mm list length ({len(ax_widths_mm)}) must match nrows*ncols ({n_axes})")
|
|
377
360
|
else:
|
|
378
|
-
ax_widths_mm = [
|
|
361
|
+
ax_widths_mm = [axes_width_mm] * n_axes
|
|
379
362
|
|
|
380
|
-
if isinstance(
|
|
381
|
-
ax_heights_mm = list(
|
|
363
|
+
if isinstance(axes_height_mm, (list, tuple)):
|
|
364
|
+
ax_heights_mm = list(axes_height_mm)
|
|
382
365
|
if len(ax_heights_mm) != n_axes:
|
|
383
|
-
raise ValueError(f"
|
|
366
|
+
raise ValueError(f"axes_height_mm list length ({len(ax_heights_mm)}) must match nrows*ncols ({n_axes})")
|
|
384
367
|
else:
|
|
385
|
-
ax_heights_mm = [
|
|
368
|
+
ax_heights_mm = [axes_height_mm] * n_axes
|
|
386
369
|
|
|
387
370
|
# Calculate figure size from axes grid
|
|
388
371
|
# For simplicity, use max width per column and max height per row
|
|
@@ -464,14 +447,16 @@ class SubplotsWrapper:
|
|
|
464
447
|
else:
|
|
465
448
|
# Build style dict from individual parameters
|
|
466
449
|
style_dict = {}
|
|
467
|
-
if
|
|
468
|
-
style_dict['axis_thickness_mm'] =
|
|
450
|
+
if axes_thickness_mm is not None:
|
|
451
|
+
style_dict['axis_thickness_mm'] = axes_thickness_mm
|
|
469
452
|
if tick_length_mm is not None:
|
|
470
453
|
style_dict['tick_length_mm'] = tick_length_mm
|
|
471
454
|
if tick_thickness_mm is not None:
|
|
472
455
|
style_dict['tick_thickness_mm'] = tick_thickness_mm
|
|
473
456
|
if trace_thickness_mm is not None:
|
|
474
457
|
style_dict['trace_thickness_mm'] = trace_thickness_mm
|
|
458
|
+
if marker_size_mm is not None:
|
|
459
|
+
style_dict['marker_size_mm'] = marker_size_mm
|
|
475
460
|
if axis_font_size_pt is not None:
|
|
476
461
|
style_dict['axis_font_size_pt'] = axis_font_size_pt
|
|
477
462
|
if tick_font_size_pt is not None:
|