scitex 2.14.0__py3-none-any.whl → 2.15.2__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 (300) hide show
  1. scitex/__init__.py +71 -17
  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 +210 -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/template.py +24 -0
  17. scitex/_mcp_tools/writer.py +21 -204
  18. scitex/ai/_gen_ai/_PARAMS.py +10 -7
  19. scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
  20. scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
  21. scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
  22. scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
  23. scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
  24. scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
  25. scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
  26. scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
  27. scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
  28. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +30 -1550
  29. scitex/ai/classification/timeseries/_sliding_window_core.py +467 -0
  30. scitex/ai/classification/timeseries/_sliding_window_plotting.py +369 -0
  31. scitex/audio/README.md +40 -36
  32. scitex/audio/__init__.py +129 -61
  33. scitex/audio/_branding.py +185 -0
  34. scitex/audio/_mcp/__init__.py +32 -0
  35. scitex/audio/_mcp/handlers.py +59 -6
  36. scitex/audio/_mcp/speak_handlers.py +238 -0
  37. scitex/audio/_relay.py +225 -0
  38. scitex/audio/_tts.py +18 -10
  39. scitex/audio/engines/base.py +17 -10
  40. scitex/audio/engines/elevenlabs_engine.py +7 -2
  41. scitex/audio/mcp_server.py +228 -75
  42. scitex/canvas/README.md +1 -1
  43. scitex/canvas/editor/_dearpygui/__init__.py +25 -0
  44. scitex/canvas/editor/_dearpygui/_editor.py +147 -0
  45. scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
  46. scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
  47. scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
  48. scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
  49. scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
  50. scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
  51. scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
  52. scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
  53. scitex/canvas/editor/_dearpygui/_selection.py +295 -0
  54. scitex/canvas/editor/_dearpygui/_state.py +93 -0
  55. scitex/canvas/editor/_dearpygui/_utils.py +61 -0
  56. scitex/canvas/editor/flask_editor/_core/__init__.py +27 -0
  57. scitex/canvas/editor/flask_editor/_core/_bbox_extraction.py +200 -0
  58. scitex/canvas/editor/flask_editor/_core/_editor.py +173 -0
  59. scitex/canvas/editor/flask_editor/_core/_export_helpers.py +353 -0
  60. scitex/canvas/editor/flask_editor/_core/_routes_basic.py +190 -0
  61. scitex/canvas/editor/flask_editor/_core/_routes_export.py +332 -0
  62. scitex/canvas/editor/flask_editor/_core/_routes_panels.py +252 -0
  63. scitex/canvas/editor/flask_editor/_core/_routes_save.py +218 -0
  64. scitex/canvas/editor/flask_editor/_core.py +25 -1684
  65. scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
  66. scitex/cli/__init__.py +38 -43
  67. scitex/cli/audio.py +76 -27
  68. scitex/cli/capture.py +13 -20
  69. scitex/cli/introspect.py +481 -0
  70. scitex/cli/main.py +200 -109
  71. scitex/cli/mcp.py +60 -34
  72. scitex/cli/plt.py +357 -0
  73. scitex/cli/repro.py +15 -8
  74. scitex/cli/resource.py +15 -8
  75. scitex/cli/scholar/__init__.py +23 -8
  76. scitex/cli/scholar/_crossref_scitex.py +296 -0
  77. scitex/cli/scholar/_fetch.py +25 -3
  78. scitex/cli/social.py +314 -0
  79. scitex/cli/stats.py +15 -8
  80. scitex/cli/template.py +129 -12
  81. scitex/cli/tex.py +15 -8
  82. scitex/cli/writer.py +132 -8
  83. scitex/cloud/__init__.py +41 -2
  84. scitex/config/README.md +1 -1
  85. scitex/config/__init__.py +16 -2
  86. scitex/config/_env_registry.py +256 -0
  87. scitex/context/__init__.py +22 -0
  88. scitex/dev/__init__.py +20 -1
  89. scitex/diagram/__init__.py +42 -19
  90. scitex/diagram/mcp_server.py +13 -125
  91. scitex/gen/__init__.py +50 -14
  92. scitex/gen/_list_packages.py +4 -4
  93. scitex/introspect/__init__.py +82 -0
  94. scitex/introspect/_call_graph.py +303 -0
  95. scitex/introspect/_class_hierarchy.py +163 -0
  96. scitex/introspect/_core.py +41 -0
  97. scitex/introspect/_docstring.py +131 -0
  98. scitex/introspect/_examples.py +113 -0
  99. scitex/introspect/_imports.py +271 -0
  100. scitex/{gen/_inspect_module.py → introspect/_list_api.py} +43 -54
  101. scitex/introspect/_mcp/__init__.py +41 -0
  102. scitex/introspect/_mcp/handlers.py +233 -0
  103. scitex/introspect/_members.py +155 -0
  104. scitex/introspect/_resolve.py +89 -0
  105. scitex/introspect/_signature.py +131 -0
  106. scitex/introspect/_source.py +80 -0
  107. scitex/introspect/_type_hints.py +172 -0
  108. scitex/io/_save.py +1 -2
  109. scitex/io/bundle/README.md +1 -1
  110. scitex/logging/_formatters.py +19 -9
  111. scitex/mcp_server.py +98 -5
  112. scitex/os/__init__.py +4 -0
  113. scitex/{gen → os}/_check_host.py +4 -5
  114. scitex/plt/__init__.py +245 -550
  115. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
  116. scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  117. scitex/plt/gallery/README.md +1 -1
  118. scitex/plt/utils/_hitmap/__init__.py +82 -0
  119. scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
  120. scitex/plt/utils/_hitmap/_color_application.py +346 -0
  121. scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
  122. scitex/plt/utils/_hitmap/_constants.py +40 -0
  123. scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
  124. scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
  125. scitex/plt/utils/_hitmap/_query.py +113 -0
  126. scitex/plt/utils/_hitmap.py +46 -1616
  127. scitex/plt/utils/_metadata/__init__.py +80 -0
  128. scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
  129. scitex/plt/utils/_metadata/_artists/_base.py +195 -0
  130. scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
  131. scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
  132. scitex/plt/utils/_metadata/_artists/_images.py +80 -0
  133. scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
  134. scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
  135. scitex/plt/utils/_metadata/_artists/_text.py +106 -0
  136. scitex/plt/utils/_metadata/_csv.py +416 -0
  137. scitex/plt/utils/_metadata/_detect.py +225 -0
  138. scitex/plt/utils/_metadata/_legend.py +127 -0
  139. scitex/plt/utils/_metadata/_rounding.py +117 -0
  140. scitex/plt/utils/_metadata/_verification.py +202 -0
  141. scitex/schema/README.md +1 -1
  142. scitex/scholar/__init__.py +8 -0
  143. scitex/scholar/_mcp/crossref_handlers.py +265 -0
  144. scitex/scholar/core/Scholar.py +63 -1700
  145. scitex/scholar/core/_mixins/__init__.py +36 -0
  146. scitex/scholar/core/_mixins/_enrichers.py +270 -0
  147. scitex/scholar/core/_mixins/_library_handlers.py +100 -0
  148. scitex/scholar/core/_mixins/_loaders.py +103 -0
  149. scitex/scholar/core/_mixins/_pdf_download.py +375 -0
  150. scitex/scholar/core/_mixins/_pipeline.py +312 -0
  151. scitex/scholar/core/_mixins/_project_handlers.py +125 -0
  152. scitex/scholar/core/_mixins/_savers.py +69 -0
  153. scitex/scholar/core/_mixins/_search.py +103 -0
  154. scitex/scholar/core/_mixins/_services.py +88 -0
  155. scitex/scholar/core/_mixins/_url_finding.py +105 -0
  156. scitex/scholar/crossref_scitex.py +367 -0
  157. scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  158. scitex/scholar/examples/00_run_all.sh +120 -0
  159. scitex/scholar/jobs/_executors.py +27 -3
  160. scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
  161. scitex/scholar/pdf_download/_cli.py +154 -0
  162. scitex/scholar/pdf_download/strategies/__init__.py +11 -8
  163. scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
  164. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
  165. scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
  166. scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
  167. scitex/scholar/pipelines/_single_steps.py +71 -36
  168. scitex/scholar/storage/_LibraryManager.py +97 -1695
  169. scitex/scholar/storage/_mixins/__init__.py +30 -0
  170. scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
  171. scitex/scholar/storage/_mixins/_library_operations.py +218 -0
  172. scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
  173. scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
  174. scitex/scholar/storage/_mixins/_resolution.py +376 -0
  175. scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
  176. scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
  177. scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
  178. scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
  179. scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
  180. scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
  181. scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
  182. scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
  183. scitex/security/README.md +3 -3
  184. scitex/session/README.md +1 -1
  185. scitex/session/__init__.py +26 -7
  186. scitex/session/_decorator.py +1 -1
  187. scitex/sh/README.md +1 -1
  188. scitex/sh/__init__.py +7 -4
  189. scitex/social/__init__.py +155 -0
  190. scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  191. scitex/stats/_mcp/_handlers/__init__.py +31 -0
  192. scitex/stats/_mcp/_handlers/_corrections.py +113 -0
  193. scitex/stats/_mcp/_handlers/_descriptive.py +78 -0
  194. scitex/stats/_mcp/_handlers/_effect_size.py +106 -0
  195. scitex/stats/_mcp/_handlers/_format.py +94 -0
  196. scitex/stats/_mcp/_handlers/_normality.py +110 -0
  197. scitex/stats/_mcp/_handlers/_posthoc.py +224 -0
  198. scitex/stats/_mcp/_handlers/_power.py +247 -0
  199. scitex/stats/_mcp/_handlers/_recommend.py +102 -0
  200. scitex/stats/_mcp/_handlers/_run_test.py +279 -0
  201. scitex/stats/_mcp/_handlers/_stars.py +48 -0
  202. scitex/stats/_mcp/handlers.py +19 -1171
  203. scitex/stats/auto/_stat_style.py +175 -0
  204. scitex/stats/auto/_style_definitions.py +411 -0
  205. scitex/stats/auto/_styles.py +22 -620
  206. scitex/stats/descriptive/__init__.py +11 -8
  207. scitex/stats/descriptive/_ci.py +39 -0
  208. scitex/stats/power/_power.py +15 -4
  209. scitex/str/__init__.py +2 -1
  210. scitex/str/_title_case.py +63 -0
  211. scitex/template/README.md +1 -1
  212. scitex/template/__init__.py +25 -10
  213. scitex/template/_code_templates.py +147 -0
  214. scitex/template/_mcp/handlers.py +81 -0
  215. scitex/template/_mcp/tool_schemas.py +55 -0
  216. scitex/template/_templates/__init__.py +51 -0
  217. scitex/template/_templates/audio.py +233 -0
  218. scitex/template/_templates/canvas.py +312 -0
  219. scitex/template/_templates/capture.py +268 -0
  220. scitex/template/_templates/config.py +43 -0
  221. scitex/template/_templates/diagram.py +294 -0
  222. scitex/template/_templates/io.py +107 -0
  223. scitex/template/_templates/module.py +53 -0
  224. scitex/template/_templates/plt.py +202 -0
  225. scitex/template/_templates/scholar.py +267 -0
  226. scitex/template/_templates/session.py +130 -0
  227. scitex/template/_templates/session_minimal.py +43 -0
  228. scitex/template/_templates/session_plot.py +67 -0
  229. scitex/template/_templates/session_stats.py +77 -0
  230. scitex/template/_templates/stats.py +323 -0
  231. scitex/template/_templates/writer.py +296 -0
  232. scitex/template/clone_writer_directory.py +5 -5
  233. scitex/ui/_backends/_email.py +10 -2
  234. scitex/ui/_backends/_webhook.py +5 -1
  235. scitex/web/_search_pubmed.py +10 -6
  236. scitex/writer/README.md +1 -1
  237. scitex/writer/_mcp/handlers.py +11 -744
  238. scitex/writer/_mcp/tool_schemas.py +5 -335
  239. scitex-2.15.2.dist-info/METADATA +648 -0
  240. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/RECORD +246 -150
  241. scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
  242. scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
  243. scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
  244. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
  245. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
  246. scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
  247. scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
  248. scitex/diagram/_compile.py +0 -312
  249. scitex/diagram/_diagram.py +0 -355
  250. scitex/diagram/_mcp/__init__.py +0 -4
  251. scitex/diagram/_mcp/handlers.py +0 -400
  252. scitex/diagram/_mcp/tool_schemas.py +0 -157
  253. scitex/diagram/_presets.py +0 -173
  254. scitex/diagram/_schema.py +0 -182
  255. scitex/diagram/_split.py +0 -278
  256. scitex/gen/_ci.py +0 -12
  257. scitex/gen/_title_case.py +0 -89
  258. scitex/plt/_mcp/__init__.py +0 -4
  259. scitex/plt/_mcp/_handlers_annotation.py +0 -102
  260. scitex/plt/_mcp/_handlers_figure.py +0 -195
  261. scitex/plt/_mcp/_handlers_plot.py +0 -252
  262. scitex/plt/_mcp/_handlers_style.py +0 -219
  263. scitex/plt/_mcp/handlers.py +0 -74
  264. scitex/plt/_mcp/tool_schemas.py +0 -497
  265. scitex/plt/mcp_server.py +0 -231
  266. scitex/scholar/data/.gitkeep +0 -0
  267. scitex/scholar/data/README.md +0 -44
  268. scitex/scholar/data/bib_files/bibliography.bib +0 -1952
  269. scitex/scholar/data/bib_files/neurovista.bib +0 -277
  270. scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
  271. scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
  272. scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
  273. scitex/scholar/data/bib_files/openaccess.bib +0 -89
  274. scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
  275. scitex/scholar/data/bib_files/pac.bib +0 -698
  276. scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
  277. scitex/scholar/data/bib_files/pac_processed.bib +0 -0
  278. scitex/scholar/data/bib_files/pac_titles.txt +0 -75
  279. scitex/scholar/data/bib_files/paywalled.bib +0 -98
  280. scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
  281. scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
  282. scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
  283. scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
  284. scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
  285. scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
  286. scitex/scholar/data/bib_files/test_seizure.bib +0 -46
  287. scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
  288. scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
  289. scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
  290. scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
  291. scitex/scholar/data/impact_factor.db +0 -0
  292. scitex/scholar/examples/SUGGESTIONS.md +0 -865
  293. scitex/scholar/examples/dev.py +0 -38
  294. scitex-2.14.0.dist-info/METADATA +0 -1238
  295. /scitex/{gen → context}/_detect_environment.py +0 -0
  296. /scitex/{gen → context}/_get_notebook_path.py +0 -0
  297. /scitex/{gen/_shell.py → sh/_shell_legacy.py} +0 -0
  298. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/WHEEL +0 -0
  299. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/entry_points.txt +0 -0
  300. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/licenses/LICENSE +0 -0
