scitex 2.14.0__py3-none-any.whl → 2.15.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 (218) hide show
  1. scitex/__init__.py +47 -0
  2. scitex/_env_loader.py +156 -0
  3. scitex/_mcp_resources/__init__.py +37 -0
  4. scitex/_mcp_resources/_cheatsheet.py +135 -0
  5. scitex/_mcp_resources/_figrecipe.py +138 -0
  6. scitex/_mcp_resources/_formats.py +102 -0
  7. scitex/_mcp_resources/_modules.py +337 -0
  8. scitex/_mcp_resources/_session.py +149 -0
  9. scitex/_mcp_tools/__init__.py +4 -0
  10. scitex/_mcp_tools/audio.py +66 -0
  11. scitex/_mcp_tools/diagram.py +11 -95
  12. scitex/_mcp_tools/introspect.py +191 -0
  13. scitex/_mcp_tools/plt.py +260 -305
  14. scitex/_mcp_tools/scholar.py +74 -0
  15. scitex/_mcp_tools/social.py +244 -0
  16. scitex/_mcp_tools/writer.py +21 -204
  17. scitex/ai/_gen_ai/_PARAMS.py +10 -7
  18. scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
  19. scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
  20. scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
  21. scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
  22. scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
  23. scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
  24. scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
  25. scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
  26. scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
  27. scitex/audio/README.md +40 -36
  28. scitex/audio/__init__.py +127 -59
  29. scitex/audio/_branding.py +185 -0
  30. scitex/audio/_mcp/__init__.py +32 -0
  31. scitex/audio/_mcp/handlers.py +59 -6
  32. scitex/audio/_mcp/speak_handlers.py +238 -0
  33. scitex/audio/_relay.py +225 -0
  34. scitex/audio/engines/elevenlabs_engine.py +6 -1
  35. scitex/audio/mcp_server.py +228 -75
  36. scitex/canvas/README.md +1 -1
  37. scitex/canvas/editor/_dearpygui/__init__.py +25 -0
  38. scitex/canvas/editor/_dearpygui/_editor.py +147 -0
  39. scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
  40. scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
  41. scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
  42. scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
  43. scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
  44. scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
  45. scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
  46. scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
  47. scitex/canvas/editor/_dearpygui/_selection.py +295 -0
  48. scitex/canvas/editor/_dearpygui/_state.py +93 -0
  49. scitex/canvas/editor/_dearpygui/_utils.py +61 -0
  50. scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
  51. scitex/cli/__init__.py +38 -43
  52. scitex/cli/audio.py +76 -27
  53. scitex/cli/capture.py +13 -20
  54. scitex/cli/introspect.py +443 -0
  55. scitex/cli/main.py +198 -109
  56. scitex/cli/mcp.py +60 -34
  57. scitex/cli/scholar/__init__.py +8 -0
  58. scitex/cli/scholar/_crossref_scitex.py +296 -0
  59. scitex/cli/scholar/_fetch.py +25 -3
  60. scitex/cli/social.py +314 -0
  61. scitex/cli/writer.py +117 -0
  62. scitex/config/README.md +1 -1
  63. scitex/config/__init__.py +16 -2
  64. scitex/config/_env_registry.py +191 -0
  65. scitex/diagram/__init__.py +42 -19
  66. scitex/diagram/mcp_server.py +13 -125
  67. scitex/introspect/__init__.py +75 -0
  68. scitex/introspect/_call_graph.py +303 -0
  69. scitex/introspect/_class_hierarchy.py +163 -0
  70. scitex/introspect/_core.py +42 -0
  71. scitex/introspect/_docstring.py +131 -0
  72. scitex/introspect/_examples.py +113 -0
  73. scitex/introspect/_imports.py +271 -0
  74. scitex/introspect/_mcp/__init__.py +37 -0
  75. scitex/introspect/_mcp/handlers.py +208 -0
  76. scitex/introspect/_members.py +151 -0
  77. scitex/introspect/_resolve.py +89 -0
  78. scitex/introspect/_signature.py +131 -0
  79. scitex/introspect/_source.py +80 -0
  80. scitex/introspect/_type_hints.py +172 -0
  81. scitex/io/bundle/README.md +1 -1
  82. scitex/mcp_server.py +98 -5
  83. scitex/plt/__init__.py +248 -550
  84. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
  85. scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  86. scitex/plt/gallery/README.md +1 -1
  87. scitex/plt/utils/_hitmap/__init__.py +82 -0
  88. scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
  89. scitex/plt/utils/_hitmap/_color_application.py +346 -0
  90. scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
  91. scitex/plt/utils/_hitmap/_constants.py +40 -0
  92. scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
  93. scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
  94. scitex/plt/utils/_hitmap/_query.py +113 -0
  95. scitex/plt/utils/_hitmap.py +46 -1616
  96. scitex/plt/utils/_metadata/__init__.py +80 -0
  97. scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
  98. scitex/plt/utils/_metadata/_artists/_base.py +195 -0
  99. scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
  100. scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
  101. scitex/plt/utils/_metadata/_artists/_images.py +80 -0
  102. scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
  103. scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
  104. scitex/plt/utils/_metadata/_artists/_text.py +106 -0
  105. scitex/plt/utils/_metadata/_csv.py +416 -0
  106. scitex/plt/utils/_metadata/_detect.py +225 -0
  107. scitex/plt/utils/_metadata/_legend.py +127 -0
  108. scitex/plt/utils/_metadata/_rounding.py +117 -0
  109. scitex/plt/utils/_metadata/_verification.py +202 -0
  110. scitex/schema/README.md +1 -1
  111. scitex/scholar/__init__.py +8 -0
  112. scitex/scholar/_mcp/crossref_handlers.py +265 -0
  113. scitex/scholar/core/Scholar.py +63 -1700
  114. scitex/scholar/core/_mixins/__init__.py +36 -0
  115. scitex/scholar/core/_mixins/_enrichers.py +270 -0
  116. scitex/scholar/core/_mixins/_library_handlers.py +100 -0
  117. scitex/scholar/core/_mixins/_loaders.py +103 -0
  118. scitex/scholar/core/_mixins/_pdf_download.py +375 -0
  119. scitex/scholar/core/_mixins/_pipeline.py +312 -0
  120. scitex/scholar/core/_mixins/_project_handlers.py +125 -0
  121. scitex/scholar/core/_mixins/_savers.py +69 -0
  122. scitex/scholar/core/_mixins/_search.py +103 -0
  123. scitex/scholar/core/_mixins/_services.py +88 -0
  124. scitex/scholar/core/_mixins/_url_finding.py +105 -0
  125. scitex/scholar/crossref_scitex.py +367 -0
  126. scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  127. scitex/scholar/examples/00_run_all.sh +120 -0
  128. scitex/scholar/jobs/_executors.py +27 -3
  129. scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
  130. scitex/scholar/pdf_download/_cli.py +154 -0
  131. scitex/scholar/pdf_download/strategies/__init__.py +11 -8
  132. scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
  133. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
  134. scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
  135. scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
  136. scitex/scholar/pipelines/_single_steps.py +71 -36
  137. scitex/scholar/storage/_LibraryManager.py +97 -1695
  138. scitex/scholar/storage/_mixins/__init__.py +30 -0
  139. scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
  140. scitex/scholar/storage/_mixins/_library_operations.py +218 -0
  141. scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
  142. scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
  143. scitex/scholar/storage/_mixins/_resolution.py +376 -0
  144. scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
  145. scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
  146. scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
  147. scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
  148. scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
  149. scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
  150. scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
  151. scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
  152. scitex/security/README.md +3 -3
  153. scitex/session/README.md +1 -1
  154. scitex/sh/README.md +1 -1
  155. scitex/social/__init__.py +153 -0
  156. scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  157. scitex/template/README.md +1 -1
  158. scitex/template/clone_writer_directory.py +5 -5
  159. scitex/writer/README.md +1 -1
  160. scitex/writer/_mcp/handlers.py +11 -744
  161. scitex/writer/_mcp/tool_schemas.py +5 -335
  162. scitex-2.15.1.dist-info/METADATA +648 -0
  163. {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/RECORD +166 -111
  164. scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
  165. scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
  166. scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
  167. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
  168. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
  169. scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
  170. scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
  171. scitex/diagram/_compile.py +0 -312
  172. scitex/diagram/_diagram.py +0 -355
  173. scitex/diagram/_mcp/__init__.py +0 -4
  174. scitex/diagram/_mcp/handlers.py +0 -400
  175. scitex/diagram/_mcp/tool_schemas.py +0 -157
  176. scitex/diagram/_presets.py +0 -173
  177. scitex/diagram/_schema.py +0 -182
  178. scitex/diagram/_split.py +0 -278
  179. scitex/plt/_mcp/__init__.py +0 -4
  180. scitex/plt/_mcp/_handlers_annotation.py +0 -102
  181. scitex/plt/_mcp/_handlers_figure.py +0 -195
  182. scitex/plt/_mcp/_handlers_plot.py +0 -252
  183. scitex/plt/_mcp/_handlers_style.py +0 -219
  184. scitex/plt/_mcp/handlers.py +0 -74
  185. scitex/plt/_mcp/tool_schemas.py +0 -497
  186. scitex/plt/mcp_server.py +0 -231
  187. scitex/scholar/data/.gitkeep +0 -0
  188. scitex/scholar/data/README.md +0 -44
  189. scitex/scholar/data/bib_files/bibliography.bib +0 -1952
  190. scitex/scholar/data/bib_files/neurovista.bib +0 -277
  191. scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
  192. scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
  193. scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
  194. scitex/scholar/data/bib_files/openaccess.bib +0 -89
  195. scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
  196. scitex/scholar/data/bib_files/pac.bib +0 -698
  197. scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
  198. scitex/scholar/data/bib_files/pac_processed.bib +0 -0
  199. scitex/scholar/data/bib_files/pac_titles.txt +0 -75
  200. scitex/scholar/data/bib_files/paywalled.bib +0 -98
  201. scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
  202. scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
  203. scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
  204. scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
  205. scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
  206. scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
  207. scitex/scholar/data/bib_files/test_seizure.bib +0 -46
  208. scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
  209. scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
  210. scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
  211. scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
  212. scitex/scholar/data/impact_factor.db +0 -0
  213. scitex/scholar/examples/SUGGESTIONS.md +0 -865
  214. scitex/scholar/examples/dev.py +0 -38
  215. scitex-2.14.0.dist-info/METADATA +0 -1238
  216. {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/WHEEL +0 -0
  217. {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/entry_points.txt +0 -0
  218. {scitex-2.14.0.dist-info → scitex-2.15.1.dist-info}/licenses/LICENSE +0 -0
@@ -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