scitex 2.4.3__py3-none-any.whl → 2.5.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/__version__.py +1 -1
- scitex/io/_load.py +5 -0
- scitex/io/_load_modules/_canvas.py +171 -0
- scitex/io/_save.py +8 -0
- scitex/io/_save_modules/_canvas.py +356 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +77 -22
- scitex/plt/docs/FIGURE_ARCHITECTURE.md +257 -0
- scitex/plt/utils/__init__.py +10 -0
- scitex/plt/utils/_collect_figure_metadata.py +14 -12
- scitex/plt/utils/_csv_column_naming.py +237 -0
- scitex/session/_decorator.py +13 -1
- scitex/vis/README.md +246 -615
- scitex/vis/__init__.py +138 -78
- scitex/vis/canvas.py +423 -0
- scitex/vis/docs/CANVAS_ARCHITECTURE.md +307 -0
- scitex/vis/editor/__init__.py +1 -1
- scitex/vis/editor/_dearpygui_editor.py +1830 -0
- scitex/vis/editor/_defaults.py +40 -1
- scitex/vis/editor/_edit.py +54 -18
- scitex/vis/editor/_flask_editor.py +37 -0
- scitex/vis/editor/_qt_editor.py +865 -0
- scitex/vis/editor/flask_editor/__init__.py +21 -0
- scitex/vis/editor/flask_editor/bbox.py +216 -0
- scitex/vis/editor/flask_editor/core.py +152 -0
- scitex/vis/editor/flask_editor/plotter.py +130 -0
- scitex/vis/editor/flask_editor/renderer.py +184 -0
- scitex/vis/editor/flask_editor/templates/__init__.py +33 -0
- scitex/vis/editor/flask_editor/templates/html.py +295 -0
- scitex/vis/editor/flask_editor/templates/scripts.py +614 -0
- scitex/vis/editor/flask_editor/templates/styles.py +549 -0
- scitex/vis/editor/flask_editor/utils.py +81 -0
- scitex/vis/io/__init__.py +84 -21
- scitex/vis/io/canvas.py +226 -0
- scitex/vis/io/data.py +204 -0
- scitex/vis/io/directory.py +202 -0
- scitex/vis/io/export.py +460 -0
- scitex/vis/io/panel.py +424 -0
- {scitex-2.4.3.dist-info → scitex-2.5.0.dist-info}/METADATA +9 -2
- {scitex-2.4.3.dist-info → scitex-2.5.0.dist-info}/RECORD +42 -21
- scitex/vis/DJANGO_INTEGRATION.md +0 -677
- scitex/vis/editor/_web_editor.py +0 -1440
- scitex/vis/tmp.txt +0 -239
- {scitex-2.4.3.dist-info → scitex-2.5.0.dist-info}/WHEEL +0 -0
- {scitex-2.4.3.dist-info → scitex-2.5.0.dist-info}/entry_points.txt +0 -0
- {scitex-2.4.3.dist-info → scitex-2.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: 2025-12-08
|
|
4
|
+
# File: ./src/scitex/plt/utils/_csv_column_naming.py
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Single source of truth for CSV column naming in scitex.
|
|
8
|
+
|
|
9
|
+
This module ensures consistent column naming between:
|
|
10
|
+
- CSV export (_export_as_csv)
|
|
11
|
+
- JSON metadata (_collect_figure_metadata)
|
|
12
|
+
- GUI editors (reading CSV data back)
|
|
13
|
+
|
|
14
|
+
Column naming convention:
|
|
15
|
+
ax_{row}{col}_{trace_id}_{data_type}
|
|
16
|
+
|
|
17
|
+
Where:
|
|
18
|
+
- row, col: axes position in grid (e.g., "00" for single axes)
|
|
19
|
+
- trace_id: unique identifier for the trace (from label, id kwarg, or index)
|
|
20
|
+
- data_type: type of data (e.g., "plot_x", "plot_y", "hist_bins", etc.)
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
'get_csv_column_name',
|
|
25
|
+
'get_csv_column_prefix',
|
|
26
|
+
'parse_csv_column_name',
|
|
27
|
+
'sanitize_trace_id',
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def sanitize_trace_id(trace_id: str) -> str:
|
|
32
|
+
"""Sanitize trace ID for use in CSV column names.
|
|
33
|
+
|
|
34
|
+
Removes or replaces characters that could cause issues in column names.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
trace_id : str
|
|
39
|
+
Raw trace identifier (label, id kwarg, or generated)
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
str
|
|
44
|
+
Sanitized trace ID safe for CSV column names
|
|
45
|
+
"""
|
|
46
|
+
if not trace_id:
|
|
47
|
+
return "unnamed"
|
|
48
|
+
|
|
49
|
+
# Replace problematic characters
|
|
50
|
+
sanitized = str(trace_id)
|
|
51
|
+
# Keep alphanumeric, underscore, hyphen; replace others with underscore
|
|
52
|
+
result = []
|
|
53
|
+
for char in sanitized:
|
|
54
|
+
if char.isalnum() or char in ('_', '-'):
|
|
55
|
+
result.append(char)
|
|
56
|
+
elif char in (' ', '(', ')', '[', ']', '{', '}', '/', '\\', '.'):
|
|
57
|
+
result.append('_')
|
|
58
|
+
# Skip other characters
|
|
59
|
+
|
|
60
|
+
sanitized = ''.join(result)
|
|
61
|
+
|
|
62
|
+
# Remove consecutive underscores
|
|
63
|
+
while '__' in sanitized:
|
|
64
|
+
sanitized = sanitized.replace('__', '_')
|
|
65
|
+
|
|
66
|
+
# Remove leading/trailing underscores
|
|
67
|
+
sanitized = sanitized.strip('_')
|
|
68
|
+
|
|
69
|
+
return sanitized if sanitized else "unnamed"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_csv_column_prefix(ax_row: int = 0, ax_col: int = 0, trace_id: str = None, trace_index: int = None) -> str:
|
|
73
|
+
"""Get CSV column prefix for a trace.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
ax_row : int
|
|
78
|
+
Row position of axes in grid (default: 0)
|
|
79
|
+
ax_col : int
|
|
80
|
+
Column position of axes in grid (default: 0)
|
|
81
|
+
trace_id : str, optional
|
|
82
|
+
Trace identifier (from label or id kwarg). If None, uses trace_index.
|
|
83
|
+
trace_index : int, optional
|
|
84
|
+
Index of trace when no trace_id is provided (default: 0)
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
str
|
|
89
|
+
Column prefix like "ax_00_sin_x_" or "ax_01_plot_0_"
|
|
90
|
+
"""
|
|
91
|
+
ax_pos = f"{ax_row}{ax_col}"
|
|
92
|
+
|
|
93
|
+
if trace_id:
|
|
94
|
+
safe_id = sanitize_trace_id(trace_id)
|
|
95
|
+
elif trace_index is not None:
|
|
96
|
+
safe_id = f"plot_{trace_index}"
|
|
97
|
+
else:
|
|
98
|
+
safe_id = "plot_0"
|
|
99
|
+
|
|
100
|
+
return f"ax_{ax_pos}_{safe_id}_"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_csv_column_name(
|
|
104
|
+
data_type: str,
|
|
105
|
+
ax_row: int = 0,
|
|
106
|
+
ax_col: int = 0,
|
|
107
|
+
trace_id: str = None,
|
|
108
|
+
trace_index: int = None,
|
|
109
|
+
) -> str:
|
|
110
|
+
"""Get full CSV column name for a data field.
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
data_type : str
|
|
115
|
+
Type of data (e.g., "plot_x", "plot_y", "hist_bins", "bar_heights")
|
|
116
|
+
ax_row : int
|
|
117
|
+
Row position of axes in grid (default: 0)
|
|
118
|
+
ax_col : int
|
|
119
|
+
Column position of axes in grid (default: 0)
|
|
120
|
+
trace_id : str, optional
|
|
121
|
+
Trace identifier (from label or id kwarg)
|
|
122
|
+
trace_index : int, optional
|
|
123
|
+
Index of trace when no trace_id is provided
|
|
124
|
+
|
|
125
|
+
Returns
|
|
126
|
+
-------
|
|
127
|
+
str
|
|
128
|
+
Full column name like "ax_00_sin_x_plot_x" or "ax_01_plot_0_plot_y"
|
|
129
|
+
|
|
130
|
+
Examples
|
|
131
|
+
--------
|
|
132
|
+
>>> get_csv_column_name("plot_x", trace_id="sin(x)")
|
|
133
|
+
'ax_00_sin_x_plot_x'
|
|
134
|
+
>>> get_csv_column_name("plot_y", ax_row=1, ax_col=2, trace_index=0)
|
|
135
|
+
'ax_12_plot_0_plot_y'
|
|
136
|
+
"""
|
|
137
|
+
prefix = get_csv_column_prefix(ax_row, ax_col, trace_id, trace_index)
|
|
138
|
+
return f"{prefix}{data_type}"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def parse_csv_column_name(column_name: str) -> dict:
|
|
142
|
+
"""Parse CSV column name to extract components.
|
|
143
|
+
|
|
144
|
+
Parameters
|
|
145
|
+
----------
|
|
146
|
+
column_name : str
|
|
147
|
+
Full column name (e.g., "ax_00_sin_x_plot_x")
|
|
148
|
+
|
|
149
|
+
Returns
|
|
150
|
+
-------
|
|
151
|
+
dict
|
|
152
|
+
Dictionary with keys:
|
|
153
|
+
- ax_row: int
|
|
154
|
+
- ax_col: int
|
|
155
|
+
- trace_id: str
|
|
156
|
+
- data_type: str
|
|
157
|
+
- valid: bool (True if parsing succeeded)
|
|
158
|
+
|
|
159
|
+
Examples
|
|
160
|
+
--------
|
|
161
|
+
>>> parse_csv_column_name("ax_00_sin_x_plot_x")
|
|
162
|
+
{'ax_row': 0, 'ax_col': 0, 'trace_id': 'sin_x', 'data_type': 'plot_x', 'valid': True}
|
|
163
|
+
"""
|
|
164
|
+
result = {
|
|
165
|
+
'ax_row': 0,
|
|
166
|
+
'ax_col': 0,
|
|
167
|
+
'trace_id': '',
|
|
168
|
+
'data_type': '',
|
|
169
|
+
'valid': False,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if not column_name or not column_name.startswith('ax_'):
|
|
173
|
+
return result
|
|
174
|
+
|
|
175
|
+
parts = column_name.split('_')
|
|
176
|
+
if len(parts) < 4:
|
|
177
|
+
return result
|
|
178
|
+
|
|
179
|
+
try:
|
|
180
|
+
# Parse ax position (e.g., "00" from "ax_00_...")
|
|
181
|
+
ax_pos = parts[1]
|
|
182
|
+
if len(ax_pos) >= 2:
|
|
183
|
+
result['ax_row'] = int(ax_pos[0])
|
|
184
|
+
result['ax_col'] = int(ax_pos[1])
|
|
185
|
+
|
|
186
|
+
# Last two parts are typically data_type (e.g., "plot_x", "hist_bins")
|
|
187
|
+
# Everything in between is the trace_id
|
|
188
|
+
data_type_parts = parts[-2:] # e.g., ["plot", "x"]
|
|
189
|
+
result['data_type'] = '_'.join(data_type_parts)
|
|
190
|
+
|
|
191
|
+
# Trace ID is everything between ax_pos and data_type
|
|
192
|
+
trace_parts = parts[2:-2]
|
|
193
|
+
result['trace_id'] = '_'.join(trace_parts) if trace_parts else 'plot_0'
|
|
194
|
+
|
|
195
|
+
result['valid'] = True
|
|
196
|
+
|
|
197
|
+
except (ValueError, IndexError):
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
return result
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def get_trace_columns_from_df(df, trace_id: str = None, trace_index: int = None, ax_row: int = 0, ax_col: int = 0) -> dict:
|
|
204
|
+
"""Find CSV columns for a specific trace in a DataFrame.
|
|
205
|
+
|
|
206
|
+
Parameters
|
|
207
|
+
----------
|
|
208
|
+
df : pandas.DataFrame
|
|
209
|
+
DataFrame with CSV data
|
|
210
|
+
trace_id : str, optional
|
|
211
|
+
Trace identifier to search for
|
|
212
|
+
trace_index : int, optional
|
|
213
|
+
Trace index to search for (if trace_id not provided)
|
|
214
|
+
ax_row : int
|
|
215
|
+
Row position of axes
|
|
216
|
+
ax_col : int
|
|
217
|
+
Column position of axes
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
dict
|
|
222
|
+
Dictionary mapping data types to column names, e.g.:
|
|
223
|
+
{'plot_x': 'ax_00_sin_x_plot_x', 'plot_y': 'ax_00_sin_x_plot_y'}
|
|
224
|
+
"""
|
|
225
|
+
result = {}
|
|
226
|
+
prefix = get_csv_column_prefix(ax_row, ax_col, trace_id, trace_index)
|
|
227
|
+
|
|
228
|
+
for col in df.columns:
|
|
229
|
+
if col.startswith(prefix):
|
|
230
|
+
# Extract data_type from column name
|
|
231
|
+
data_type = col[len(prefix):]
|
|
232
|
+
result[data_type] = col
|
|
233
|
+
|
|
234
|
+
return result
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
# EOF
|
scitex/session/_decorator.py
CHANGED
|
@@ -495,6 +495,7 @@ def _add_argument(
|
|
|
495
495
|
type_hints: Type hints dictionary
|
|
496
496
|
short_form: Optional short form (e.g., 'a' for -a)
|
|
497
497
|
"""
|
|
498
|
+
from typing import get_origin, get_args, Literal
|
|
498
499
|
|
|
499
500
|
# Get type
|
|
500
501
|
param_type = type_hints.get(param_name, param.annotation)
|
|
@@ -513,6 +514,13 @@ def _add_argument(
|
|
|
513
514
|
if short_form:
|
|
514
515
|
arg_names.insert(0, f"-{short_form}")
|
|
515
516
|
|
|
517
|
+
# Check for Literal type (choices)
|
|
518
|
+
choices = None
|
|
519
|
+
origin = get_origin(param_type)
|
|
520
|
+
if origin is Literal:
|
|
521
|
+
choices = list(get_args(param_type))
|
|
522
|
+
param_type = type(choices[0]) if choices else str
|
|
523
|
+
|
|
516
524
|
# Handle different types
|
|
517
525
|
if param_type == bool:
|
|
518
526
|
# Boolean flags
|
|
@@ -524,11 +532,15 @@ def _add_argument(
|
|
|
524
532
|
)
|
|
525
533
|
else:
|
|
526
534
|
# Regular arguments
|
|
535
|
+
choices_str = f", choices: {choices}" if choices else ""
|
|
527
536
|
kwargs = {
|
|
528
537
|
'type': param_type,
|
|
529
|
-
'help': f"(default: {default})" if has_default else "(required)",
|
|
538
|
+
'help': f"(default: {default}{choices_str})" if has_default else f"(required{choices_str})",
|
|
530
539
|
}
|
|
531
540
|
|
|
541
|
+
if choices:
|
|
542
|
+
kwargs['choices'] = choices
|
|
543
|
+
|
|
532
544
|
if has_default:
|
|
533
545
|
kwargs['default'] = default
|
|
534
546
|
else:
|