scitex/_mcp_tools/plt.py CHANGED
@@ -1,350 +1,305 @@
1
1
  #!/usr/bin/env python3
2
- # Timestamp: 2026-01-15
2
+ # Timestamp: 2026-01-24
3
3
  # File: /home/ywatanabe/proj/scitex-code/src/scitex/_mcp_tools/plt.py
4
- """Plt module tools for FastMCP unified server."""
4
+ """Plt module tools for FastMCP unified server.
5
5
 
6
- from __future__ import annotations
7
-
8
- import json
9
- from typing import Optional
6
+ This module delegates to figrecipe's MCP tools for single source of truth.
7
+ All plt_* tools are thin wrappers around figrecipe's canonical implementation.
8
+ """
10
9
 
10
+ from __future__ import annotations
11
11
 
12
- def _json(data: dict) -> str:
13
- return json.dumps(data, indent=2, default=str)
12
+ import os
13
+ from typing import Any, Dict, List, Optional, Tuple
14
14
 
15
15
 
16
16
  def register_plt_tools(mcp) -> None:
17
- """Register plt tools with FastMCP server."""
17
+ """Register plt tools with FastMCP server.
18
18
 
19
- # Style tools
20
- @mcp.tool()
21
- async def plt_get_style() -> str:
22
- """[plt] Get current SciTeX publication style configuration."""
23
- from scitex.plt._mcp._handlers_style import get_style_handler
19
+ Delegates to figrecipe's plt tools (canonical source).
20
+ Tools are prefixed with 'plt_' for scitex namespace consistency.
21
+ """
22
+ # Ensure branding is set before any figrecipe imports
23
+ os.environ.setdefault("FIGRECIPE_BRAND", "scitex.plt")
24
+ os.environ.setdefault("FIGRECIPE_ALIAS", "plt")
24
25
 
