scitex 2.4.2__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/browser/__init__.py +53 -0
- scitex/browser/debugging/__init__.py +56 -0
- scitex/browser/debugging/_failure_capture.py +372 -0
- scitex/browser/debugging/_sync_session.py +259 -0
- scitex/browser/debugging/_test_monitor.py +284 -0
- scitex/browser/debugging/_visual_cursor.py +432 -0
- 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/scholar/citation_graph/database.py +9 -2
- scitex/scholar/config/ScholarConfig.py +23 -3
- scitex/scholar/config/default.yaml +55 -0
- scitex/scholar/core/Paper.py +102 -0
- scitex/scholar/core/__init__.py +44 -0
- scitex/scholar/core/journal_normalizer.py +524 -0
- scitex/scholar/core/oa_cache.py +285 -0
- scitex/scholar/core/open_access.py +457 -0
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +137 -0
- scitex/scholar/pdf_download/strategies/__init__.py +6 -0
- scitex/scholar/pdf_download/strategies/open_access_download.py +186 -0
- scitex/scholar/pipelines/ScholarPipelineSearchParallel.py +18 -3
- scitex/scholar/pipelines/ScholarPipelineSearchSingle.py +15 -2
- 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.2.dist-info → scitex-2.5.0.dist-info}/METADATA +9 -2
- {scitex-2.4.2.dist-info → scitex-2.5.0.dist-info}/RECORD +61 -32
- scitex/vis/DJANGO_INTEGRATION.md +0 -677
- scitex/vis/editor/_web_editor.py +0 -1440
- scitex/vis/tmp.txt +0 -239
- {scitex-2.4.2.dist-info → scitex-2.5.0.dist-info}/WHEEL +0 -0
- {scitex-2.4.2.dist-info → scitex-2.5.0.dist-info}/entry_points.txt +0 -0
- {scitex-2.4.2.dist-info → scitex-2.5.0.dist-info}/licenses/LICENSE +0 -0
scitex/vis/editor/_defaults.py
CHANGED
|
@@ -197,9 +197,48 @@ def extract_defaults_from_metadata(metadata):
|
|
|
197
197
|
if legend:
|
|
198
198
|
defaults['legend_visible'] = legend.get('visible', True)
|
|
199
199
|
defaults['legend_frameon'] = legend.get('frameon', False)
|
|
200
|
-
|
|
200
|
+
loc = legend.get('loc', 'best')
|
|
201
|
+
# Convert numeric legend loc to string (matplotlib accepts both but GUI needs string)
|
|
202
|
+
defaults['legend_loc'] = _normalize_legend_loc(loc)
|
|
201
203
|
|
|
202
204
|
return defaults
|
|
203
205
|
|
|
204
206
|
|
|
207
|
+
def _normalize_legend_loc(loc):
|
|
208
|
+
"""Convert legend location to string format for GUI compatibility.
|
|
209
|
+
|
|
210
|
+
Matplotlib accepts both numeric codes and string locations for legends.
|
|
211
|
+
This function ensures consistency by converting numeric codes to strings.
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
loc : int or str
|
|
216
|
+
Legend location (numeric or string)
|
|
217
|
+
|
|
218
|
+
Returns
|
|
219
|
+
-------
|
|
220
|
+
str
|
|
221
|
+
String representation of legend location
|
|
222
|
+
"""
|
|
223
|
+
if isinstance(loc, str):
|
|
224
|
+
return loc
|
|
225
|
+
|
|
226
|
+
# Numeric to string mapping (matplotlib legend location codes)
|
|
227
|
+
loc_map = {
|
|
228
|
+
0: 'best',
|
|
229
|
+
1: 'upper right',
|
|
230
|
+
2: 'upper left',
|
|
231
|
+
3: 'lower left',
|
|
232
|
+
4: 'lower right',
|
|
233
|
+
5: 'right',
|
|
234
|
+
6: 'center left',
|
|
235
|
+
7: 'center right',
|
|
236
|
+
8: 'lower center',
|
|
237
|
+
9: 'upper center',
|
|
238
|
+
10: 'center',
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return loc_map.get(loc, 'best')
|
|
242
|
+
|
|
243
|
+
|
|
205
244
|
# EOF
|
scitex/vis/editor/_edit.py
CHANGED
|
@@ -7,11 +7,46 @@ from pathlib import Path
|
|
|
7
7
|
from typing import Union, Optional, Literal
|
|
8
8
|
import hashlib
|
|
9
9
|
import json
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _print_available_backends():
|
|
14
|
+
"""Print available backends status."""
|
|
15
|
+
backends = {
|
|
16
|
+
"flask": ["flask"],
|
|
17
|
+
"dearpygui": ["dearpygui"],
|
|
18
|
+
"qt": ["PyQt6", "PyQt5", "PySide6", "PySide2"],
|
|
19
|
+
"tkinter": ["tkinter"],
|
|
20
|
+
"mpl": ["matplotlib"],
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
print("\n" + "=" * 50)
|
|
24
|
+
print("SciTeX Visual Editor - Available Backends")
|
|
25
|
+
print("=" * 50)
|
|
26
|
+
|
|
27
|
+
for backend, packages in backends.items():
|
|
28
|
+
available = False
|
|
29
|
+
available_pkg = None
|
|
30
|
+
for pkg in packages:
|
|
31
|
+
try:
|
|
32
|
+
__import__(pkg)
|
|
33
|
+
available = True
|
|
34
|
+
available_pkg = pkg
|
|
35
|
+
break
|
|
36
|
+
except ImportError:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
status = f"[OK] {available_pkg}" if available else "[NOT INSTALLED]"
|
|
40
|
+
print(f" {backend:12s}: {status}")
|
|
41
|
+
|
|
42
|
+
print("=" * 50)
|
|
43
|
+
print("Install: pip install scitex[gui]")
|
|
44
|
+
print("=" * 50 + "\n")
|
|
10
45
|
|
|
11
46
|
|
|
12
47
|
def edit(
|
|
13
48
|
path: Union[str, Path],
|
|
14
|
-
backend: Literal["auto", "
|
|
49
|
+
backend: Literal["auto", "flask", "dearpygui", "qt", "tkinter", "mpl"] = "auto",
|
|
15
50
|
apply_manual: bool = True,
|
|
16
51
|
) -> None:
|
|
17
52
|
"""
|
|
@@ -28,8 +63,8 @@ def edit(
|
|
|
28
63
|
backend : str, optional
|
|
29
64
|
GUI backend to use (default: "auto"):
|
|
30
65
|
- "auto": Pick best available with graceful degradation
|
|
31
|
-
(
|
|
32
|
-
- "
|
|
66
|
+
(flask -> dearpygui -> qt -> tkinter -> mpl)
|
|
67
|
+
- "flask": Browser-based editor (Flask, modern UI)
|
|
33
68
|
- "dearpygui": GPU-accelerated modern GUI (fast, requires dearpygui)
|
|
34
69
|
- "qt": Rich desktop editor (requires PyQt5/6 or PySide2/6)
|
|
35
70
|
- "tkinter": Built-in Python GUI (works everywhere)
|
|
@@ -46,7 +81,7 @@ def edit(
|
|
|
46
81
|
--------
|
|
47
82
|
>>> import scitex as stx
|
|
48
83
|
>>> stx.vis.edit("output/figure.json") # Auto-select best backend
|
|
49
|
-
>>> stx.vis.edit("output/figure.png", backend="
|
|
84
|
+
>>> stx.vis.edit("output/figure.png", backend="flask") # Force flask editor
|
|
50
85
|
>>> stx.vis.edit("output/figure.json", backend="tkinter") # Force tkinter
|
|
51
86
|
|
|
52
87
|
Notes
|
|
@@ -54,7 +89,7 @@ def edit(
|
|
|
54
89
|
- Changes are saved to `{basename}.manual.json` alongside the original
|
|
55
90
|
- Manual JSON includes hash of base JSON for staleness detection
|
|
56
91
|
- Original JSON/CSV files are never modified
|
|
57
|
-
- Backend auto-detection order:
|
|
92
|
+
- Backend auto-detection order: flask > dearpygui > qt > tkinter > mpl
|
|
58
93
|
"""
|
|
59
94
|
path = Path(path)
|
|
60
95
|
|
|
@@ -82,10 +117,14 @@ def edit(
|
|
|
82
117
|
if backend == "auto":
|
|
83
118
|
backend = _detect_best_backend()
|
|
84
119
|
|
|
120
|
+
# Print status
|
|
121
|
+
_print_available_backends()
|
|
122
|
+
print(f"Launching {backend} editor for: {json_path}")
|
|
123
|
+
|
|
85
124
|
# Launch appropriate backend
|
|
86
|
-
if backend == "
|
|
125
|
+
if backend == "flask":
|
|
87
126
|
try:
|
|
88
|
-
from .
|
|
127
|
+
from ._flask_editor import WebEditor
|
|
89
128
|
editor = WebEditor(
|
|
90
129
|
json_path=json_path,
|
|
91
130
|
metadata=metadata,
|
|
@@ -96,7 +135,7 @@ def edit(
|
|
|
96
135
|
editor.run()
|
|
97
136
|
except ImportError as e:
|
|
98
137
|
raise ImportError(
|
|
99
|
-
"
|
|
138
|
+
"Flask backend requires Flask. "
|
|
100
139
|
"Install with: pip install flask"
|
|
101
140
|
) from e
|
|
102
141
|
elif backend == "dearpygui":
|
|
@@ -106,6 +145,7 @@ def edit(
|
|
|
106
145
|
json_path=json_path,
|
|
107
146
|
metadata=metadata,
|
|
108
147
|
csv_data=csv_data,
|
|
148
|
+
png_path=png_path,
|
|
109
149
|
manual_overrides=manual_overrides,
|
|
110
150
|
)
|
|
111
151
|
editor.run()
|
|
@@ -121,6 +161,7 @@ def edit(
|
|
|
121
161
|
json_path=json_path,
|
|
122
162
|
metadata=metadata,
|
|
123
163
|
csv_data=csv_data,
|
|
164
|
+
png_path=png_path,
|
|
124
165
|
manual_overrides=manual_overrides,
|
|
125
166
|
)
|
|
126
167
|
editor.run()
|
|
@@ -150,7 +191,7 @@ def edit(
|
|
|
150
191
|
else:
|
|
151
192
|
raise ValueError(
|
|
152
193
|
f"Unknown backend: {backend}. "
|
|
153
|
-
"Use 'auto', '
|
|
194
|
+
"Use 'auto', 'flask', 'dearpygui', 'qt', 'tkinter', or 'mpl'."
|
|
154
195
|
)
|
|
155
196
|
|
|
156
197
|
|
|
@@ -158,20 +199,15 @@ def _detect_best_backend() -> str:
|
|
|
158
199
|
"""
|
|
159
200
|
Detect the best available GUI backend with graceful degradation.
|
|
160
201
|
|
|
161
|
-
Order:
|
|
202
|
+
Order: flask > dearpygui > qt > tkinter > mpl
|
|
162
203
|
Shows warnings when falling back to less capable backends.
|
|
163
204
|
"""
|
|
164
205
|
import warnings
|
|
165
206
|
|
|
166
|
-
# Try
|
|
207
|
+
# Try Flask - best for modern UI
|
|
167
208
|
try:
|
|
168
209
|
import flask
|
|
169
|
-
return "
|
|
170
|
-
except ImportError:
|
|
171
|
-
pass
|
|
172
|
-
try:
|
|
173
|
-
import fastapi
|
|
174
|
-
return "web"
|
|
210
|
+
return "flask"
|
|
175
211
|
except ImportError:
|
|
176
212
|
pass
|
|
177
213
|
|
|
@@ -181,7 +217,7 @@ def _detect_best_backend() -> str:
|
|
|
181
217
|
return "dearpygui"
|
|
182
218
|
except ImportError:
|
|
183
219
|
warnings.warn(
|
|
184
|
-
"
|
|
220
|
+
"Flask not available. Consider: pip install flask\n"
|
|
185
221
|
"Trying DearPyGui..."
|
|
186
222
|
)
|
|
187
223
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# File: ./src/scitex/vis/editor/_flask_editor.py
|
|
4
|
+
"""Web-based figure editor using Flask.
|
|
5
|
+
|
|
6
|
+
This module re-exports from the flask_editor package for backward compatibility.
|
|
7
|
+
The actual implementation is in the flask_editor/ subpackage.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .flask_editor import (
|
|
11
|
+
WebEditor,
|
|
12
|
+
find_available_port,
|
|
13
|
+
kill_process_on_port,
|
|
14
|
+
check_port_available,
|
|
15
|
+
render_preview_with_bboxes,
|
|
16
|
+
plot_from_csv,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Legacy aliases for backward compatibility
|
|
20
|
+
_find_available_port = find_available_port
|
|
21
|
+
_kill_process_on_port = kill_process_on_port
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
'WebEditor',
|
|
26
|
+
'find_available_port',
|
|
27
|
+
'kill_process_on_port',
|
|
28
|
+
'check_port_available',
|
|
29
|
+
'render_preview_with_bboxes',
|
|
30
|
+
'plot_from_csv',
|
|
31
|
+
# Legacy aliases
|
|
32
|
+
'_find_available_port',
|
|
33
|
+
'_kill_process_on_port',
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# EOF
|