scitex 2.14.0__py3-none-any.whl → 2.15.3__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/__init__.py +71 -17
- scitex/_env_loader.py +156 -0
- scitex/_mcp_resources/__init__.py +37 -0
- scitex/_mcp_resources/_cheatsheet.py +135 -0
- scitex/_mcp_resources/_figrecipe.py +138 -0
- scitex/_mcp_resources/_formats.py +102 -0
- scitex/_mcp_resources/_modules.py +337 -0
- scitex/_mcp_resources/_session.py +149 -0
- scitex/_mcp_tools/__init__.py +4 -0
- scitex/_mcp_tools/audio.py +66 -0
- scitex/_mcp_tools/diagram.py +11 -95
- scitex/_mcp_tools/introspect.py +210 -0
- scitex/_mcp_tools/plt.py +260 -305
- scitex/_mcp_tools/scholar.py +74 -0
- scitex/_mcp_tools/social.py +27 -0
- scitex/_mcp_tools/template.py +24 -0
- scitex/_mcp_tools/writer.py +17 -210
- scitex/ai/_gen_ai/_PARAMS.py +10 -7
- scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
- scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
- scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
- scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
- scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
- scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
- scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
- scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
- scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +30 -1550
- scitex/ai/classification/timeseries/_sliding_window_core.py +467 -0
- scitex/ai/classification/timeseries/_sliding_window_plotting.py +369 -0
- scitex/audio/README.md +40 -36
- scitex/audio/__init__.py +129 -61
- scitex/audio/_branding.py +185 -0
- scitex/audio/_mcp/__init__.py +32 -0
- scitex/audio/_mcp/handlers.py +59 -6
- scitex/audio/_mcp/speak_handlers.py +238 -0
- scitex/audio/_relay.py +225 -0
- scitex/audio/_tts.py +18 -10
- scitex/audio/engines/base.py +17 -10
- scitex/audio/engines/elevenlabs_engine.py +7 -2
- scitex/audio/mcp_server.py +228 -75
- scitex/canvas/README.md +1 -1
- scitex/canvas/editor/_dearpygui/__init__.py +25 -0
- scitex/canvas/editor/_dearpygui/_editor.py +147 -0
- scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
- scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
- scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
- scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
- scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
- scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
- scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
- scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
- scitex/canvas/editor/_dearpygui/_selection.py +295 -0
- scitex/canvas/editor/_dearpygui/_state.py +93 -0
- scitex/canvas/editor/_dearpygui/_utils.py +61 -0
- scitex/canvas/editor/flask_editor/_core/__init__.py +27 -0
- scitex/canvas/editor/flask_editor/_core/_bbox_extraction.py +200 -0
- scitex/canvas/editor/flask_editor/_core/_editor.py +173 -0
- scitex/canvas/editor/flask_editor/_core/_export_helpers.py +353 -0
- scitex/canvas/editor/flask_editor/_core/_routes_basic.py +190 -0
- scitex/canvas/editor/flask_editor/_core/_routes_export.py +332 -0
- scitex/canvas/editor/flask_editor/_core/_routes_panels.py +252 -0
- scitex/canvas/editor/flask_editor/_core/_routes_save.py +218 -0
- scitex/canvas/editor/flask_editor/_core.py +25 -1684
- scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
- scitex/cli/__init__.py +38 -43
- scitex/cli/audio.py +160 -41
- scitex/cli/capture.py +133 -20
- scitex/cli/introspect.py +488 -0
- scitex/cli/main.py +200 -109
- scitex/cli/mcp.py +60 -34
- scitex/cli/plt.py +414 -0
- scitex/cli/repro.py +15 -8
- scitex/cli/resource.py +15 -8
- scitex/cli/scholar/__init__.py +154 -8
- scitex/cli/scholar/_crossref_scitex.py +296 -0
- scitex/cli/scholar/_fetch.py +25 -3
- scitex/cli/social.py +355 -0
- scitex/cli/stats.py +136 -11
- scitex/cli/template.py +129 -12
- scitex/cli/tex.py +15 -8
- scitex/cli/writer.py +49 -299
- scitex/cloud/__init__.py +41 -2
- scitex/config/README.md +1 -1
- scitex/config/__init__.py +16 -2
- scitex/config/_env_registry.py +256 -0
- scitex/context/__init__.py +22 -0
- scitex/dev/__init__.py +20 -1
- scitex/diagram/__init__.py +42 -19
- scitex/diagram/mcp_server.py +13 -125
- scitex/gen/__init__.py +50 -14
- scitex/gen/_list_packages.py +4 -4
- scitex/introspect/__init__.py +82 -0
- scitex/introspect/_call_graph.py +303 -0
- scitex/introspect/_class_hierarchy.py +163 -0
- scitex/introspect/_core.py +41 -0
- scitex/introspect/_docstring.py +131 -0
- scitex/introspect/_examples.py +113 -0
- scitex/introspect/_imports.py +271 -0
- scitex/{gen/_inspect_module.py → introspect/_list_api.py} +48 -56
- scitex/introspect/_mcp/__init__.py +41 -0
- scitex/introspect/_mcp/handlers.py +233 -0
- scitex/introspect/_members.py +155 -0
- scitex/introspect/_resolve.py +89 -0
- scitex/introspect/_signature.py +131 -0
- scitex/introspect/_source.py +80 -0
- scitex/introspect/_type_hints.py +172 -0
- scitex/io/_save.py +1 -2
- scitex/io/bundle/README.md +1 -1
- scitex/logging/_formatters.py +19 -9
- scitex/mcp_server.py +98 -5
- scitex/os/__init__.py +4 -0
- scitex/{gen → os}/_check_host.py +4 -5
- scitex/plt/__init__.py +245 -550
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
- scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/plt/gallery/README.md +1 -1
- scitex/plt/utils/_hitmap/__init__.py +82 -0
- scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
- scitex/plt/utils/_hitmap/_color_application.py +346 -0
- scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
- scitex/plt/utils/_hitmap/_constants.py +40 -0
- scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
- scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
- scitex/plt/utils/_hitmap/_query.py +113 -0
- scitex/plt/utils/_hitmap.py +46 -1616
- scitex/plt/utils/_metadata/__init__.py +80 -0
- scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
- scitex/plt/utils/_metadata/_artists/_base.py +195 -0
- scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
- scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
- scitex/plt/utils/_metadata/_artists/_images.py +80 -0
- scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
- scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
- scitex/plt/utils/_metadata/_artists/_text.py +106 -0
- scitex/plt/utils/_metadata/_csv.py +416 -0
- scitex/plt/utils/_metadata/_detect.py +225 -0
- scitex/plt/utils/_metadata/_legend.py +127 -0
- scitex/plt/utils/_metadata/_rounding.py +117 -0
- scitex/plt/utils/_metadata/_verification.py +202 -0
- scitex/schema/README.md +1 -1
- scitex/scholar/__init__.py +8 -0
- scitex/scholar/_mcp/crossref_handlers.py +265 -0
- scitex/scholar/core/Scholar.py +63 -1700
- scitex/scholar/core/_mixins/__init__.py +36 -0
- scitex/scholar/core/_mixins/_enrichers.py +270 -0
- scitex/scholar/core/_mixins/_library_handlers.py +100 -0
- scitex/scholar/core/_mixins/_loaders.py +103 -0
- scitex/scholar/core/_mixins/_pdf_download.py +375 -0
- scitex/scholar/core/_mixins/_pipeline.py +312 -0
- scitex/scholar/core/_mixins/_project_handlers.py +125 -0
- scitex/scholar/core/_mixins/_savers.py +69 -0
- scitex/scholar/core/_mixins/_search.py +103 -0
- scitex/scholar/core/_mixins/_services.py +88 -0
- scitex/scholar/core/_mixins/_url_finding.py +105 -0
- scitex/scholar/crossref_scitex.py +367 -0
- scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/scholar/examples/00_run_all.sh +120 -0
- scitex/scholar/jobs/_executors.py +27 -3
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
- scitex/scholar/pdf_download/_cli.py +154 -0
- scitex/scholar/pdf_download/strategies/__init__.py +11 -8
- scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
- scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
- scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
- scitex/scholar/pipelines/_single_steps.py +71 -36
- scitex/scholar/storage/_LibraryManager.py +97 -1695
- scitex/scholar/storage/_mixins/__init__.py +30 -0
- scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
- scitex/scholar/storage/_mixins/_library_operations.py +218 -0
- scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
- scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
- scitex/scholar/storage/_mixins/_resolution.py +376 -0
- scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
- scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
- scitex/security/README.md +3 -3
- scitex/session/README.md +1 -1
- scitex/session/__init__.py +26 -7
- scitex/session/_decorator.py +1 -1
- scitex/sh/README.md +1 -1
- scitex/sh/__init__.py +7 -4
- scitex/social/__init__.py +155 -0
- scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/stats/_mcp/_handlers/__init__.py +31 -0
- scitex/stats/_mcp/_handlers/_corrections.py +113 -0
- scitex/stats/_mcp/_handlers/_descriptive.py +78 -0
- scitex/stats/_mcp/_handlers/_effect_size.py +106 -0
- scitex/stats/_mcp/_handlers/_format.py +94 -0
- scitex/stats/_mcp/_handlers/_normality.py +110 -0
- scitex/stats/_mcp/_handlers/_posthoc.py +224 -0
- scitex/stats/_mcp/_handlers/_power.py +247 -0
- scitex/stats/_mcp/_handlers/_recommend.py +102 -0
- scitex/stats/_mcp/_handlers/_run_test.py +279 -0
- scitex/stats/_mcp/_handlers/_stars.py +48 -0
- scitex/stats/_mcp/handlers.py +19 -1171
- scitex/stats/auto/_stat_style.py +175 -0
- scitex/stats/auto/_style_definitions.py +411 -0
- scitex/stats/auto/_styles.py +22 -620
- scitex/stats/descriptive/__init__.py +11 -8
- scitex/stats/descriptive/_ci.py +39 -0
- scitex/stats/power/_power.py +15 -4
- scitex/str/__init__.py +2 -1
- scitex/str/_title_case.py +63 -0
- scitex/template/README.md +1 -1
- scitex/template/__init__.py +25 -10
- scitex/template/_code_templates.py +147 -0
- scitex/template/_mcp/handlers.py +81 -0
- scitex/template/_mcp/tool_schemas.py +55 -0
- scitex/template/_templates/__init__.py +51 -0
- scitex/template/_templates/audio.py +233 -0
- scitex/template/_templates/canvas.py +312 -0
- scitex/template/_templates/capture.py +268 -0
- scitex/template/_templates/config.py +43 -0
- scitex/template/_templates/diagram.py +294 -0
- scitex/template/_templates/io.py +107 -0
- scitex/template/_templates/module.py +53 -0
- scitex/template/_templates/plt.py +202 -0
- scitex/template/_templates/scholar.py +267 -0
- scitex/template/_templates/session.py +130 -0
- scitex/template/_templates/session_minimal.py +43 -0
- scitex/template/_templates/session_plot.py +67 -0
- scitex/template/_templates/session_stats.py +77 -0
- scitex/template/_templates/stats.py +323 -0
- scitex/template/_templates/writer.py +296 -0
- scitex/template/clone_writer_directory.py +5 -5
- scitex/ui/_backends/_email.py +10 -2
- scitex/ui/_backends/_webhook.py +5 -1
- scitex/web/_search_pubmed.py +10 -6
- scitex/writer/README.md +1 -1
- scitex/writer/__init__.py +43 -34
- scitex/writer/_mcp/handlers.py +11 -744
- scitex/writer/_mcp/tool_schemas.py +5 -335
- scitex-2.15.3.dist-info/METADATA +667 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/RECORD +241 -120
- scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
- scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
- scitex/diagram/_compile.py +0 -312
- scitex/diagram/_diagram.py +0 -355
- scitex/diagram/_mcp/__init__.py +0 -4
- scitex/diagram/_mcp/handlers.py +0 -400
- scitex/diagram/_mcp/tool_schemas.py +0 -157
- scitex/diagram/_presets.py +0 -173
- scitex/diagram/_schema.py +0 -182
- scitex/diagram/_split.py +0 -278
- scitex/gen/_ci.py +0 -12
- scitex/gen/_title_case.py +0 -89
- scitex/plt/_mcp/__init__.py +0 -4
- scitex/plt/_mcp/_handlers_annotation.py +0 -102
- scitex/plt/_mcp/_handlers_figure.py +0 -195
- scitex/plt/_mcp/_handlers_plot.py +0 -252
- scitex/plt/_mcp/_handlers_style.py +0 -219
- scitex/plt/_mcp/handlers.py +0 -74
- scitex/plt/_mcp/tool_schemas.py +0 -497
- scitex/plt/mcp_server.py +0 -231
- scitex/scholar/examples/SUGGESTIONS.md +0 -865
- scitex/scholar/examples/dev.py +0 -38
- scitex-2.14.0.dist-info/METADATA +0 -1238
- /scitex/{gen → context}/_detect_environment.py +0 -0
- /scitex/{gen → context}/_get_notebook_path.py +0 -0
- /scitex/{gen/_shell.py → sh/_shell_legacy.py} +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/WHEEL +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/entry_points.txt +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: "2026-01-24 (ywatanabe)"
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-python/src/scitex/canvas/editor/flask_editor/_core/_routes_save.py
|
|
4
|
+
|
|
5
|
+
"""Save-related Flask routes for the editor."""
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from .._core import WebEditor
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"create_save_route",
|
|
14
|
+
"create_save_layout_route",
|
|
15
|
+
"create_save_element_position_route",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create_save_route(app, editor: "WebEditor"):
|
|
20
|
+
"""Create the save route."""
|
|
21
|
+
from flask import jsonify
|
|
22
|
+
|
|
23
|
+
from ..edit import save_manual_overrides
|
|
24
|
+
|
|
25
|
+
@app.route("/save", methods=["POST"])
|
|
26
|
+
def save():
|
|
27
|
+
try:
|
|
28
|
+
manual_path = save_manual_overrides(
|
|
29
|
+
editor.json_path, editor.current_overrides
|
|
30
|
+
)
|
|
31
|
+
return jsonify({"status": "saved", "path": str(manual_path)})
|
|
32
|
+
except Exception as e:
|
|
33
|
+
return jsonify({"status": "error", "message": str(e)}), 500
|
|
34
|
+
|
|
35
|
+
return save
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def create_save_layout_route(app, editor: "WebEditor"):
|
|
39
|
+
"""Create the save_layout route."""
|
|
40
|
+
from flask import jsonify, request
|
|
41
|
+
|
|
42
|
+
from ._export_helpers import export_composed_figure
|
|
43
|
+
|
|
44
|
+
@app.route("/save_layout", methods=["POST"])
|
|
45
|
+
def save_layout():
|
|
46
|
+
try:
|
|
47
|
+
data = request.get_json()
|
|
48
|
+
layout = data.get("layout", {})
|
|
49
|
+
|
|
50
|
+
if not layout:
|
|
51
|
+
return jsonify({"success": False, "error": "No layout data provided"})
|
|
52
|
+
|
|
53
|
+
if not editor.panel_info:
|
|
54
|
+
return jsonify(
|
|
55
|
+
{
|
|
56
|
+
"success": False,
|
|
57
|
+
"error": "No panel info available (not a figure bundle)",
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
bundle_path = editor.panel_info.get("bundle_path")
|
|
62
|
+
if not bundle_path:
|
|
63
|
+
return jsonify({"success": False, "error": "Bundle path not available"})
|
|
64
|
+
|
|
65
|
+
from scitex.canvas.io import ZipBundle
|
|
66
|
+
|
|
67
|
+
bundle = ZipBundle(bundle_path)
|
|
68
|
+
|
|
69
|
+
# Read existing layout or create new one
|
|
70
|
+
try:
|
|
71
|
+
existing_layout = bundle.read_json("layout.json")
|
|
72
|
+
except:
|
|
73
|
+
existing_layout = {}
|
|
74
|
+
|
|
75
|
+
# Update layout with new positions
|
|
76
|
+
for panel_name, pos in layout.items():
|
|
77
|
+
if panel_name not in existing_layout:
|
|
78
|
+
existing_layout[panel_name] = {}
|
|
79
|
+
if "position" not in existing_layout[panel_name]:
|
|
80
|
+
existing_layout[panel_name]["position"] = {}
|
|
81
|
+
if "size" not in existing_layout[panel_name]:
|
|
82
|
+
existing_layout[panel_name]["size"] = {}
|
|
83
|
+
|
|
84
|
+
existing_layout[panel_name]["position"]["x_mm"] = pos.get("x_mm", 0)
|
|
85
|
+
existing_layout[panel_name]["position"]["y_mm"] = pos.get("y_mm", 0)
|
|
86
|
+
|
|
87
|
+
if "width_mm" in pos:
|
|
88
|
+
existing_layout[panel_name]["size"]["width_mm"] = pos["width_mm"]
|
|
89
|
+
if "height_mm" in pos:
|
|
90
|
+
existing_layout[panel_name]["size"]["height_mm"] = pos["height_mm"]
|
|
91
|
+
|
|
92
|
+
bundle.write_json("layout.json", existing_layout)
|
|
93
|
+
editor.panel_info["layout"] = existing_layout
|
|
94
|
+
|
|
95
|
+
# Auto-export composed figure
|
|
96
|
+
export_result = export_composed_figure(editor, formats=["png", "svg"])
|
|
97
|
+
|
|
98
|
+
return jsonify(
|
|
99
|
+
{
|
|
100
|
+
"success": True,
|
|
101
|
+
"layout": existing_layout,
|
|
102
|
+
"exported": export_result.get("exported", {}),
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
except Exception as e:
|
|
107
|
+
import traceback
|
|
108
|
+
|
|
109
|
+
return jsonify(
|
|
110
|
+
{
|
|
111
|
+
"success": False,
|
|
112
|
+
"error": str(e),
|
|
113
|
+
"traceback": traceback.format_exc(),
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return save_layout
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def create_save_element_position_route(app, editor: "WebEditor"):
|
|
121
|
+
"""Create the save_element_position route.
|
|
122
|
+
|
|
123
|
+
ONLY legends and panel letters can be repositioned to maintain
|
|
124
|
+
scientific rigor. Data elements are never moved.
|
|
125
|
+
"""
|
|
126
|
+
from flask import jsonify, request
|
|
127
|
+
|
|
128
|
+
@app.route("/save_element_position", methods=["POST"])
|
|
129
|
+
def save_element_position():
|
|
130
|
+
try:
|
|
131
|
+
data = request.get_json()
|
|
132
|
+
element = data.get("element", "")
|
|
133
|
+
panel = data.get("panel", "")
|
|
134
|
+
element_type = data.get("element_type", "")
|
|
135
|
+
position = data.get("position", {})
|
|
136
|
+
snap_name = data.get("snap_name")
|
|
137
|
+
|
|
138
|
+
# Validate element type (whitelist for scientific rigor)
|
|
139
|
+
ALLOWED_TYPES = ["legend", "panel_letter"]
|
|
140
|
+
if element_type not in ALLOWED_TYPES:
|
|
141
|
+
return jsonify(
|
|
142
|
+
{
|
|
143
|
+
"success": False,
|
|
144
|
+
"error": f"Element type '{element_type}' cannot be repositioned (scientific rigor)",
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if not editor.panel_info:
|
|
149
|
+
return jsonify({"success": False, "error": "No panel info available"})
|
|
150
|
+
|
|
151
|
+
bundle_path = editor.panel_info.get("bundle_path")
|
|
152
|
+
if not bundle_path:
|
|
153
|
+
return jsonify({"success": False, "error": "Bundle path not available"})
|
|
154
|
+
|
|
155
|
+
from scitex.canvas.io import ZipBundle
|
|
156
|
+
|
|
157
|
+
bundle = ZipBundle(bundle_path)
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
style = bundle.read_json("style.json")
|
|
161
|
+
except:
|
|
162
|
+
style = {}
|
|
163
|
+
|
|
164
|
+
if "elements" not in style:
|
|
165
|
+
style["elements"] = {}
|
|
166
|
+
if panel not in style["elements"]:
|
|
167
|
+
style["elements"][panel] = {}
|
|
168
|
+
|
|
169
|
+
style["elements"][panel][element] = {
|
|
170
|
+
"type": element_type,
|
|
171
|
+
"position": position,
|
|
172
|
+
"snap_name": snap_name,
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
# For legends, update legend_location for matplotlib compatibility
|
|
176
|
+
if element_type == "legend" and snap_name:
|
|
177
|
+
loc_map = {
|
|
178
|
+
"upper left": "upper left",
|
|
179
|
+
"upper center": "upper center",
|
|
180
|
+
"upper right": "upper right",
|
|
181
|
+
"center left": "center left",
|
|
182
|
+
"center": "center",
|
|
183
|
+
"center right": "center right",
|
|
184
|
+
"lower left": "lower left",
|
|
185
|
+
"lower center": "lower center",
|
|
186
|
+
"lower right": "lower right",
|
|
187
|
+
}
|
|
188
|
+
if snap_name in loc_map:
|
|
189
|
+
if "legend" not in style:
|
|
190
|
+
style["legend"] = {}
|
|
191
|
+
style["legend"]["location"] = loc_map[snap_name]
|
|
192
|
+
|
|
193
|
+
bundle.write_json("style.json", style)
|
|
194
|
+
|
|
195
|
+
return jsonify(
|
|
196
|
+
{
|
|
197
|
+
"success": True,
|
|
198
|
+
"element": element,
|
|
199
|
+
"position": position,
|
|
200
|
+
"snap_name": snap_name,
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
except Exception as e:
|
|
205
|
+
import traceback
|
|
206
|
+
|
|
207
|
+
return jsonify(
|
|
208
|
+
{
|
|
209
|
+
"success": False,
|
|
210
|
+
"error": str(e),
|
|
211
|
+
"traceback": traceback.format_exc(),
|
|
212
|
+
}
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
return save_element_position
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# EOF
|