25
- result = await get_style_handler()
26
- return _json(result)
26
+ # Check if figrecipe is available
27
+ try:
28
+ from figrecipe._mcp import server as fr_mcp
27
29
 
28
- @mcp.tool()
29
- async def plt_set_style(
30
- axes_width_mm: Optional[float] = None,
31
- axes_height_mm: Optional[float] = None,
32
- margin_left_mm: Optional[float] = None,
33
- margin_right_mm: Optional[float] = None,
34
- margin_top_mm: Optional[float] = None,
35
- margin_bottom_mm: Optional[float] = None,
36
- dpi: Optional[int] = None,
37
- title_font_size_pt: Optional[float] = None,
38
- axis_font_size_pt: Optional[float] = None,
39
- tick_font_size_pt: Optional[float] = None,
40
- legend_font_size_pt: Optional[float] = None,
41
- trace_thickness_mm: Optional[float] = None,
42
- reset: Optional[bool] = None,
43
- ) -> str:
44
- """[plt] Set global style overrides for publication figures."""
45
- from scitex.plt._mcp._handlers_style import set_style_handler
46
-
47
- result = await set_style_handler(
48
- axes_width_mm=axes_width_mm,
49
- axes_height_mm=axes_height_mm,
50
- margin_left_mm=margin_left_mm,
51
- margin_right_mm=margin_right_mm,
52
- margin_top_mm=margin_top_mm,
53
- margin_bottom_mm=margin_bottom_mm,
54
- dpi=dpi,
55
- title_font_size_pt=title_font_size_pt,
56
- axis_font_size_pt=axis_font_size_pt,
57
- tick_font_size_pt=tick_font_size_pt,
58
- legend_font_size_pt=legend_font_size_pt,
59
- trace_thickness_mm=trace_thickness_mm,
60
- reset=reset,
61
- )
62
- return _json(result)
30
+ # Access underlying functions from FunctionTool objects
31
+ _plot = fr_mcp.plot.fn
32
+ _reproduce = fr_mcp.reproduce.fn
33
+ _compose = fr_mcp.compose.fn
34
+ _info = fr_mcp.info.fn
35
+ _validate = fr_mcp.validate.fn
36
+ _crop = fr_mcp.crop.fn
37
+ _extract_data = fr_mcp.extract_data.fn
38
+ _list_styles = fr_mcp.list_styles.fn
39
+ _get_plot_types = fr_mcp.get_plot_types.fn
63
40
 
