scitex 2.3.0__py3-none-any.whl → 2.4.1__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 +559 -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.1.dist-info}/METADATA +2 -1
  91. {scitex-2.3.0.dist-info → scitex-2.4.1.dist-info}/RECORD +94 -67
  92. {scitex-2.3.0.dist-info → scitex-2.4.1.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.1.dist-info}/entry_points.txt +0 -0
  99. {scitex-2.3.0.dist-info → scitex-2.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- # Timestamp: "2025-05-18 17:51:44 (ywatanabe)"
4
- # File: /home/ywatanabe/proj/scitex_repo/src/scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py
3
+ # Timestamp: "2025-12-01 12:00:00 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py
5
5
  # ----------------------------------------
6
6
  import os
7
7
 
@@ -19,17 +19,37 @@ from scipy.stats import gaussian_kde
19
19
 
20
20
  from scitex.pd import to_xyz
21
21
  from scitex.types import ArrayLike
22
+ from scitex.plt.utils import mm_to_pt
23
+
24
+
25
+ # ============================================================================
26
+ # Constants for default styling (same as styles/_plot_defaults.py)
27
+ # ============================================================================
28
+ DEFAULT_LINE_WIDTH_MM = 0.2
29
+ DEFAULT_MARKER_SIZE_MM = 0.8
30
+ DEFAULT_FILL_ALPHA = 0.3
22
31
 
23
32
 
24
33
  class MatplotlibPlotMixin:
25
34
  """Mixin class for basic plotting operations."""
26
-
35
+
27
36
  def _get_ax_module(self):
28
37
  """Lazy import ax module to avoid circular imports."""
29
38
  from ....plt import ax as ax_module
30
39
  return ax_module
31
40
 
32
- def plot_image(
41
+ def _apply_scitex_postprocess(self, method_name, result=None, kwargs=None, args=None):
42
+ """Apply scitex post-processing styling after plotting.
43
+
44
+ This ensures all scitex wrapper methods get the same styling
45
+ as matplotlib methods going through __getattr__ (tick locator, spines, etc.).
46
+ """
47
+ from scitex.plt.styles import apply_plot_postprocess
48
+ apply_plot_postprocess(
49
+ method_name, result, self._axis_mpl, kwargs or {}, args
50
+ )
51
+
52
+ def stx_image(
33
53
  self,
34
54
  arr_2d: ArrayLike,
35
55
  track: bool = True,
@@ -37,11 +57,11 @@ class MatplotlibPlotMixin:
37
57
  **kwargs,
38
58
  ) -> None:
39
59
  # Method Name for downstream csv exporting
40
- method_name = "plot_image"
60
+ method_name = "stx_image"
41
61
 
42
62
  # Plotting with pure matplotlib methods under non-tracking context
43
63
  with self._no_tracking():
44
- self._axis_mpl = self._get_ax_module().plot_image(self._axis_mpl, arr_2d, **kwargs)
64
+ self._axis_mpl = self._get_ax_module().stx_image(self._axis_mpl, arr_2d, **kwargs)
45
65
 
46
66
  # Tracking
47
67
  tracked_dict = {"image_df": pd.DataFrame(arr_2d)}
@@ -55,11 +75,14 @@ class MatplotlibPlotMixin:
55
75
  None,
56
76
  )
57
77
 
78
+ # Apply post-processing (tick locator, spines, etc.)
79
+ self._apply_scitex_postprocess(method_name)
80
+
58
81
  return self._axis_mpl
59
82
 
60
- def plot_kde(
83
+ def stx_kde(
61
84
  self,
62
- data: ArrayLike,
85
+ values_1d: ArrayLike,
63
86
  cumulative=False,
64
87
  fill=False,
65
88
  track: bool = True,
@@ -67,23 +90,23 @@ class MatplotlibPlotMixin:
67
90
  **kwargs,
68
91
  ) -> None:
69
92
  # Method Name for downstream csv exporting
70
- method_name = "plot_kde"
93
+ method_name = "stx_kde"
71
94
 
72
95
  # Sample count as label
73
- n_samples = (~np.isnan(data)).sum()
96
+ n_samples = (~np.isnan(values_1d)).sum()
74
97
  if kwargs.get("label"):
75
- kwargs["label"] = f"{kwargs['label']} (n={n_samples})"
98
+ kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
76
99
 
77
100
  # Xlim (kwargs["xlim"] is not accepted in downstream plotters)
78
- xlim = kwargs.get("xlim")
101
+ xlim = kwargs.pop("xlim", None)
79
102
  if not xlim:
80
- xlim = (np.nanmin(data), np.nanmax(data))
103
+ xlim = (np.nanmin(values_1d), np.nanmax(values_1d))
81
104
 
82
105
  # X
83
106
  xx = np.linspace(xlim[0], xlim[1], int(1e3))
84
107
 
85
108
  # Y
86
- density = gaussian_kde(data)(xx)
109
+ density = gaussian_kde(values_1d)(xx)
87
110
  density /= density.sum()
88
111
 
89
112
  # Cumulative
@@ -101,6 +124,10 @@ class MatplotlibPlotMixin:
101
124
  if 'color' not in kwargs and 'c' not in kwargs:
102
125
  kwargs['color'] = 'black'
103
126
 
127
+ # Set default linestyle to dashed (customizable via linestyle kwarg)
128
+ if 'linestyle' not in kwargs and 'ls' not in kwargs:
129
+ kwargs['linestyle'] = '--'
130
+
104
131
  # Filled Line
105
132
  if fill:
106
133
  self._axis_mpl.fill_between(
@@ -126,11 +153,14 @@ class MatplotlibPlotMixin:
126
153
  None,
127
154
  )
128
155
 
156
+ # Apply post-processing (tick locator, spines, etc.)
157
+ self._apply_scitex_postprocess(method_name)
158
+
129
159
  return self._axis_mpl
130
160
 
131
- def plot_conf_mat(
161
+ def stx_conf_mat(
132
162
  self,
133
- data: ArrayLike,
163
+ conf_mat_2d: ArrayLike,
134
164
  x_labels: Optional[List[str]] = None,
135
165
  y_labels: Optional[List[str]] = None,
136
166
  title: str = "Confusion Matrix",
@@ -146,13 +176,13 @@ class MatplotlibPlotMixin:
146
176
  **kwargs,
147
177
  ) -> None:
148
178
  # Method Name for downstream csv exporting
149
- method_name = "plot_conf_mat"
179
+ method_name = "stx_conf_mat"
150
180
 
151
181
  # Plotting with pure matplotlib methods under non-tracking context
152
182
  with self._no_tracking():
153
- self._axis_mpl, bacc_val = self._get_ax_module().plot_conf_mat(
183
+ self._axis_mpl, bacc_val = self._get_ax_module().stx_conf_mat(
154
184
  self._axis_mpl,
155
- data,
185
+ conf_mat_2d,
156
186
  x_labels=x_labels,
157
187
  y_labels=y_labels,
158
188
  title=title,
@@ -170,10 +200,13 @@ class MatplotlibPlotMixin:
170
200
  # Tracking
171
201
  self._track(track, id, method_name, tracked_dict, None)
172
202
 
203
+ # Apply post-processing (tick locator, spines, etc.)
204
+ self._apply_scitex_postprocess(method_name)
205
+
173
206
  return self._axis_mpl, bacc_val
174
207
 
175
208
  # @wraps removed to avoid circular import
176
- def plot_rectangle(
209
+ def stx_rectangle(
177
210
  self,
178
211
  xx: float,
179
212
  yy: float,
@@ -184,11 +217,11 @@ class MatplotlibPlotMixin:
184
217
  **kwargs,
185
218
  ) -> None:
186
219
  # Method Name for downstream csv exporting
187
- method_name = "plot_rectangle"
220
+ method_name = "stx_rectangle"
188
221
 
189
222
  # Plotting with pure matplotlib methods under non-tracking context
190
223
  with self._no_tracking():
191
- self._axis_mpl = self._get_ax_module().plot_rectangle(
224
+ self._axis_mpl = self._get_ax_module().stx_rectangle(
192
225
  self._axis_mpl, xx, yy, width, height, **kwargs
193
226
  )
194
227
 
@@ -196,13 +229,16 @@ class MatplotlibPlotMixin:
196
229
  tracked_dict = {"xx": xx, "yy": yy, "width": width, "height": height}
197
230
  self._track(track, id, method_name, tracked_dict, None)
198
231
 
232
+ # Apply post-processing (tick locator, spines, etc.)
233
+ self._apply_scitex_postprocess(method_name)
234
+
199
235
  return self._axis_mpl
200
236
 
201
237
  # @wraps removed to avoid circular import
202
- def plot_fillv(
238
+ def stx_fillv(
203
239
  self,
204
- starts: ArrayLike,
205
- ends: ArrayLike,
240
+ starts_1d: ArrayLike,
241
+ ends_1d: ArrayLike,
206
242
  color: str = "red",
207
243
  alpha: float = 0.2,
208
244
  track: bool = True,
@@ -210,51 +246,70 @@ class MatplotlibPlotMixin:
210
246
  **kwargs,
211
247
  ) -> None:
212
248
  # Method Name for downstream csv exporting
213
- method_name = "plot_fillv"
249
+ method_name = "stx_fillv"
214
250
 
215
251
  # Plotting with pure matplotlib methods under non-tracking context
216
252
  with self._no_tracking():
217
- self._axis_mpl = self._get_ax_module().plot_fillv(
218
- self._axis_mpl, starts, ends, color=color, alpha=alpha
253
+ self._axis_mpl = self._get_ax_module().stx_fillv(
254
+ self._axis_mpl, starts_1d, ends_1d, color=color, alpha=alpha
219
255
  )
220
256
 
221
257
  # Tracking
222
- tracked_dict = {"starts": starts, "ends": ends}
258
+ tracked_dict = {"starts": starts_1d, "ends": ends_1d}
223
259
  self._track(track, id, method_name, tracked_dict, None)
224
260
 
261
+ # Apply post-processing (tick locator, spines, etc.)
262
+ self._apply_scitex_postprocess(method_name)
263
+
225
264
  return self._axis_mpl
226
265
 
227
- def plot_box(
266
+ def stx_box(
228
267
  self,
229
- data: ArrayLike,
268
+ values_list: ArrayLike,
269
+ colors: Optional[List] = None,
230
270
  track: bool = True,
231
271
  id: Optional[str] = None,
232
272
  **kwargs,
233
- ) -> None:
273
+ ) -> dict:
234
274
  # Method Name for downstream csv exporting
235
- method_name = "plot_box"
275
+ method_name = "stx_box"
236
276
 
237
277
  # Copy data
238
- _data = data.copy()
278
+ _data = values_list.copy()
239
279
 
240
- # Sample count as label
241
- n = len(data)
280
+ # Sample count per group as label (show range if variable)
242
281
  if kwargs.get("label"):
243
- kwargs["label"] = kwargs["label"] + f" (n={n})"
282
+ n_per_group = [len(g) for g in values_list]
283
+ n_min, n_max = min(n_per_group), max(n_per_group)
284
+ n_str = str(n_min) if n_min == n_max else f"{n_min}-{n_max}"
285
+ kwargs["label"] = kwargs["label"] + f" ($n$={n_str})"
286
+
287
+ # Enable patch_artist for styling (fill colors, edges)
288
+ if "patch_artist" not in kwargs:
289
+ kwargs["patch_artist"] = True
244
290
 
245
291
  # Plotting with pure matplotlib methods under non-tracking context
246
292
  with self._no_tracking():
247
- self._axis_mpl.boxplot(data, **kwargs)
293
+ result = self._axis_mpl.boxplot(values_list, **kwargs)
248
294
 
249
- # Tracking
295
+ # Tracking - calculate sample size per group
296
+ n_per_group = [len(g) for g in values_list]
250
297
  tracked_dict = {
251
298
  "data": _data,
252
- "n": [n for ii in range(len(data))],
299
+ "n": n_per_group,
253
300
  }
254
301
  self._track(track, id, method_name, tracked_dict, None)
255
302
 
256
- return self._axis_mpl
257
-
303
+ # Apply style_boxplot automatically for publication quality
304
+ # Uses scitex palette by default, or custom colors if provided
305
+ from scitex.plt.ax import style_boxplot
306
+ style_boxplot(result, colors=colors)
307
+
308
+ # Apply post-processing (tick locator, spines, etc.)
309
+ self._apply_scitex_postprocess(method_name, result)
310
+
311
+ return result
312
+
258
313
  def hist(
259
314
  self,
260
315
  x: ArrayLike,
@@ -312,13 +367,16 @@ class MatplotlibPlotMixin:
312
367
  }
313
368
 
314
369
  self._track(track, id, method_name, tracked_dict, kwargs)
315
-
370
+
371
+ # Apply post-processing (tick locator, spines, etc.)
372
+ self._apply_scitex_postprocess(method_name, hist_data)
373
+
316
374
  return hist_data
317
375
 
318
376
  # @wraps removed to avoid circular import
319
- def plot_raster(
377
+ def stx_raster(
320
378
  self,
321
- positions: List[ArrayLike],
379
+ spike_times_list: List[ArrayLike],
322
380
  time: Optional[ArrayLike] = None,
323
381
  labels: Optional[List[str]] = None,
324
382
  colors: Optional[List[str]] = None,
@@ -327,90 +385,77 @@ class MatplotlibPlotMixin:
327
385
  **kwargs,
328
386
  ) -> None:
329
387
  # Method Name for downstream csv exporting
330
- method_name = "plot_raster"
388
+ method_name = "stx_raster"
331
389
 
332
390
  # Plotting with pure matplotlib methods under non-tracking context
333
391
  with self._no_tracking():
334
- self._axis_mpl, raster_digit_df = self._get_ax_module().plot_raster(
335
- self._axis_mpl, positions, time=time
392
+ self._axis_mpl, raster_digit_df = self._get_ax_module().stx_raster(
393
+ self._axis_mpl, spike_times_list, time=time
336
394
  )
337
395
 
338
396
  # Tracking
339
397
  tracked_dict = {"raster_digit_df": raster_digit_df}
340
398
  self._track(track, id, method_name, tracked_dict, None)
341
399
 
400
+ # Apply post-processing (tick locator, spines, etc.)
401
+ self._apply_scitex_postprocess(method_name)
402
+
342
403
  return self._axis_mpl, raster_digit_df
343
404
 
344
405
  # @wraps removed to avoid circular import
345
- def plot_ecdf(
406
+ def stx_ecdf(
346
407
  self,
347
- data: ArrayLike,
408
+ values_1d: ArrayLike,
348
409
  track: bool = True,
349
410
  id: Optional[str] = None,
350
411
  **kwargs,
351
412
  ) -> None:
352
413
  # Method Name for downstream csv exporting
353
- method_name = "plot_ecdf"
414
+ method_name = "stx_ecdf"
354
415
 
355
416
  # Plotting with pure matplotlib methods under non-tracking context
356
417
  with self._no_tracking():
357
- self._axis_mpl, ecdf_df = self._get_ax_module().plot_ecdf(
358
- self._axis_mpl, data, **kwargs
418
+ self._axis_mpl, ecdf_df = self._get_ax_module().stx_ecdf(
419
+ self._axis_mpl, values_1d, **kwargs
359
420
  )
360
421
 
361
422
  # Tracking
362
423
  tracked_dict = {"ecdf_df": ecdf_df}
363
424
  self._track(track, id, method_name, tracked_dict, None)
364
425
 
426
+ # Apply post-processing (tick locator, spines, etc.)
427
+ self._apply_scitex_postprocess(method_name)
428
+
365
429
  return self._axis_mpl, ecdf_df
366
430
 
367
431
  # @wraps removed to avoid circular import
368
- def plot_joyplot(
432
+ def stx_joyplot(
369
433
  self,
370
- data: ArrayLike,
371
- orientation: str = "vertical",
434
+ arrays: ArrayLike,
372
435
  track: bool = True,
373
436
  id: Optional[str] = None,
374
437
  **kwargs,
375
438
  ) -> None:
376
439
  # Method Name for downstream csv exporting
377
- method_name = "plot_joyplot"
440
+ method_name = "stx_joyplot"
378
441
 
379
442
  # Plotting with pure matplotlib methods under non-tracking context
380
443
  with self._no_tracking():
381
- self._axis_mpl = self._get_ax_module().plot_joyplot(
382
- self._axis_mpl, data, orientation=orientation, **kwargs
444
+ self._axis_mpl = self._get_ax_module().stx_joyplot(
445
+ self._axis_mpl, arrays, **kwargs
383
446
  )
384
447
 
385
448
  # Tracking
386
- tracked_dict = {"joyplot_data": data}
449
+ tracked_dict = {"joyplot_arrays": arrays}
387
450
  self._track(track, id, method_name, tracked_dict, None)
388
451
 
389
- return self._axis_mpl
390
-
391
- # @wraps removed to avoid circular import
392
- def plot_joyplot(
393
- self,
394
- data: ArrayLike,
395
- track: bool = True,
396
- id: Optional[str] = None,
397
- **kwargs,
398
- ) -> None:
399
- # Method Name for downstream csv exporting
400
- method_name = "plot_joyplot"
401
-
402
- # Plotting with pure matplotlib methods under non-tracking context
403
- with self._no_tracking():
404
- self._axis_mpl = self._get_ax_module().plot_joyplot(self._axis_mpl, data, **kwargs)
405
-
406
- # Tracking
407
- tracked_dict = {"joyplot_data": data}
408
- self._track(track, id, method_name, tracked_dict, None)
452
+ # Apply post-processing (tick locator, spines, etc.)
453
+ self._apply_scitex_postprocess(method_name)
409
454
 
410
455
  return self._axis_mpl
411
456
 
412
457
  # @wraps removed to avoid circular import
413
- def plot_scatter_hist(
458
+ def stx_scatter_hist(
414
459
  self,
415
460
  x: ArrayLike,
416
461
  y: ArrayLike,
@@ -428,11 +473,11 @@ class MatplotlibPlotMixin:
428
473
  ) -> None:
429
474
  """Plot a scatter plot with marginal histograms."""
430
475
  # Method Name for downstream csv exporting
431
- method_name = "plot_scatter_hist"
476
+ method_name = "stx_scatter_hist"
432
477
 
433
478
  # Plotting with pure matplotlib methods under non-tracking context
434
479
  with self._no_tracking():
435
- self._axis_mpl, ax_histx, ax_histy, hist_data = self._get_ax_module().plot_scatter_hist(
480
+ self._axis_mpl, ax_histx, ax_histy, hist_data = self._get_ax_module().stx_scatter_hist(
436
481
  self._axis_mpl,
437
482
  x,
438
483
  y,
@@ -458,12 +503,15 @@ class MatplotlibPlotMixin:
458
503
  }
459
504
  self._track(track, id, method_name, tracked_dict, None)
460
505
 
506
+ # Apply post-processing (tick locator, spines, etc.)
507
+ self._apply_scitex_postprocess(method_name)
508
+
461
509
  return self._axis_mpl, ax_histx, ax_histy, hist_data
462
510
 
463
511
  # @wraps removed to avoid circular import
464
- def plot_heatmap(
512
+ def stx_heatmap(
465
513
  self,
466
- data: ArrayLike,
514
+ values_2d: ArrayLike,
467
515
  x_labels: Optional[List[str]] = None,
468
516
  y_labels: Optional[List[str]] = None,
469
517
  cmap: str = "viridis",
@@ -478,13 +526,13 @@ class MatplotlibPlotMixin:
478
526
  ) -> Tuple[matplotlib.image.AxesImage, matplotlib.colorbar.Colorbar]:
479
527
  """Plot a heatmap on the axes."""
480
528
  # Method Name for downstream csv exporting
481
- method_name = "plot_heatmap"
529
+ method_name = "stx_heatmap"
482
530
 
483
531
  # Plotting with pure matplotlib methods under non-tracking context
484
532
  with self._no_tracking():
485
- ax, im, cbar = self._get_ax_module().plot_heatmap(
533
+ ax, im, cbar = self._get_ax_module().stx_heatmap(
486
534
  self._axis_mpl,
487
- data,
535
+ values_2d,
488
536
  x_labels=x_labels,
489
537
  y_labels=y_labels,
490
538
  cmap=cmap,
@@ -498,18 +546,21 @@ class MatplotlibPlotMixin:
498
546
 
499
547
  # Tracking
500
548
  tracked_dict = {
501
- "data": data,
549
+ "data": values_2d,
502
550
  "x_labels": x_labels,
503
551
  "y_labels": y_labels,
504
552
  }
505
553
  self._track(track, id, method_name, tracked_dict, None)
506
554
 
555
+ # Apply post-processing (tick locator, spines, etc.)
556
+ self._apply_scitex_postprocess(method_name)
557
+
507
558
  return ax, im, cbar
508
559
 
509
560
  # @wraps removed to avoid circular import
510
- def plot_violin(
561
+ def stx_violin(
511
562
  self,
512
- data: Union[pd.DataFrame, List, ArrayLike],
563
+ values_list: Union[pd.DataFrame, List, ArrayLike],
513
564
  x=None,
514
565
  y=None,
515
566
  hue=None,
@@ -522,17 +573,17 @@ class MatplotlibPlotMixin:
522
573
  ) -> None:
523
574
  """Plot a violin plot."""
524
575
  # Method Name for downstream csv exporting
525
- method_name = "plot_violin"
576
+ method_name = "stx_violin"
526
577
 
527
578
  # Plotting with pure matplotlib methods under non-tracking context
528
579
  with self._no_tracking():
529
580
  # Handle the list-style input case
530
- if isinstance(data, list) and all(
531
- isinstance(item, (list, np.ndarray)) for item in data
581
+ if isinstance(values_list, list) and all(
582
+ isinstance(item, (list, np.ndarray)) for item in values_list
532
583
  ):
533
- self._axis_mpl = self._get_ax_module().plot_violin(
584
+ self._axis_mpl = self._get_ax_module().stx_violin(
534
585
  self._axis_mpl,
535
- data_list=data,
586
+ values_list=values_list,
536
587
  labels=labels,
537
588
  colors=colors,
538
589
  half=half,
@@ -540,9 +591,9 @@ class MatplotlibPlotMixin:
540
591
  )
541
592
  # Handle DataFrame or other inputs
542
593
  else:
543
- self._axis_mpl = self._get_ax_module().plot_violin(
594
+ self._axis_mpl = self._get_ax_module().stx_violin(
544
595
  self._axis_mpl,
545
- data=data,
596
+ data=values_list,
546
597
  x=x,
547
598
  y=y,
548
599
  hue=hue,
@@ -552,7 +603,7 @@ class MatplotlibPlotMixin:
552
603
 
553
604
  # Tracking
554
605
  tracked_dict = {
555
- "data": data,
606
+ "data": values_list,
556
607
  "x": x,
557
608
  "y": y,
558
609
  "hue": hue,
@@ -561,6 +612,10 @@ class MatplotlibPlotMixin:
561
612
  "colors": colors,
562
613
  }
563
614
  self._track(track, id, method_name, tracked_dict, None)
615
+
616
+ # Apply post-processing (tick locator, spines, etc.)
617
+ self._apply_scitex_postprocess(method_name)
618
+
564
619
  return self._axis_mpl
565
620
 
566
621
  # def plot_area(
@@ -766,9 +821,9 @@ class MatplotlibPlotMixin:
766
821
  # return self._axis_mpl
767
822
 
768
823
  # @wraps removed to avoid circular import
769
- def plot_line(
824
+ def stx_line(
770
825
  self,
771
- data: ArrayLike,
826
+ values_1d: ArrayLike,
772
827
  xx: Optional[ArrayLike] = None,
773
828
  track: bool = True,
774
829
  id: Optional[str] = None,
@@ -776,24 +831,27 @@ class MatplotlibPlotMixin:
776
831
  ) -> None:
777
832
  """Plot a simple line."""
778
833
  # Method Name for downstream csv exporting
779
- method_name = "plot_line"
834
+ method_name = "stx_line"
780
835
 
781
836
  # Plotting with pure matplotlib methods under non-tracking context
782
837
  with self._no_tracking():
783
- self._axis_mpl, plot_df = self._get_ax_module().plot_line(
784
- self._axis_mpl, data, xx=xx, **kwargs
838
+ self._axis_mpl, plot_df = self._get_ax_module().stx_line(
839
+ self._axis_mpl, values_1d, xx=xx, **kwargs
785
840
  )
786
841
 
787
842
  # Tracking
788
843
  tracked_dict = {"plot_df": plot_df}
789
844
  self._track(track, id, method_name, tracked_dict, None)
790
845
 
846
+ # Apply post-processing (tick locator, spines, etc.)
847
+ self._apply_scitex_postprocess(method_name)
848
+
791
849
  return self._axis_mpl, plot_df
792
850
 
793
851
  # @wraps removed to avoid circular import
794
- def plot_mean_std(
852
+ def stx_mean_std(
795
853
  self,
796
- data: ArrayLike,
854
+ values_2d: ArrayLike,
797
855
  xx: Optional[ArrayLike] = None,
798
856
  sd: float = 1,
799
857
  track: bool = True,
@@ -802,24 +860,27 @@ class MatplotlibPlotMixin:
802
860
  ) -> None:
803
861
  """Plot mean line with standard deviation shading."""
804
862
  # Method Name for downstream csv exporting
805
- method_name = "plot_mean_std"
863
+ method_name = "stx_mean_std"
806
864
 
807
865
  # Plotting with pure matplotlib methods under non-tracking context
808
866
  with self._no_tracking():
809
- self._axis_mpl, plot_df = self._get_ax_module().plot_mean_std(
810
- self._axis_mpl, data, xx=xx, sd=sd, **kwargs
867
+ self._axis_mpl, plot_df = self._get_ax_module().stx_mean_std(
868
+ self._axis_mpl, values_2d, xx=xx, sd=sd, **kwargs
811
869
  )
812
870
 
813
871
  # Tracking
814
872
  tracked_dict = {"plot_df": plot_df}
815
873
  self._track(track, id, method_name, tracked_dict, None)
816
874
 
875
+ # Apply post-processing (tick locator, spines, etc.)
876
+ self._apply_scitex_postprocess(method_name)
877
+
817
878
  return self._axis_mpl, plot_df
818
879
 
819
880
  # @wraps removed to avoid circular import
820
- def plot_mean_ci(
881
+ def stx_mean_ci(
821
882
  self,
822
- data: ArrayLike,
883
+ values_2d: ArrayLike,
823
884
  xx: Optional[ArrayLike] = None,
824
885
  perc: float = 95,
825
886
  track: bool = True,
@@ -828,24 +889,27 @@ class MatplotlibPlotMixin:
828
889
  ) -> None:
829
890
  """Plot mean line with confidence interval shading."""
830
891
  # Method Name for downstream csv exporting
831
- method_name = "plot_mean_ci"
892
+ method_name = "stx_mean_ci"
832
893
 
833
894
  # Plotting with pure matplotlib methods under non-tracking context
834
895
  with self._no_tracking():
835
- self._axis_mpl, plot_df = self._get_ax_module().plot_mean_ci(
836
- self._axis_mpl, data, xx=xx, perc=perc, **kwargs
896
+ self._axis_mpl, plot_df = self._get_ax_module().stx_mean_ci(
897
+ self._axis_mpl, values_2d, xx=xx, perc=perc, **kwargs
837
898
  )
838
899
 
839
900
  # Tracking
840
901
  tracked_dict = {"plot_df": plot_df}
841
902
  self._track(track, id, method_name, tracked_dict, None)
842
903
 
904
+ # Apply post-processing (tick locator, spines, etc.)
905
+ self._apply_scitex_postprocess(method_name)
906
+
843
907
  return self._axis_mpl, plot_df
844
908
 
845
909
  # @wraps removed to avoid circular import
846
- def plot_median_iqr(
910
+ def stx_median_iqr(
847
911
  self,
848
- data: ArrayLike,
912
+ values_2d: ArrayLike,
849
913
  xx: Optional[ArrayLike] = None,
850
914
  track: bool = True,
851
915
  id: Optional[str] = None,
@@ -853,22 +917,25 @@ class MatplotlibPlotMixin:
853
917
  ) -> None:
854
918
  """Plot median line with interquartile range shading."""
855
919
  # Method Name for downstream csv exporting
856
- method_name = "plot_median_iqr"
920
+ method_name = "stx_median_iqr"
857
921
 
858
922
  # Plotting with pure matplotlib methods under non-tracking context
859
923
  with self._no_tracking():
860
- self._axis_mpl, plot_df = self._get_ax_module().plot_median_iqr(
861
- self._axis_mpl, data, xx=xx, **kwargs
924
+ self._axis_mpl, plot_df = self._get_ax_module().stx_median_iqr(
925
+ self._axis_mpl, values_2d, xx=xx, **kwargs
862
926
  )
863
927
 
864
928
  # Tracking
865
929
  tracked_dict = {"plot_df": plot_df}
866
930
  self._track(track, id, method_name, tracked_dict, None)
867
931
 
932
+ # Apply post-processing (tick locator, spines, etc.)
933
+ self._apply_scitex_postprocess(method_name)
934
+
868
935
  return self._axis_mpl, plot_df
869
936
 
870
937
  # @wraps removed to avoid circular import
871
- def plot_shaded_line(
938
+ def stx_shaded_line(
872
939
  self,
873
940
  xs: ArrayLike,
874
941
  ys_lower: ArrayLike,
@@ -882,11 +949,11 @@ class MatplotlibPlotMixin:
882
949
  ) -> None:
883
950
  """Plot a line with shaded area between lower and upper bounds."""
884
951
  # Method Name for downstream csv exporting
885
- method_name = "plot_shaded_line"
952
+ method_name = "stx_shaded_line"
886
953
 
887
954
  # Plotting with pure matplotlib methods under non-tracking context
888
955
  with self._no_tracking():
889
- self._axis_mpl, plot_df = self._get_ax_module().plot_shaded_line(
956
+ self._axis_mpl, plot_df = self._get_ax_module().stx_shaded_line(
890
957
  self._axis_mpl,
891
958
  xs,
892
959
  ys_lower,
@@ -901,8 +968,316 @@ class MatplotlibPlotMixin:
901
968
  tracked_dict = {"plot_df": plot_df}
902
969
  self._track(track, id, method_name, tracked_dict, None)
903
970
 
971
+ # Apply post-processing (tick locator, spines, etc.)
972
+ self._apply_scitex_postprocess(method_name)
973
+
904
974
  return self._axis_mpl, plot_df
905
975
 
976
+ # =========================================================================
977
+ # stx_ aliases for standard matplotlib methods
978
+ # These provide a consistent stx_ prefix for all scitex wrapper methods
979
+ # =========================================================================
980
+
981
+ def stx_bar(self, x, height, track: bool = True, id: Optional[str] = None, **kwargs):
982
+ """Bar plot with scitex styling and tracking.
983
+
984
+ Parameters
985
+ ----------
986
+ x : array-like
987
+ The x coordinates of the bars
988
+ height : array-like
989
+ The heights of the bars
990
+ track : bool
991
+ Whether to track data for CSV export
992
+ id : str, optional
993
+ Identifier for tracking
994
+ **kwargs
995
+ Additional arguments passed to matplotlib bar
996
+ """
997
+ method_name = "stx_bar"
998
+
999
+ # Add sample size to label if provided
1000
+ if kwargs.get("label"):
1001
+ n_samples = len(x)
1002
+ kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1003
+
1004
+ with self._no_tracking():
1005
+ result = self._axis_mpl.bar(x, height, **kwargs)
1006
+
1007
+ # Track bar data
1008
+ tracked_dict = {"bar_df": pd.DataFrame({"x": x, "height": height})}
1009
+ self._track(track, id, method_name, tracked_dict, None)
1010
+
1011
+ # Apply style_barplot automatically for publication quality
1012
+ from scitex.plt.ax import style_barplot
1013
+ style_barplot(result)
1014
+
1015
+ # Apply post-processing (tick locator, spines, etc.)
1016
+ self._apply_scitex_postprocess(method_name, result)
1017
+
1018
+ return result
1019
+
1020
+ def stx_barh(self, y, width, track: bool = True, id: Optional[str] = None, **kwargs):
1021
+ """Horizontal bar plot with scitex styling and tracking.
1022
+
1023
+ Parameters
1024
+ ----------
1025
+ y : array-like
1026
+ The y coordinates of the bars
1027
+ width : array-like
1028
+ The widths of the bars
1029
+ track : bool
1030
+ Whether to track data for CSV export
1031
+ id : str, optional
1032
+ Identifier for tracking
1033
+ **kwargs
1034
+ Additional arguments passed to matplotlib barh
1035
+ """
1036
+ method_name = "stx_barh"
1037
+
1038
+ # Add sample size to label if provided
1039
+ if kwargs.get("label"):
1040
+ n_samples = len(y)
1041
+ kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1042
+
1043
+ with self._no_tracking():
1044
+ result = self._axis_mpl.barh(y, width, **kwargs)
1045
+
1046
+ # Track bar data
1047
+ tracked_dict = {"barh_df": pd.DataFrame({"y": y, "width": width})}
1048
+ self._track(track, id, method_name, tracked_dict, None)
1049
+
1050
+ # Apply post-processing (tick locator, spines, etc.)
1051
+ self._apply_scitex_postprocess(method_name, result)
1052
+
1053
+ return result
1054
+
1055
+ def stx_scatter(self, x, y, track: bool = True, id: Optional[str] = None, **kwargs):
1056
+ """Scatter plot with scitex styling and tracking.
1057
+
1058
+ Parameters
1059
+ ----------
1060
+ x : array-like
1061
+ The x coordinates of the points
1062
+ y : array-like
1063
+ The y coordinates of the points
1064
+ track : bool
1065
+ Whether to track data for CSV export
1066
+ id : str, optional
1067
+ Identifier for tracking
1068
+ **kwargs
1069
+ Additional arguments passed to matplotlib scatter
1070
+ """
1071
+ method_name = "stx_scatter"
1072
+
1073
+ # Add sample size to label if provided
1074
+ if kwargs.get("label"):
1075
+ n_samples = len(x)
1076
+ kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1077
+
1078
+ with self._no_tracking():
1079
+ result = self._axis_mpl.scatter(x, y, **kwargs)
1080
+
1081
+ # Track scatter data
1082
+ tracked_dict = {"scatter_df": pd.DataFrame({"x": x, "y": y})}
1083
+ self._track(track, id, method_name, tracked_dict, None)
1084
+
1085
+ # Apply style_scatter automatically for publication quality
1086
+ from scitex.plt.ax import style_scatter
1087
+ style_scatter(result)
1088
+
1089
+ # Apply post-processing (tick locator, spines, etc.)
1090
+ self._apply_scitex_postprocess(method_name, result)
1091
+
1092
+ return result
1093
+
1094
+ def stx_errorbar(self, x, y, yerr=None, xerr=None, track: bool = True, id: Optional[str] = None, **kwargs):
1095
+ """Error bar plot with scitex styling and tracking.
1096
+
1097
+ Parameters
1098
+ ----------
1099
+ x : array-like
1100
+ The x coordinates of the data points
1101
+ y : array-like
1102
+ The y coordinates of the data points
1103
+ yerr : array-like, optional
1104
+ The y error values
1105
+ xerr : array-like, optional
1106
+ The x error values
1107
+ track : bool
1108
+ Whether to track data for CSV export
1109
+ id : str, optional
1110
+ Identifier for tracking
1111
+ **kwargs
1112
+ Additional arguments passed to matplotlib errorbar
1113
+ """
1114
+ method_name = "stx_errorbar"
1115
+
1116
+ # Add sample size to label if provided
1117
+ if kwargs.get("label"):
1118
+ n_samples = len(x)
1119
+ kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1120
+
1121
+ with self._no_tracking():
1122
+ result = self._axis_mpl.errorbar(x, y, yerr=yerr, xerr=xerr, **kwargs)
1123
+
1124
+ # Track errorbar data
1125
+ df_dict = {"x": x, "y": y}
1126
+ if yerr is not None:
1127
+ df_dict["yerr"] = yerr
1128
+ if xerr is not None:
1129
+ df_dict["xerr"] = xerr
1130
+ tracked_dict = {"errorbar_df": pd.DataFrame(df_dict)}
1131
+ self._track(track, id, method_name, tracked_dict, None)
1132
+
1133
+ # Apply style_errorbar automatically for publication quality
1134
+ from scitex.plt.ax import style_errorbar
1135
+ style_errorbar(result)
1136
+
1137
+ # Apply post-processing (tick locator, spines, etc.)
1138
+ self._apply_scitex_postprocess(method_name, result)
1139
+
1140
+ return result
1141
+
1142
+ def stx_fill_between(self, x, y1, y2=0, track: bool = True, id: Optional[str] = None, **kwargs):
1143
+ """Fill between plot with scitex styling and tracking.
1144
+
1145
+ Parameters
1146
+ ----------
1147
+ x : array-like
1148
+ The x coordinates
1149
+ y1 : array-like
1150
+ The first y boundary
1151
+ y2 : array-like or scalar, optional
1152
+ The second y boundary (default 0)
1153
+ track : bool
1154
+ Whether to track data for CSV export
1155
+ id : str, optional
1156
+ Identifier for tracking
1157
+ **kwargs
1158
+ Additional arguments passed to matplotlib fill_between
1159
+ """
1160
+ method_name = "stx_fill_between"
1161
+
1162
+ with self._no_tracking():
1163
+ result = self._axis_mpl.fill_between(x, y1, y2, **kwargs)
1164
+
1165
+ # Track fill_between data
1166
+ tracked_dict = {"fill_between_df": pd.DataFrame({
1167
+ "x": x,
1168
+ "y1": y1,
1169
+ "y2": y2 if hasattr(y2, '__len__') else [y2] * len(x)
1170
+ })}
1171
+ self._track(track, id, method_name, tracked_dict, None)
1172
+
1173
+ # Apply post-processing (tick locator, spines, etc.)
1174
+ self._apply_scitex_postprocess(method_name, result)
1175
+
1176
+ return result
1177
+
1178
+ def stx_contour(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
1179
+ """Contour plot with scitex styling and tracking.
1180
+
1181
+ Parameters
1182
+ ----------
1183
+ *args
1184
+ Positional arguments passed to matplotlib contour (X, Y, Z)
1185
+ track : bool
1186
+ Whether to track data for CSV export
1187
+ id : str, optional
1188
+ Identifier for tracking
1189
+ **kwargs
1190
+ Additional arguments passed to matplotlib contour
1191
+ """
1192
+ method_name = "stx_contour"
1193
+
1194
+ with self._no_tracking():
1195
+ result = self._axis_mpl.contour(*args, **kwargs)
1196
+
1197
+ # Track contour data
1198
+ if len(args) >= 3:
1199
+ X, Y, Z = args[0], args[1], args[2]
1200
+ tracked_dict = {"contour_df": pd.DataFrame({
1201
+ "X": np.ravel(X),
1202
+ "Y": np.ravel(Y),
1203
+ "Z": np.ravel(Z)
1204
+ })}
1205
+ self._track(track, id, method_name, tracked_dict, None)
1206
+
1207
+ # Apply post-processing (tick locator, spines, etc.)
1208
+ self._apply_scitex_postprocess(method_name, result)
1209
+
1210
+ return result
1211
+
1212
+ def stx_imshow(self, data, track: bool = True, id: Optional[str] = None, **kwargs):
1213
+ """Image display with scitex styling and tracking.
1214
+
1215
+ Parameters
1216
+ ----------
1217
+ data : array-like
1218
+ 2D array of image data
1219
+ track : bool
1220
+ Whether to track data for CSV export
1221
+ id : str, optional
1222
+ Identifier for tracking
1223
+ **kwargs
1224
+ Additional arguments passed to matplotlib imshow
1225
+ """
1226
+ method_name = "stx_imshow"
1227
+
1228
+ with self._no_tracking():
1229
+ result = self._axis_mpl.imshow(data, **kwargs)
1230
+
1231
+ # Track image data
1232
+ if hasattr(data, 'shape') and len(data.shape) == 2:
1233
+ n_rows, n_cols = data.shape
1234
+ df = pd.DataFrame(data, columns=[f"col_{i}" for i in range(n_cols)])
1235
+ else:
1236
+ df = pd.DataFrame(data)
1237
+ tracked_dict = {"imshow_df": df}
1238
+ self._track(track, id, method_name, tracked_dict, None)
1239
+
1240
+ # Apply post-processing (tick locator, spines, etc.)
1241
+ self._apply_scitex_postprocess(method_name, result)
1242
+
1243
+ return result
1244
+
1245
+ def stx_boxplot(self, data, colors: Optional[List] = None, track: bool = True, id: Optional[str] = None, **kwargs):
1246
+ """Boxplot with scitex styling and tracking (alias for stx_box).
1247
+
1248
+ Parameters
1249
+ ----------
1250
+ data : list of array-like
1251
+ List of data arrays for each box
1252
+ colors : list, optional
1253
+ Colors for each box
1254
+ track : bool
1255
+ Whether to track data for CSV export
1256
+ id : str, optional
1257
+ Identifier for tracking
1258
+ **kwargs
1259
+ Additional arguments passed to matplotlib boxplot
1260
+ """
1261
+ return self.stx_box(data, colors=colors, track=track, id=id, **kwargs)
1262
+
1263
+ def stx_violinplot(self, data, colors: Optional[List] = None, track: bool = True, id: Optional[str] = None, **kwargs):
1264
+ """Violinplot with scitex styling and tracking (alias for stx_violin).
1265
+
1266
+ Parameters
1267
+ ----------
1268
+ data : list of array-like or DataFrame
1269
+ Data for violin plot
1270
+ colors : list, optional
1271
+ Colors for each violin
1272
+ track : bool
1273
+ Whether to track data for CSV export
1274
+ id : str, optional
1275
+ Identifier for tracking
1276
+ **kwargs
1277
+ Additional arguments passed to stx_violin
1278
+ """
1279
+ return self.stx_violin(data, colors=colors, track=track, id=id, **kwargs)
1280
+
906
1281
  # Standard matplotlib plot methods with plot_ prefix
907
1282
  def plot_bar(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
908
1283
  """Wrapper for matplotlib bar plot with tracking support."""
@@ -916,6 +1291,9 @@ class MatplotlibPlotMixin:
916
1291
  tracked_dict = {"bar_df": pd.DataFrame({"x": args[0], "height": args[1]})}
917
1292
  self._track(track, id, method_name, tracked_dict, None)
918
1293
 
1294
+ # Apply post-processing (tick locator, spines, etc.)
1295
+ self._apply_scitex_postprocess(method_name, result)
1296
+
919
1297
  return result
920
1298
 
921
1299
  def plot_barh(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
@@ -930,12 +1308,20 @@ class MatplotlibPlotMixin:
930
1308
  tracked_dict = {"barh_df": pd.DataFrame({"y": args[0], "width": args[1]})}
931
1309
  self._track(track, id, method_name, tracked_dict, None)
932
1310
 
1311
+ # Apply post-processing (tick locator, spines, etc.)
1312
+ self._apply_scitex_postprocess(method_name, result)
1313
+
933
1314
  return result
934
1315
 
935
1316
  def plot_scatter(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
936
1317
  """Wrapper for matplotlib scatter plot with tracking support."""
937
1318
  method_name = "plot_scatter"
938
1319
 
1320
+ # Add sample size to label if provided
1321
+ if kwargs.get("label") and len(args) >= 1:
1322
+ n_samples = len(args[0])
1323
+ kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1324
+
939
1325
  with self._no_tracking():
940
1326
  result = self._axis_mpl.scatter(*args, **kwargs)
941
1327
 
@@ -944,6 +1330,9 @@ class MatplotlibPlotMixin:
944
1330
  tracked_dict = {"scatter_df": pd.DataFrame({"x": args[0], "y": args[1]})}
945
1331
  self._track(track, id, method_name, tracked_dict, None)
946
1332
 
1333
+ # Apply post-processing (tick locator, spines, etc.)
1334
+ self._apply_scitex_postprocess(method_name, result)
1335
+
947
1336
  return result
948
1337
 
949
1338
  def plot_errorbar(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
@@ -963,6 +1352,9 @@ class MatplotlibPlotMixin:
963
1352
  tracked_dict = {"errorbar_df": pd.DataFrame(df_dict)}
964
1353
  self._track(track, id, method_name, tracked_dict, None)
965
1354
 
1355
+ # Apply post-processing (tick locator, spines, etc.)
1356
+ self._apply_scitex_postprocess(method_name, result)
1357
+
966
1358
  return result
967
1359
 
968
1360
  def plot_fill_between(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
@@ -981,6 +1373,9 @@ class MatplotlibPlotMixin:
981
1373
  })}
982
1374
  self._track(track, id, method_name, tracked_dict, None)
983
1375
 
1376
+ # Apply post-processing (tick locator, spines, etc.)
1377
+ self._apply_scitex_postprocess(method_name, result)
1378
+
984
1379
  return result
985
1380
 
986
1381
  def plot_contour(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
@@ -1001,6 +1396,9 @@ class MatplotlibPlotMixin:
1001
1396
  })}
1002
1397
  self._track(track, id, method_name, tracked_dict, None)
1003
1398
 
1399
+ # Apply post-processing (tick locator, spines, etc.)
1400
+ self._apply_scitex_postprocess(method_name, result)
1401
+
1004
1402
  return result
1005
1403
 
1006
1404
  def plot_imshow(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
@@ -1023,12 +1421,28 @@ class MatplotlibPlotMixin:
1023
1421
  tracked_dict = {"imshow_df": df}
1024
1422
  self._track(track, id, method_name, tracked_dict, None)
1025
1423
 
1424
+ # Apply post-processing (tick locator, spines, etc.)
1425
+ self._apply_scitex_postprocess(method_name, result)
1426
+
1026
1427
  return result
1027
1428
 
1028
- def plot_boxplot(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
1029
- """Wrapper for matplotlib boxplot with tracking support."""
1429
+ def plot_boxplot(self, *args, colors: Optional[List] = None, track: bool = True, id: Optional[str] = None, **kwargs):
1430
+ """Wrapper for matplotlib boxplot with tracking support and auto-styling."""
1030
1431
  method_name = "plot_boxplot"
1031
1432
 
1433
+ # Add sample size per group to label if provided (show range if variable)
1434
+ if kwargs.get("label") and len(args) >= 1:
1435
+ data = args[0]
1436
+ if isinstance(data, list):
1437
+ n_per_group = [len(g) for g in data]
1438
+ n_min, n_max = min(n_per_group), max(n_per_group)
1439
+ n_str = str(n_min) if n_min == n_max else f"{n_min}-{n_max}"
1440
+ kwargs["label"] = f"{kwargs['label']} ($n$={n_str})"
1441
+
1442
+ # Enable patch_artist for styling (fill colors, edges)
1443
+ if "patch_artist" not in kwargs:
1444
+ kwargs["patch_artist"] = True
1445
+
1032
1446
  with self._no_tracking():
1033
1447
  result = self._axis_mpl.boxplot(*args, **kwargs)
1034
1448
 
@@ -1041,12 +1455,29 @@ class MatplotlibPlotMixin:
1041
1455
  tracked_dict = {"boxplot_df": pd.DataFrame({"data": data})}
1042
1456
  self._track(track, id, method_name, tracked_dict, None)
1043
1457
 
1458
+ # Apply style_boxplot automatically for publication quality
1459
+ # Uses scitex palette by default, or custom colors if provided
1460
+ from scitex.plt.ax import style_boxplot
1461
+ style_boxplot(result, colors=colors)
1462
+
1463
+ # Apply post-processing (tick locator, spines, etc.)
1464
+ self._apply_scitex_postprocess(method_name, result)
1465
+
1044
1466
  return result
1045
1467
 
1046
1468
  def plot_violinplot(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
1047
1469
  """Wrapper for matplotlib violinplot with tracking support."""
1048
1470
  method_name = "plot_violinplot"
1049
1471
 
1472
+ # Add sample size per group to label if provided (show range if variable)
1473
+ if kwargs.get("label") and len(args) >= 1:
1474
+ data = args[0]
1475
+ if isinstance(data, list):
1476
+ n_per_group = [len(g) for g in data]
1477
+ n_min, n_max = min(n_per_group), max(n_per_group)
1478
+ n_str = str(n_min) if n_min == n_max else f"{n_min}-{n_max}"
1479
+ kwargs["label"] = f"{kwargs['label']} ($n$={n_str})"
1480
+
1050
1481
  with self._no_tracking():
1051
1482
  result = self._axis_mpl.violinplot(*args, **kwargs)
1052
1483
 
@@ -1059,6 +1490,10 @@ class MatplotlibPlotMixin:
1059
1490
  tracked_dict = {"violinplot_df": pd.DataFrame({"data": data})}
1060
1491
  self._track(track, id, method_name, tracked_dict, None)
1061
1492
 
1493
+ # Apply post-processing (tick locator, spines, etc.)
1494
+ self._apply_scitex_postprocess(method_name, result, kwargs, args)
1495
+
1062
1496
  return result
1063
1497
 
1498
+
1064
1499
  # EOF