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
scitex/gen/_title_case.py
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
#!./env/bin/python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# Time-stamp: "2024-04-24 15:05:34"
|
|
4
|
-
# Author: Yusuke Watanabe (ywatanabe@scitex.ai)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"""
|
|
8
|
-
This script does XYZ.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
"""
|
|
12
|
-
Imports
|
|
13
|
-
"""
|
|
14
|
-
import sys
|
|
15
|
-
|
|
16
|
-
import matplotlib.pyplot as plt
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"""
|
|
20
|
-
Config
|
|
21
|
-
"""
|
|
22
|
-
# CONFIG = scitex.gen.load_configs()
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"""
|
|
26
|
-
Functions & Classes
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def title_case(text):
|
|
31
|
-
"""
|
|
32
|
-
Converts a string to title case while keeping certain prepositions, conjunctions, and articles in lowercase,
|
|
33
|
-
and ensuring words detected as potential acronyms (all uppercase) are fully capitalized.
|
|
34
|
-
|
|
35
|
-
Parameters:
|
|
36
|
-
- text (str): The text to convert to title case.
|
|
37
|
-
|
|
38
|
-
Returns:
|
|
39
|
-
- str: The converted text in title case with certain words in lowercase and potential acronyms fully capitalized.
|
|
40
|
-
|
|
41
|
-
Examples:
|
|
42
|
-
--------
|
|
43
|
-
print(title_case("welcome to the world of ai and using CPUs for gaming")) # Welcome to the World of AI and Using CPUs for Gaming
|
|
44
|
-
"""
|
|
45
|
-
# List of words to keep in lowercase
|
|
46
|
-
lowercase_words = [
|
|
47
|
-
"a",
|
|
48
|
-
"an",
|
|
49
|
-
"the",
|
|
50
|
-
"and",
|
|
51
|
-
"but",
|
|
52
|
-
"or",
|
|
53
|
-
"nor",
|
|
54
|
-
"at",
|
|
55
|
-
"by",
|
|
56
|
-
"to",
|
|
57
|
-
"in",
|
|
58
|
-
"with",
|
|
59
|
-
"of",
|
|
60
|
-
"on",
|
|
61
|
-
]
|
|
62
|
-
|
|
63
|
-
words = text.split()
|
|
64
|
-
final_words = []
|
|
65
|
-
for word in words:
|
|
66
|
-
# Check if the word is fully in uppercase and more than one character, suggesting an acronym
|
|
67
|
-
if word.isupper() and len(word) > 1:
|
|
68
|
-
final_words.append(word)
|
|
69
|
-
elif word.lower() in lowercase_words:
|
|
70
|
-
final_words.append(word.lower())
|
|
71
|
-
else:
|
|
72
|
-
final_words.append(word.capitalize())
|
|
73
|
-
return " ".join(final_words)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def main():
|
|
77
|
-
# Example usage:
|
|
78
|
-
text = "welcome to the world of ai and using CPUs for gaming"
|
|
79
|
-
print(title_case(text))
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if __name__ == "__main__":
|
|
83
|
-
CONFIG, sys.stdout, sys.stderr, plt, CC = scitex.session.start(
|
|
84
|
-
sys, plt, verbose=False
|
|
85
|
-
)
|
|
86
|
-
main()
|
|
87
|
-
scitex.session.close(CONFIG, verbose=False, notify=False)
|
|
88
|
-
|
|
89
|
-
# EOF
|
scitex/plt/_mcp/__init__.py
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp: 2026-01-13
|
|
3
|
-
# File: src/scitex/plt/_mcp/_handlers_annotation.py
|
|
4
|
-
|
|
5
|
-
"""Annotation MCP handlers for SciTeX plt module."""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from typing import Optional
|
|
10
|
-
|
|
11
|
-
from ._handlers_figure import _get_axes
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
async def add_significance_handler(
|
|
15
|
-
x1: float,
|
|
16
|
-
x2: float,
|
|
17
|
-
y: float,
|
|
18
|
-
text: str,
|
|
19
|
-
figure_id: Optional[str] = None,
|
|
20
|
-
panel: str = "0,0",
|
|
21
|
-
height: Optional[float] = None,
|
|
22
|
-
) -> dict:
|
|
23
|
-
"""Add significance bracket between two groups."""
|
|
24
|
-
try:
|
|
25
|
-
from scitex.plt.styles.presets import SCITEX_STYLE
|
|
26
|
-
from scitex.plt.utils import mm_to_pt
|
|
27
|
-
|
|
28
|
-
fig, ax, fid = _get_axes(figure_id, panel)
|
|
29
|
-
|
|
30
|
-
ylim = ax.get_ylim()
|
|
31
|
-
ylim_range = float(ylim[1]) - float(ylim[0])
|
|
32
|
-
h = height if height else 0.1 * ylim_range
|
|
33
|
-
|
|
34
|
-
# Use SCITEX line width (0.2mm converted to points)
|
|
35
|
-
line_width_mm = SCITEX_STYLE.get("trace_thickness_mm", 0.2)
|
|
36
|
-
line_width_pt = mm_to_pt(line_width_mm)
|
|
37
|
-
|
|
38
|
-
# Draw bracket with SCITEX styling
|
|
39
|
-
ax.plot(
|
|
40
|
-
[x1, x1, x2, x2],
|
|
41
|
-
[y, y + h, y + h, y],
|
|
42
|
-
color="black",
|
|
43
|
-
linewidth=line_width_pt,
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
ax.text(
|
|
47
|
-
(x1 + x2) / 2,
|
|
48
|
-
y + h + 0.02 * ylim_range,
|
|
49
|
-
text,
|
|
50
|
-
ha="center",
|
|
51
|
-
va="bottom",
|
|
52
|
-
fontsize=6,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
"success": True,
|
|
57
|
-
"figure_id": fid,
|
|
58
|
-
"panel": panel,
|
|
59
|
-
"bracket": {"x1": x1, "x2": x2, "y": y, "text": text},
|
|
60
|
-
}
|
|
61
|
-
except Exception as e:
|
|
62
|
-
return {"success": False, "error": str(e)}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
async def add_panel_label_handler(
|
|
66
|
-
label: str,
|
|
67
|
-
figure_id: Optional[str] = None,
|
|
68
|
-
panel: str = "0,0",
|
|
69
|
-
x: float = -0.15,
|
|
70
|
-
y: float = 1.1,
|
|
71
|
-
fontsize: float = 10,
|
|
72
|
-
fontweight: str = "bold",
|
|
73
|
-
) -> dict:
|
|
74
|
-
"""Add panel label (A, B, C, etc.) to a panel."""
|
|
75
|
-
try:
|
|
76
|
-
fig, ax, fid = _get_axes(figure_id, panel)
|
|
77
|
-
|
|
78
|
-
ax.text(
|
|
79
|
-
x,
|
|
80
|
-
y,
|
|
81
|
-
label,
|
|
82
|
-
transform=ax.transAxes,
|
|
83
|
-
fontsize=fontsize,
|
|
84
|
-
fontweight=fontweight,
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
"success": True,
|
|
89
|
-
"figure_id": fid,
|
|
90
|
-
"panel": panel,
|
|
91
|
-
"label": label,
|
|
92
|
-
}
|
|
93
|
-
except Exception as e:
|
|
94
|
-
return {"success": False, "error": str(e)}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
__all__ = [
|
|
98
|
-
"add_significance_handler",
|
|
99
|
-
"add_panel_label_handler",
|
|
100
|
-
]
|
|
101
|
-
|
|
102
|
-
# EOF
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp: 2026-01-13
|
|
3
|
-
# File: src/scitex/plt/_mcp/_handlers_figure.py
|
|
4
|
-
|
|
5
|
-
"""Figure management MCP handlers for SciTeX plt module."""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
import asyncio
|
|
10
|
-
from typing import Any, Optional
|
|
11
|
-
|
|
12
|
-
# Figure registry for tracking active figures across MCP calls
|
|
13
|
-
_FIGURE_REGISTRY: dict[str, dict[str, Any]] = {}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def _get_axes(figure_id: Optional[str], panel: str):
|
|
17
|
-
"""Helper to get axes from figure registry."""
|
|
18
|
-
if figure_id is None:
|
|
19
|
-
if not _FIGURE_REGISTRY:
|
|
20
|
-
raise ValueError("No active figures. Call create_figure first.")
|
|
21
|
-
figure_id = list(_FIGURE_REGISTRY.keys())[-1]
|
|
22
|
-
|
|
23
|
-
if figure_id not in _FIGURE_REGISTRY:
|
|
24
|
-
raise ValueError(f"Figure '{figure_id}' not found")
|
|
25
|
-
|
|
26
|
-
fig_data = _FIGURE_REGISTRY[figure_id]
|
|
27
|
-
axes = fig_data["axes"]
|
|
28
|
-
|
|
29
|
-
if "," in panel:
|
|
30
|
-
row, col = map(int, panel.split(","))
|
|
31
|
-
try:
|
|
32
|
-
ax = axes[row, col]
|
|
33
|
-
except (TypeError, IndexError):
|
|
34
|
-
ax = axes
|
|
35
|
-
else:
|
|
36
|
-
idx = ord(panel.upper()) - ord("A")
|
|
37
|
-
if hasattr(axes, "flat"):
|
|
38
|
-
ax = list(axes.flat)[idx]
|
|
39
|
-
elif hasattr(axes, "__getitem__"):
|
|
40
|
-
ax = axes[idx]
|
|
41
|
-
else:
|
|
42
|
-
ax = axes
|
|
43
|
-
|
|
44
|
-
return fig_data["fig"], ax, figure_id
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
async def create_figure_handler(
|
|
48
|
-
nrows: int = 1,
|
|
49
|
-
ncols: int = 1,
|
|
50
|
-
axes_width_mm: Optional[float] = None,
|
|
51
|
-
axes_height_mm: Optional[float] = None,
|
|
52
|
-
space_w_mm: Optional[float] = None,
|
|
53
|
-
space_h_mm: Optional[float] = None,
|
|
54
|
-
) -> dict:
|
|
55
|
-
"""Create a multi-panel figure canvas with SciTeX style."""
|
|
56
|
-
import uuid
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
import scitex.plt as splt
|
|
60
|
-
|
|
61
|
-
kwargs = {"nrows": nrows, "ncols": ncols}
|
|
62
|
-
if axes_width_mm is not None:
|
|
63
|
-
kwargs["axes_width_mm"] = axes_width_mm
|
|
64
|
-
if axes_height_mm is not None:
|
|
65
|
-
kwargs["axes_height_mm"] = axes_height_mm
|
|
66
|
-
if space_w_mm is not None:
|
|
67
|
-
kwargs["space_w_mm"] = space_w_mm
|
|
68
|
-
if space_h_mm is not None:
|
|
69
|
-
kwargs["space_h_mm"] = space_h_mm
|
|
70
|
-
|
|
71
|
-
fig, axes = splt.subplots(**kwargs)
|
|
72
|
-
|
|
73
|
-
figure_id = str(uuid.uuid4())[:8]
|
|
74
|
-
|
|
75
|
-
_FIGURE_REGISTRY[figure_id] = {
|
|
76
|
-
"fig": fig,
|
|
77
|
-
"axes": axes,
|
|
78
|
-
"nrows": nrows,
|
|
79
|
-
"ncols": ncols,
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
"success": True,
|
|
84
|
-
"figure_id": figure_id,
|
|
85
|
-
"nrows": nrows,
|
|
86
|
-
"ncols": ncols,
|
|
87
|
-
"message": f"Created {nrows}x{ncols} figure with SciTeX style",
|
|
88
|
-
}
|
|
89
|
-
except Exception as e:
|
|
90
|
-
return {"success": False, "error": str(e)}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
async def crop_figure_handler(
|
|
94
|
-
input_path: str,
|
|
95
|
-
output_path: Optional[str] = None,
|
|
96
|
-
margin: int = 12,
|
|
97
|
-
overwrite: bool = False,
|
|
98
|
-
) -> dict:
|
|
99
|
-
"""Auto-crop whitespace from a saved figure image."""
|
|
100
|
-
try:
|
|
101
|
-
from scitex.plt import crop
|
|
102
|
-
|
|
103
|
-
loop = asyncio.get_event_loop()
|
|
104
|
-
result_path = await loop.run_in_executor(
|
|
105
|
-
None,
|
|
106
|
-
lambda: crop(
|
|
107
|
-
input_path=input_path,
|
|
108
|
-
output_path=output_path,
|
|
109
|
-
margin=margin,
|
|
110
|
-
overwrite=overwrite,
|
|
111
|
-
),
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
"success": True,
|
|
116
|
-
"input_path": input_path,
|
|
117
|
-
"output_path": str(result_path),
|
|
118
|
-
"margin_pixels": margin,
|
|
119
|
-
"message": f"Cropped figure saved to {result_path}",
|
|
120
|
-
}
|
|
121
|
-
except Exception as e:
|
|
122
|
-
return {"success": False, "error": str(e)}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
async def save_figure_handler(
|
|
126
|
-
output_path: str,
|
|
127
|
-
figure_id: Optional[str] = None,
|
|
128
|
-
dpi: int = 300,
|
|
129
|
-
crop: bool = True,
|
|
130
|
-
) -> dict:
|
|
131
|
-
"""Save the figure to file."""
|
|
132
|
-
try:
|
|
133
|
-
if figure_id is None:
|
|
134
|
-
if not _FIGURE_REGISTRY:
|
|
135
|
-
raise ValueError("No active figures")
|
|
136
|
-
figure_id = list(_FIGURE_REGISTRY.keys())[-1]
|
|
137
|
-
|
|
138
|
-
if figure_id not in _FIGURE_REGISTRY:
|
|
139
|
-
raise ValueError(f"Figure '{figure_id}' not found")
|
|
140
|
-
|
|
141
|
-
fig = _FIGURE_REGISTRY[figure_id]["fig"]
|
|
142
|
-
|
|
143
|
-
fig.savefig(output_path, dpi=dpi, bbox_inches="tight")
|
|
144
|
-
|
|
145
|
-
final_path = output_path
|
|
146
|
-
if crop and output_path.endswith(".png"):
|
|
147
|
-
from scitex.plt import crop as crop_fn
|
|
148
|
-
|
|
149
|
-
final_path = crop_fn(output_path, overwrite=True)
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
"success": True,
|
|
153
|
-
"figure_id": figure_id,
|
|
154
|
-
"output_path": str(final_path),
|
|
155
|
-
"dpi": dpi,
|
|
156
|
-
"cropped": crop,
|
|
157
|
-
}
|
|
158
|
-
except Exception as e:
|
|
159
|
-
return {"success": False, "error": str(e)}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
async def close_figure_handler(figure_id: Optional[str] = None) -> dict:
|
|
163
|
-
"""Close a figure and free memory."""
|
|
164
|
-
try:
|
|
165
|
-
import scitex.plt as splt
|
|
166
|
-
|
|
167
|
-
if figure_id is None:
|
|
168
|
-
if not _FIGURE_REGISTRY:
|
|
169
|
-
return {"success": True, "message": "No figures to close"}
|
|
170
|
-
figure_id = list(_FIGURE_REGISTRY.keys())[-1]
|
|
171
|
-
|
|
172
|
-
if figure_id in _FIGURE_REGISTRY:
|
|
173
|
-
fig = _FIGURE_REGISTRY[figure_id]["fig"]
|
|
174
|
-
splt.close(fig)
|
|
175
|
-
del _FIGURE_REGISTRY[figure_id]
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
"success": True,
|
|
179
|
-
"figure_id": figure_id,
|
|
180
|
-
"message": f"Closed figure {figure_id}",
|
|
181
|
-
}
|
|
182
|
-
except Exception as e:
|
|
183
|
-
return {"success": False, "error": str(e)}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
__all__ = [
|
|
187
|
-
"_FIGURE_REGISTRY",
|
|
188
|
-
"_get_axes",
|
|
189
|
-
"create_figure_handler",
|
|
190
|
-
"crop_figure_handler",
|
|
191
|
-
"save_figure_handler",
|
|
192
|
-
"close_figure_handler",
|
|
193
|
-
]
|
|
194
|
-
|
|
195
|
-
# EOF
|
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp: 2026-01-13
|
|
3
|
-
# File: src/scitex/plt/_mcp/_handlers_plot.py
|
|
4
|
-
|
|
5
|
-
"""Plot-related MCP handlers for SciTeX plt module."""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from typing import Optional
|
|
10
|
-
|
|
11
|
-
from ._handlers_figure import _get_axes
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
async def plot_bar_handler(
|
|
15
|
-
x: list[str],
|
|
16
|
-
y: list[float],
|
|
17
|
-
figure_id: Optional[str] = None,
|
|
18
|
-
panel: str = "0,0",
|
|
19
|
-
yerr: Optional[list[float]] = None,
|
|
20
|
-
colors: Optional[list[str]] = None,
|
|
21
|
-
xlabel: Optional[str] = None,
|
|
22
|
-
ylabel: Optional[str] = None,
|
|
23
|
-
title: Optional[str] = None,
|
|
24
|
-
) -> dict:
|
|
25
|
-
"""Create a bar plot on specified panel."""
|
|
26
|
-
try:
|
|
27
|
-
fig, ax, fid = _get_axes(figure_id, panel)
|
|
28
|
-
|
|
29
|
-
if colors is None:
|
|
30
|
-
from scitex.plt import color as color_module
|
|
31
|
-
|
|
32
|
-
params = getattr(color_module, "PARAMS", {})
|
|
33
|
-
rgba_cycle = params.get("RGBA_NORM_FOR_CYCLE", {})
|
|
34
|
-
color_list = list(rgba_cycle.values())
|
|
35
|
-
colors = color_list[: len(x)] if color_list else None
|
|
36
|
-
|
|
37
|
-
ax.bar(x, y, yerr=yerr, capsize=3, color=colors)
|
|
38
|
-
|
|
39
|
-
if xlabel:
|
|
40
|
-
ax.set_xlabel(xlabel)
|
|
41
|
-
if ylabel:
|
|
42
|
-
ax.set_ylabel(ylabel)
|
|
43
|
-
if title:
|
|
44
|
-
ax.set_title(title)
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
"success": True,
|
|
48
|
-
"figure_id": fid,
|
|
49
|
-
"panel": panel,
|
|
50
|
-
"plot_type": "bar",
|
|
51
|
-
"n_bars": len(x),
|
|
52
|
-
}
|
|
53
|
-
except Exception as e:
|
|
54
|
-
return {"success": False, "error": str(e)}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
async def plot_scatter_handler(
|
|
58
|
-
x: list[float],
|
|
59
|
-
y: list[float],
|
|
60
|
-
figure_id: Optional[str] = None,
|
|
61
|
-
panel: str = "0,0",
|
|
62
|
-
color: Optional[str] = None,
|
|
63
|
-
size: Optional[float] = None,
|
|
64
|
-
alpha: float = 0.7,
|
|
65
|
-
add_regression: bool = False,
|
|
66
|
-
xlabel: Optional[str] = None,
|
|
67
|
-
ylabel: Optional[str] = None,
|
|
68
|
-
title: Optional[str] = None,
|
|
69
|
-
) -> dict:
|
|
70
|
-
"""Create a scatter plot on specified panel."""
|
|
71
|
-
try:
|
|
72
|
-
import numpy as np
|
|
73
|
-
|
|
74
|
-
fig, ax, fid = _get_axes(figure_id, panel)
|
|
75
|
-
|
|
76
|
-
if color is None:
|
|
77
|
-
color = "#c633ff" # SciTeX purple
|
|
78
|
-
|
|
79
|
-
s = (size * 2.83465) ** 2 if size else 15
|
|
80
|
-
|
|
81
|
-
ax.scatter(x, y, c=color, s=s, alpha=alpha)
|
|
82
|
-
|
|
83
|
-
if add_regression:
|
|
84
|
-
z = np.polyfit(x, y, 1)
|
|
85
|
-
p = np.poly1d(z)
|
|
86
|
-
x_line = np.linspace(min(x), max(x), 100)
|
|
87
|
-
ax.plot(x_line, p(x_line), color="#e25e33", linestyle="--", linewidth=1)
|
|
88
|
-
|
|
89
|
-
if xlabel:
|
|
90
|
-
ax.set_xlabel(xlabel)
|
|
91
|
-
if ylabel:
|
|
92
|
-
ax.set_ylabel(ylabel)
|
|
93
|
-
if title:
|
|
94
|
-
ax.set_title(title)
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
"success": True,
|
|
98
|
-
"figure_id": fid,
|
|
99
|
-
"panel": panel,
|
|
100
|
-
"plot_type": "scatter",
|
|
101
|
-
"n_points": len(x),
|
|
102
|
-
"regression_added": add_regression,
|
|
103
|
-
}
|
|
104
|
-
except Exception as e:
|
|
105
|
-
return {"success": False, "error": str(e)}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
async def plot_line_handler(
|
|
109
|
-
x: list[float],
|
|
110
|
-
y: list[float],
|
|
111
|
-
figure_id: Optional[str] = None,
|
|
112
|
-
panel: str = "0,0",
|
|
113
|
-
yerr: Optional[list[float]] = None,
|
|
114
|
-
color: Optional[str] = None,
|
|
115
|
-
label: Optional[str] = None,
|
|
116
|
-
linestyle: str = "-",
|
|
117
|
-
xlabel: Optional[str] = None,
|
|
118
|
-
ylabel: Optional[str] = None,
|
|
119
|
-
title: Optional[str] = None,
|
|
120
|
-
) -> dict:
|
|
121
|
-
"""Create a line plot on specified panel."""
|
|
122
|
-
try:
|
|
123
|
-
fig, ax, fid = _get_axes(figure_id, panel)
|
|
124
|
-
|
|
125
|
-
if color is None:
|
|
126
|
-
color = "#007fbf" # SciTeX blue
|
|
127
|
-
|
|
128
|
-
ax.plot(x, y, color=color, label=label, linestyle=linestyle)
|
|
129
|
-
|
|
130
|
-
if yerr:
|
|
131
|
-
import numpy as np
|
|
132
|
-
|
|
133
|
-
y_arr = np.array(y)
|
|
134
|
-
yerr_arr = np.array(yerr)
|
|
135
|
-
ax.fill_between(
|
|
136
|
-
x, y_arr - yerr_arr, y_arr + yerr_arr, alpha=0.3, color=color
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
if xlabel:
|
|
140
|
-
ax.set_xlabel(xlabel)
|
|
141
|
-
if ylabel:
|
|
142
|
-
ax.set_ylabel(ylabel)
|
|
143
|
-
if title:
|
|
144
|
-
ax.set_title(title)
|
|
145
|
-
if label:
|
|
146
|
-
ax.legend(loc="upper right", frameon=False)
|
|
147
|
-
|
|
148
|
-
return {
|
|
149
|
-
"success": True,
|
|
150
|
-
"figure_id": fid,
|
|
151
|
-
"panel": panel,
|
|
152
|
-
"plot_type": "line",
|
|
153
|
-
"n_points": len(x),
|
|
154
|
-
}
|
|
155
|
-
except Exception as e:
|
|
156
|
-
return {"success": False, "error": str(e)}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
async def plot_box_handler(
|
|
160
|
-
data: list[list[float]],
|
|
161
|
-
figure_id: Optional[str] = None,
|
|
162
|
-
panel: str = "0,0",
|
|
163
|
-
labels: Optional[list[str]] = None,
|
|
164
|
-
colors: Optional[list[str]] = None,
|
|
165
|
-
xlabel: Optional[str] = None,
|
|
166
|
-
ylabel: Optional[str] = None,
|
|
167
|
-
title: Optional[str] = None,
|
|
168
|
-
) -> dict:
|
|
169
|
-
"""Create a box plot on specified panel."""
|
|
170
|
-
try:
|
|
171
|
-
fig, ax, fid = _get_axes(figure_id, panel)
|
|
172
|
-
|
|
173
|
-
bp = ax.boxplot(data, patch_artist=True, widths=0.6)
|
|
174
|
-
|
|
175
|
-
if colors is None:
|
|
176
|
-
colors = ["#007fbf", "#ff4433", "#14b514", "#c633ff", "#e25e33"]
|
|
177
|
-
for i, box in enumerate(bp["boxes"]):
|
|
178
|
-
box.set_facecolor(colors[i % len(colors)])
|
|
179
|
-
|
|
180
|
-
if labels:
|
|
181
|
-
ax.set_xticklabels(labels)
|
|
182
|
-
if xlabel:
|
|
183
|
-
ax.set_xlabel(xlabel)
|
|
184
|
-
if ylabel:
|
|
185
|
-
ax.set_ylabel(ylabel)
|
|
186
|
-
if title:
|
|
187
|
-
ax.set_title(title)
|
|
188
|
-
|
|
189
|
-
return {
|
|
190
|
-
"success": True,
|
|
191
|
-
"figure_id": fid,
|
|
192
|
-
"panel": panel,
|
|
193
|
-
"plot_type": "box",
|
|
194
|
-
"n_groups": len(data),
|
|
195
|
-
}
|
|
196
|
-
except Exception as e:
|
|
197
|
-
return {"success": False, "error": str(e)}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
async def plot_violin_handler(
|
|
201
|
-
data: list[list[float]],
|
|
202
|
-
figure_id: Optional[str] = None,
|
|
203
|
-
panel: str = "0,0",
|
|
204
|
-
labels: Optional[list[str]] = None,
|
|
205
|
-
colors: Optional[list[str]] = None,
|
|
206
|
-
xlabel: Optional[str] = None,
|
|
207
|
-
ylabel: Optional[str] = None,
|
|
208
|
-
title: Optional[str] = None,
|
|
209
|
-
) -> dict:
|
|
210
|
-
"""Create a violin plot on specified panel."""
|
|
211
|
-
try:
|
|
212
|
-
fig, ax, fid = _get_axes(figure_id, panel)
|
|
213
|
-
|
|
214
|
-
positions = list(range(1, len(data) + 1))
|
|
215
|
-
vp = ax.violinplot(data, positions=positions, showmedians=True, widths=0.7)
|
|
216
|
-
|
|
217
|
-
if colors is None:
|
|
218
|
-
colors = ["#007fbf", "#ff4433", "#14b514", "#c633ff", "#e25e33"]
|
|
219
|
-
for i, body in enumerate(vp["bodies"]):
|
|
220
|
-
body.set_facecolor(colors[i % len(colors)])
|
|
221
|
-
body.set_alpha(0.6)
|
|
222
|
-
|
|
223
|
-
if labels:
|
|
224
|
-
ax.set_xticks(positions)
|
|
225
|
-
ax.set_xticklabels(labels)
|
|
226
|
-
if xlabel:
|
|
227
|
-
ax.set_xlabel(xlabel)
|
|
228
|
-
if ylabel:
|
|
229
|
-
ax.set_ylabel(ylabel)
|
|
230
|
-
if title:
|
|
231
|
-
ax.set_title(title)
|
|
232
|
-
|
|
233
|
-
return {
|
|
234
|
-
"success": True,
|
|
235
|
-
"figure_id": fid,
|
|
236
|
-
"panel": panel,
|
|
237
|
-
"plot_type": "violin",
|
|
238
|
-
"n_groups": len(data),
|
|
239
|
-
}
|
|
240
|
-
except Exception as e:
|
|
241
|
-
return {"success": False, "error": str(e)}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
__all__ = [
|
|
245
|
-
"plot_bar_handler",
|
|
246
|
-
"plot_scatter_handler",
|
|
247
|
-
"plot_line_handler",
|
|
248
|
-
"plot_box_handler",
|
|
249
|
-
"plot_violin_handler",
|
|
250
|
-
]
|
|
251
|
-
|
|
252
|
-
# EOF
|