64
- @mcp.tool()
65
- async def plt_list_presets() -> str:
66
- """[plt] List available publication style presets."""
67
- from scitex.plt._mcp._handlers_style import list_presets_handler
41
+ _FIGRECIPE_AVAILABLE = True
42
+ except ImportError:
43
+ _FIGRECIPE_AVAILABLE = False
68
44
 
69
- result = await list_presets_handler()
70
- return _json(result)
45
+ if not _FIGRECIPE_AVAILABLE:
71
46
 
72
- @mcp.tool()
73
- async def plt_get_dpi_settings() -> str:
74
- """[plt] Get DPI settings for different output contexts."""
75
- from scitex.plt._mcp._handlers_style import get_dpi_settings_handler
47
+ @mcp.tool()
48
+ def plt_not_available() -> str:
49
+ """[plt] figrecipe not installed."""
50
+ return "figrecipe is required for plt tools. Install with: pip install figrecipe"
76
51
 
77
- result = await get_dpi_settings_handler()
78
- return _json(result)
52
+ return
79
53
 
80
- @mcp.tool()
81
- async def plt_get_color_palette(format: str = "hex") -> str:
82
- """[plt] Get the SciTeX color palette for consistent figure colors."""
83
- from scitex.plt._mcp._handlers_style import get_color_palette_handler
54
+ # Delegate to figrecipe's MCP tools with plt_ prefix
55
+ # Each wrapper simply calls the figrecipe function
84
56
 
