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
@@ -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
- if kwargs.get("hue"):
284
- hues = data[kwargs["hue"]]
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.plot_kde(_data, xlim=lim, label=hue, id=hue, **kwargs)
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.plot_kde(_data, xlim=lim, label=hue, id=hue, **kwargs)
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.plot_kde(_data, xlim=lim, **kwargs)
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
- ax_width_mm=None,
97
- ax_height_mm=None,
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
- ax_thickness_mm=None,
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=False, # Transparent background for publication figures
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
- ax_width_mm : float or list, optional
137
+ axes_width_mm : float or list, optional
137
138
  Axes width in mm (single value for all, or list for each)
138
- ax_height_mm : float or list, optional
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
- ax_thickness_mm : float, optional
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
- ... ax_width_mm=30,
189
- ... ax_height_mm=21,
190
- ... ax_thickness_mm=0.2,
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
- ... ax_width_mm=30,
200
- ... ax_height_mm=21,
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
- ... 'ax_width_mm': 30,
210
- ... 'ax_height_mm': 21,
211
- ... 'ax_thickness_mm': 0.2,
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
- # Check if mm-control is requested
218
- mm_control_requested = any([
219
- ax_width_mm is not None,
220
- ax_height_mm is not None,
221
- mode is not None,
222
- styles is not None,
223
- ])
224
-
225
- if mm_control_requested:
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
- ax_width_mm=ax_width_mm,
233
- ax_height_mm=ax_height_mm,
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
- ax_thickness_mm=ax_thickness_mm,
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
- ax_width_mm=None,
307
- ax_height_mm=None,
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
- ax_thickness_mm=None,
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=False,
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 ax_width_mm is None:
356
- ax_width_mm = 30.0 * scale_factor
338
+ if axes_width_mm is None:
339
+ axes_width_mm = 30.0 * scale_factor
357
340
  elif mode == 'display':
358
- ax_width_mm = ax_width_mm * scale_factor
341
+ axes_width_mm = axes_width_mm * scale_factor
359
342
 
360
- if ax_height_mm is None:
361
- ax_height_mm = 21.0 * scale_factor
343
+ if axes_height_mm is None:
344
+ axes_height_mm = 21.0 * scale_factor
362
345
  elif mode == 'display':
363
- ax_height_mm = ax_height_mm * scale_factor
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 ax_width_mm and ax_height_mm
373
- if isinstance(ax_width_mm, (list, tuple)):
374
- ax_widths_mm = list(ax_width_mm)
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"ax_width_mm list length ({len(ax_widths_mm)}) must match nrows*ncols ({n_axes})")
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 = [ax_width_mm] * n_axes
361
+ ax_widths_mm = [axes_width_mm] * n_axes
379
362
 
380
- if isinstance(ax_height_mm, (list, tuple)):
381
- ax_heights_mm = list(ax_height_mm)
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"ax_height_mm list length ({len(ax_heights_mm)}) must match nrows*ncols ({n_axes})")
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 = [ax_height_mm] * n_axes
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 ax_thickness_mm is not None:
468
- style_dict['axis_thickness_mm'] = ax_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: