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/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
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env python3
2
- # File: __init__.py
3
- """MCP server components."""
4
-
@@ -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