85
- result = await get_color_palette_handler(format=format)
86
- return _json(result)
87
57
 
88
- # Figure tools
89
58
  @mcp.tool()
90
- async def plt_create_figure(
91
- nrows: int = 1,
92
- ncols: int = 1,
93
- axes_width_mm: float = 40,
94
- axes_height_mm: float = 28,
95
- space_w_mm: Optional[float] = None,
96
- space_h_mm: Optional[float] = None,
97
- ) -> str:
98
- """[plt] Create a multi-panel figure canvas with SciTeX style."""
99
- from scitex.plt._mcp._handlers_figure import create_figure_handler
100
-
101
- result = await create_figure_handler(
102
- nrows=nrows,
103
- ncols=ncols,
104
- axes_width_mm=axes_width_mm,
105
- axes_height_mm=axes_height_mm,
106
- space_w_mm=space_w_mm,
107
- space_h_mm=space_h_mm,
108
- )
109
- return _json(result)
59
+ def plt_plot(
60
+ spec: Dict[str, Any],
61
+ output_path: str,
62
+ dpi: int = 300,
63
+ save_recipe: bool = True,
64
+ ) -> Dict[str, Any]:
65
+ """[plt] Create a matplotlib figure from a declarative specification.
66
+
67
+ See figrecipe._api._plot module docstring for full spec format.
68
+
69
+ Parameters
70
+ ----------
71
+ spec : dict
72
+ Declarative specification. Key sections: figure, plots, stat_annotations,
73
+ xlabel, ylabel, title, legend, xlim, ylim.
74
+ output_path : str
75
+ Path to save the output figure.
76
+ dpi : int
77
+ DPI for raster output (default: 300).
78
+ save_recipe : bool
79
+ If True, also save as figrecipe YAML recipe.
80
+
81
+ Returns
82
+ -------
83
+ dict
84
+ Result with 'image_path' and 'recipe_path'.
85
+
86
+ Raises
87
+ ------
88
+ ValueError
89
+ If no plots are specified or data is missing.
90
+ """
91
+ return _plot(spec, output_path, dpi, save_recipe)
110
92
 
111
93
  @mcp.tool()
112
- async def plt_crop_figure(
113
- input_path: str,
94
+ def plt_reproduce(
95
+ recipe_path: str,
114
96
  output_path: Optional[str] = None,
115
- margin: int = 12,
116
- overwrite: bool = False,
117
- ) -> str:
118
- """[plt] Auto-crop whitespace from a saved figure image."""
119
- from scitex.plt._mcp._handlers_figure import crop_figure_handler
120
-
121
- result = await crop_figure_handler(
122
- input_path=input_path,
123
- output_path=output_path,
124
- margin=margin,
125
- overwrite=overwrite,
126
- )
127
- return _json(result)
97
+ format: str = "png",
98
+ dpi: int = 300,
99
+ ) -> Dict[str, Any]:
100
+ """[plt] Reproduce a figure from a saved YAML recipe.
101
+
102
+ Parameters
103
+ ----------
104
+ recipe_path : str
105
+ Path to the .yaml recipe file.
106
+
107
+ output_path : str, optional
108
+ Output path for the reproduced figure.
109
+ Defaults to recipe_path with .reproduced.{format} suffix.
110
+
111
+ format : str
112
+ Output format: png, pdf, or svg.
113
+
114
+ dpi : int
115
+ DPI for raster output.
116
+
117
+ Returns
118
+ -------
119
+ dict
120
+ Result with 'output_path' and 'success'.
121
+ """
122
+ return _reproduce(recipe_path, output_path, format, dpi)
128
123
 
129
124
  @mcp.tool()
130
- async def plt_save_figure(
125
+ def plt_compose(
126
+ sources: List[str],
131
127
  output_path: str,
132
- figure_id: Optional[str] = None,
128
+ layout: str = "horizontal",
129
+ gap_mm: float = 5.0,
133
130
  dpi: int = 300,
134
- crop: bool = True,
135
- ) -> str:
136
- """[plt] Save the current figure to file."""
137
- from scitex.plt._mcp._handlers_figure import save_figure_handler
138
-
139
- result = await save_figure_handler(
140
- output_path=output_path,
141
- figure_id=figure_id,
142
- dpi=dpi,
143
- crop=crop,
131
+ panel_labels: bool = True,
132
+ label_style: str = "uppercase",
133
+ caption: Optional[str] = None,
134
+ create_symlinks: bool = True,
135
+ canvas_size_mm: Optional[Tuple[float, float]] = None,
136
+ facecolor: str = "white",
137
+ ) -> Dict[str, Any]:
138
+ """[plt] Compose multiple figures into a single figure with panel labels.
139
+
140
+ Supports two modes:
141
+ 1. Grid-based layout (list sources): automatic arrangement with layout parameter
142
+ 2. Free-form positioning (dict sources): precise mm-based positioning
143
+
144
+ Parameters
145
+ ----------
146
+ sources : list of str or dict
147
+ Either:
148
+ - List of paths to source images or recipe files (grid-based layout)
149
+ - Dict mapping source paths to positioning specs with 'xy_mm' and 'size_mm':
150
+ {"panel_a.yaml": {"xy_mm": [0, 0], "size_mm": [80, 50]}, ...}
151
+ output_path : str
152
+ Path to save the composed figure.
153
+ layout : str
154
+ Layout mode for list sources: 'horizontal', 'vertical', or 'grid'.
155
+ Ignored when using dict sources with mm positioning.
156
+ gap_mm : float
157
+ Gap between panels in millimeters (for grid-based layout only).
158
+ dpi : int
159
+ DPI for output.
160
+ panel_labels : bool
161
+ If True, add panel labels (A, B, C, D) automatically.
162
+ label_style : str
163
+ Style: 'uppercase' (A,B,C), 'lowercase' (a,b,c), 'numeric' (1,2,3).
164
+ caption : str, optional
165
+ Figure caption to add below.
166
+ create_symlinks : bool
167
+ If True (default), create symlinks to source files for traceability.
168
+ canvas_size_mm : tuple of (float, float), optional
169
+ Canvas size as (width_mm, height_mm) for free-form positioning.
170
+ Required when sources is a dict with mm positioning.
171
+ facecolor : str
172
+ Background color for the composed figure. Default is 'white'.
173
+ All source panels are flattened onto this background to ensure
174
+ consistent appearance regardless of original panel transparency.
175
+
176
+ Returns
177
+ -------
178
+ dict
179
+ Result with 'output_path', 'success', and 'sources_dir' (if symlinks created).
180
+ """
181
+ return _compose(
182
+ sources,
183
+ output_path,
184
+ layout,
185
+ gap_mm,
186
+ dpi,
187
+ panel_labels,
188
+ label_style,
189
+ caption,
190
+ create_symlinks,
191
+ canvas_size_mm,
192
+ facecolor,
144
193
  )
145
- return _json(result)
146
194
 
147
195
  @mcp.tool()
148
- async def plt_close_figure(figure_id: Optional[str] = None) -> str:
149
- """[plt] Close a figure and free memory."""
150
- from scitex.plt._mcp._handlers_figure import close_figure_handler
196
+ def plt_info(recipe_path: str, verbose: bool = False) -> Dict[str, Any]:
197
+ """[plt] Get information about a recipe file.
151
198
 
152
- result = await close_figure_handler(figure_id=figure_id)
153
- return _json(result)
199
+ Parameters
200
+ ----------
201
+ recipe_path : str
202
+ Path to the .yaml recipe file.
154
203
 
155
- # Plot tools
156
- @mcp.tool()
157
- async def plt_plot_bar(
158
- x: list,
159
- y: list,
160
- yerr: Optional[list] = None,
161
- colors: Optional[list] = None,
162
- xlabel: Optional[str] = None,
163
- ylabel: Optional[str] = None,
164
- title: Optional[str] = None,
165
- panel: str = "0,0",
166
- figure_id: Optional[str] = None,
167
- ) -> str:
168
- """[plt] Create a bar plot on specified panel."""
169
- from scitex.plt._mcp._handlers_plot import plot_bar_handler
170
-
171
- result = await plot_bar_handler(
172
- x=x,
173
- y=y,
174
- yerr=yerr,
175
- colors=colors,
176
- xlabel=xlabel,
177
- ylabel=ylabel,
178
- title=title,
179
- panel=panel,
180
- figure_id=figure_id,
181
- )
182
- return _json(result)
204
+ verbose : bool
205
+ If True, include detailed call information.
183
206
 
184
- @mcp.tool()
185
- async def plt_plot_scatter(
186
- x: list,
187
- y: list,
188
- color: Optional[str] = None,
189
- size: Optional[float] = None,
190
- alpha: Optional[float] = None,
191
- add_regression: bool = False,
192
- xlabel: Optional[str] = None,
193
- ylabel: Optional[str] = None,
194
- title: Optional[str] = None,
195
- panel: str = "0,0",
196
- figure_id: Optional[str] = None,
197
- ) -> str:
198
- """[plt] Create a scatter plot on specified panel."""
199
- from scitex.plt._mcp._handlers_plot import plot_scatter_handler
200
-
201
- result = await plot_scatter_handler(
202
- x=x,
203
- y=y,
204
- color=color,
205
- size=size,
206
- alpha=alpha,
207
- add_regression=add_regression,
208
- xlabel=xlabel,
209
- ylabel=ylabel,
210
- title=title,
211
- panel=panel,
212
- figure_id=figure_id,
213
- )
214
- return _json(result)
207
+ Returns
208
+ -------
209
+ dict
210
+ Recipe information including figure dimensions, call counts, etc.
211
+ """
212
+ return _info(recipe_path, verbose)
215
213
 
216
214
  @mcp.tool()
217
- async def plt_plot_line(
218
- x: list,
219
- y: list,
220
- yerr: Optional[list] = None,
221
- color: Optional[str] = None,
222
- linestyle: str = "-",
223
- label: Optional[str] = None,
224
- xlabel: Optional[str] = None,
225
- ylabel: Optional[str] = None,
226
- title: Optional[str] = None,
227
- panel: str = "0,0",
228
- figure_id: Optional[str] = None,
229
- ) -> str:
230
- """[plt] Create a line plot on specified panel."""
231
- from scitex.plt._mcp._handlers_plot import plot_line_handler
232
-
233
- result = await plot_line_handler(
234
- x=x,
235
- y=y,
236
- yerr=yerr,
237
- color=color,
238
- linestyle=linestyle,
239
- label=label,
240
- xlabel=xlabel,
241
- ylabel=ylabel,
242
- title=title,
243
- panel=panel,
244
- figure_id=figure_id,
245
- )
246
- return _json(result)
215
+ def plt_validate(
216
+ recipe_path: str,
217
+ mse_threshold: float = 100.0,
218
+ ) -> Dict[str, Any]:
219
+ """[plt] Validate that a recipe can reproduce its original figure.
220
+
221
+ Parameters
222
+ ----------
223
+ recipe_path : str
224
+ Path to the .yaml recipe file.
225
+
226
+ mse_threshold : float
227
+ Maximum acceptable mean squared error (default: 100).
228
+
229
+ Returns
230
+ -------
231
+ dict
232
+ Validation result with 'passed', 'mse', and details.
233
+ """
234
+ return _validate(recipe_path, mse_threshold)
247
235
 
248
236
  @mcp.tool()
249
- async def plt_plot_box(
250
- data: list,
251
- labels: Optional[list] = None,
252
- colors: Optional[list] = None,
253
- xlabel: Optional[str] = None,
254
- ylabel: Optional[str] = None,
255
- title: Optional[str] = None,
256
- panel: str = "0,0",
257
- figure_id: Optional[str] = None,
258
- ) -> str:
259
- """[plt] Create a box plot on specified panel."""
260
- from scitex.plt._mcp._handlers_plot import plot_box_handler
261
-
262
- result = await plot_box_handler(
263
- data=data,
264
- labels=labels,
265
- colors=colors,
266
- xlabel=xlabel,
267
- ylabel=ylabel,
268
- title=title,
269
- panel=panel,
270
- figure_id=figure_id,
271
- )
272
- return _json(result)
237
+ def plt_crop(
238
+ input_path: str,
239
+ output_path: Optional[str] = None,
240
+ margin_mm: float = 1.0,
241
+ overwrite: bool = False,
242
+ ) -> Dict[str, Any]:
243
+ """[plt] Crop whitespace from a figure image.
244
+
245
+ Parameters
246
+ ----------
247
+ input_path : str
248
+ Path to the input image.
249
+
250
+ output_path : str, optional
251
+ Path for cropped output. Defaults to input with .cropped suffix.
252
+
253
+ margin_mm : float
254
+ Margin to keep around content in millimeters.
255
+
256
+ overwrite : bool
257
+ If True, overwrite the input file.
258
+
259
+ Returns
260
+ -------
261
+ dict
262
+ Result with 'output_path' and 'success'.
263
+ """
264
+ return _crop(input_path, output_path, margin_mm, overwrite)
273
265
 
274
266
  @mcp.tool()
275
- async def plt_plot_violin(
276
- data: list,
277
- labels: Optional[list] = None,
278
- colors: Optional[list] = None,
279
- xlabel: Optional[str] = None,
280
- ylabel: Optional[str] = None,
281
- title: Optional[str] = None,
282
- panel: str = "0,0",
283
- figure_id: Optional[str] = None,
284
- ) -> str:
285
- """[plt] Create a violin plot on specified panel."""
286
- from scitex.plt._mcp._handlers_plot import plot_violin_handler
287
-
288
- result = await plot_violin_handler(
289
- data=data,
290
- labels=labels,
291
- colors=colors,
292
- xlabel=xlabel,
293
- ylabel=ylabel,
294
- title=title,
295
- panel=panel,
296
- figure_id=figure_id,
297
- )
298
- return _json(result)
267
+ def plt_extract_data(recipe_path: str) -> Dict[str, Dict[str, Any]]:
268
+ """[plt] Extract plotted data arrays from a saved recipe.
269
+
270
+ Parameters
271
+ ----------
272
+ recipe_path : str
273
+ Path to the .yaml recipe file.
274
+
275
+ Returns
276
+ -------
277
+ dict
278
+ Nested dict: {call_id: {'x': list, 'y': list, ...}}
279
+ """
280
+ return _extract_data(recipe_path)
299
281
 
300
- # Annotation tools
301
282
  @mcp.tool()
302
- async def plt_add_significance(
303
- x1: float,
304
- x2: float,
305
- y: float,
306
- text: str,
307
- height: Optional[float] = None,
308
- panel: str = "0,0",
309
- figure_id: Optional[str] = None,
310
- ) -> str:
311
- """[plt] Add significance bracket between two groups."""
312
- from scitex.plt._mcp._handlers_annotation import add_significance_handler
313
-
314
- result = await add_significance_handler(
315
- x1=x1,
316
- x2=x2,
317
- y=y,
318
- text=text,
319
- height=height,
320
- panel=panel,
321
- figure_id=figure_id,
322
- )
323
- return _json(result)
283
+ def plt_list_styles() -> Dict[str, Any]:
284
+ """[plt] List available figure style presets.
285
+
286
+ Returns
287
+ -------
288
+ dict
289
+ Dictionary with 'presets' list of available style names.
290
+ """
291
+ return _list_styles()
324
292
 
325
293
  @mcp.tool()
326
- async def plt_add_panel_label(
327
- label: str,
328
- x: float = -0.15,
329
- y: float = 1.1,
330
- fontsize: float = 10,
331
- fontweight: str = "bold",
332
- panel: str = "0,0",
333
- figure_id: Optional[str] = None,
334
- ) -> str:
335
- """[plt] Add panel label (A, B, C, etc.) to a panel."""
336
- from scitex.plt._mcp._handlers_annotation import add_panel_label_handler
337
-
338
- result = await add_panel_label_handler(
339
- label=label,
340
- x=x,
341
- y=y,
342
- fontsize=fontsize,
343
- fontweight=fontweight,
344
- panel=panel,
345
- figure_id=figure_id,
346
- )
347
- return _json(result)
294
+ def plt_get_plot_types() -> Dict[str, Any]:
295
+ """[plt] Get list of supported plot types.
296
+
297
+ Returns
298
+ -------
299
+ dict
300
+ Dictionary with 'plot_types' and their descriptions.
301
+ """
302
+ return _get_plot_types()
348
303
 
349
304
 
350
305
  # EOF