scitex 2.4.3__py3-none-any.whl → 2.7.0__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 (1092) hide show
  1. scitex/__init__.py +19 -8
  2. scitex/__main__.py +2 -1
  3. scitex/__version__.py +1 -1
  4. scitex/_optional_deps.py +13 -20
  5. scitex/ai/__init__.py +5 -0
  6. scitex/ai/_gen_ai/_Anthropic.py +3 -1
  7. scitex/ai/_gen_ai/_BaseGenAI.py +3 -2
  8. scitex/ai/_gen_ai/_DeepSeek.py +1 -1
  9. scitex/ai/_gen_ai/_Google.py +3 -2
  10. scitex/ai/_gen_ai/_Llama.py +4 -2
  11. scitex/ai/_gen_ai/_OpenAI.py +3 -1
  12. scitex/ai/_gen_ai/_PARAMS.py +1 -0
  13. scitex/ai/_gen_ai/_Perplexity.py +3 -1
  14. scitex/ai/_gen_ai/__init__.py +1 -0
  15. scitex/ai/_gen_ai/_format_output_func.py +3 -1
  16. scitex/ai/classification/CrossValidationExperiment.py +8 -14
  17. scitex/ai/classification/examples/timeseries_cv_demo.py +128 -112
  18. scitex/ai/classification/reporters/_BaseClassificationReporter.py +2 -0
  19. scitex/ai/classification/reporters/_ClassificationReporter.py +30 -45
  20. scitex/ai/classification/reporters/_MultiClassificationReporter.py +8 -11
  21. scitex/ai/classification/reporters/_SingleClassificationReporter.py +126 -182
  22. scitex/ai/classification/reporters/__init__.py +1 -1
  23. scitex/ai/classification/reporters/reporter_utils/_Plotter.py +213 -119
  24. scitex/ai/classification/reporters/reporter_utils/__init__.py +28 -36
  25. scitex/ai/classification/reporters/reporter_utils/aggregation.py +125 -143
  26. scitex/ai/classification/reporters/reporter_utils/data_models.py +128 -120
  27. scitex/ai/classification/reporters/reporter_utils/reporting.py +507 -340
  28. scitex/ai/classification/reporters/reporter_utils/storage.py +4 -1
  29. scitex/ai/classification/reporters/reporter_utils/validation.py +141 -154
  30. scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +204 -129
  31. scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +215 -171
  32. scitex/ai/classification/timeseries/_TimeSeriesMetadata.py +17 -17
  33. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +67 -143
  34. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +67 -143
  35. scitex/ai/classification/timeseries/_TimeSeriesStrategy.py +12 -13
  36. scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +231 -144
  37. scitex/ai/classification/timeseries/__init__.py +2 -4
  38. scitex/ai/classification/timeseries/_normalize_timestamp.py +3 -0
  39. scitex/ai/clustering/_pca.py +0 -1
  40. scitex/ai/clustering/_umap.py +1 -2
  41. scitex/ai/feature_extraction/__init__.py +10 -8
  42. scitex/ai/feature_extraction/vit.py +0 -1
  43. scitex/ai/feature_selection/feature_selection.py +3 -8
  44. scitex/ai/metrics/_calc_conf_mat.py +2 -0
  45. scitex/ai/metrics/_calc_feature_importance.py +3 -7
  46. scitex/ai/metrics/_calc_pre_rec_auc.py +5 -5
  47. scitex/ai/metrics/_calc_roc_auc.py +4 -2
  48. scitex/ai/metrics/_calc_seizure_prediction_metrics.py +35 -20
  49. scitex/ai/metrics/_calc_silhouette_score.py +1 -3
  50. scitex/ai/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger.py +0 -3
  51. scitex/ai/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger2020.py +0 -3
  52. scitex/ai/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger913A.py +0 -3
  53. scitex/ai/optim/_optimizers.py +1 -1
  54. scitex/ai/plt/__init__.py +6 -1
  55. scitex/ai/plt/_plot_feature_importance.py +1 -3
  56. scitex/ai/plt/_plot_learning_curve.py +9 -24
  57. scitex/ai/plt/_plot_optuna_study.py +4 -3
  58. scitex/ai/plt/_plot_pre_rec_curve.py +9 -15
  59. scitex/ai/plt/_plot_roc_curve.py +6 -8
  60. scitex/ai/plt/_stx_conf_mat.py +121 -122
  61. scitex/ai/sampling/undersample.py +3 -2
  62. scitex/ai/sklearn/__init__.py +2 -2
  63. scitex/ai/training/_LearningCurveLogger.py +23 -10
  64. scitex/ai/utils/_check_params.py +0 -1
  65. scitex/benchmark/__init__.py +15 -25
  66. scitex/benchmark/benchmark.py +124 -117
  67. scitex/benchmark/monitor.py +117 -107
  68. scitex/benchmark/profiler.py +61 -58
  69. scitex/bridge/__init__.py +110 -0
  70. scitex/bridge/_helpers.py +149 -0
  71. scitex/bridge/_plt_vis.py +529 -0
  72. scitex/bridge/_protocol.py +283 -0
  73. scitex/bridge/_stats_plt.py +261 -0
  74. scitex/bridge/_stats_vis.py +265 -0
  75. scitex/browser/__init__.py +0 -2
  76. scitex/browser/auth/__init__.py +0 -0
  77. scitex/browser/auth/google.py +16 -11
  78. scitex/browser/automation/CookieHandler.py +2 -3
  79. scitex/browser/collaboration/__init__.py +3 -0
  80. scitex/browser/collaboration/auth_helpers.py +3 -1
  81. scitex/browser/collaboration/collaborative_agent.py +2 -0
  82. scitex/browser/collaboration/interactive_panel.py +2 -2
  83. scitex/browser/collaboration/shared_session.py +20 -11
  84. scitex/browser/collaboration/standard_interactions.py +1 -0
  85. scitex/browser/core/BrowserMixin.py +12 -30
  86. scitex/browser/core/ChromeProfileManager.py +9 -24
  87. scitex/browser/debugging/_browser_logger.py +15 -25
  88. scitex/browser/debugging/_failure_capture.py +9 -2
  89. scitex/browser/debugging/_highlight_element.py +15 -6
  90. scitex/browser/debugging/_show_grid.py +5 -6
  91. scitex/browser/debugging/_sync_session.py +4 -3
  92. scitex/browser/debugging/_test_monitor.py +14 -5
  93. scitex/browser/debugging/_visual_cursor.py +46 -35
  94. scitex/browser/interaction/click_center.py +4 -3
  95. scitex/browser/interaction/click_with_fallbacks.py +7 -10
  96. scitex/browser/interaction/close_popups.py +79 -66
  97. scitex/browser/interaction/fill_with_fallbacks.py +8 -8
  98. scitex/browser/pdf/__init__.py +3 -1
  99. scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +11 -10
  100. scitex/browser/pdf/detect_chrome_pdf_viewer.py +3 -6
  101. scitex/browser/remote/CaptchaHandler.py +109 -96
  102. scitex/browser/remote/ZenRowsAPIClient.py +91 -97
  103. scitex/browser/remote/ZenRowsBrowserManager.py +138 -112
  104. scitex/browser/stealth/HumanBehavior.py +4 -9
  105. scitex/browser/stealth/StealthManager.py +11 -26
  106. scitex/capture/__init__.py +17 -17
  107. scitex/capture/__main__.py +2 -3
  108. scitex/capture/capture.py +23 -51
  109. scitex/capture/cli.py +14 -39
  110. scitex/capture/gif.py +5 -9
  111. scitex/capture/mcp_server.py +7 -20
  112. scitex/capture/session.py +4 -3
  113. scitex/capture/utils.py +18 -53
  114. scitex/cli/__init__.py +1 -1
  115. scitex/cli/cloud.py +158 -116
  116. scitex/cli/config.py +224 -0
  117. scitex/cli/main.py +41 -40
  118. scitex/cli/scholar.py +60 -27
  119. scitex/cli/security.py +14 -20
  120. scitex/cli/web.py +87 -90
  121. scitex/cli/writer.py +51 -45
  122. scitex/cloud/__init__.py +14 -11
  123. scitex/cloud/_matplotlib_hook.py +6 -6
  124. scitex/config/README.md +313 -0
  125. scitex/config/{PriorityConfig.py → _PriorityConfig.py} +114 -17
  126. scitex/config/_ScitexConfig.py +319 -0
  127. scitex/config/__init__.py +41 -9
  128. scitex/config/_paths.py +325 -0
  129. scitex/config/default.yaml +81 -0
  130. scitex/context/_suppress_output.py +2 -3
  131. scitex/db/_BaseMixins/_BaseBackupMixin.py +3 -1
  132. scitex/db/_BaseMixins/_BaseBatchMixin.py +3 -1
  133. scitex/db/_BaseMixins/_BaseBlobMixin.py +3 -1
  134. scitex/db/_BaseMixins/_BaseImportExportMixin.py +1 -3
  135. scitex/db/_BaseMixins/_BaseIndexMixin.py +3 -1
  136. scitex/db/_BaseMixins/_BaseMaintenanceMixin.py +1 -3
  137. scitex/db/_BaseMixins/_BaseQueryMixin.py +3 -1
  138. scitex/db/_BaseMixins/_BaseRowMixin.py +3 -1
  139. scitex/db/_BaseMixins/_BaseTableMixin.py +3 -1
  140. scitex/db/_BaseMixins/_BaseTransactionMixin.py +1 -3
  141. scitex/db/_BaseMixins/__init__.py +1 -1
  142. scitex/db/__init__.py +9 -1
  143. scitex/db/__main__.py +8 -21
  144. scitex/db/_check_health.py +15 -31
  145. scitex/db/_delete_duplicates.py +7 -4
  146. scitex/db/_inspect.py +22 -38
  147. scitex/db/_inspect_optimized.py +89 -85
  148. scitex/db/_postgresql/_PostgreSQL.py +0 -1
  149. scitex/db/_postgresql/_PostgreSQLMixins/_BlobMixin.py +3 -1
  150. scitex/db/_postgresql/_PostgreSQLMixins/_ConnectionMixin.py +1 -3
  151. scitex/db/_postgresql/_PostgreSQLMixins/_ImportExportMixin.py +1 -3
  152. scitex/db/_postgresql/_PostgreSQLMixins/_MaintenanceMixin.py +1 -4
  153. scitex/db/_postgresql/_PostgreSQLMixins/_QueryMixin.py +3 -3
  154. scitex/db/_postgresql/_PostgreSQLMixins/_RowMixin.py +3 -1
  155. scitex/db/_postgresql/_PostgreSQLMixins/_TransactionMixin.py +1 -3
  156. scitex/db/_postgresql/__init__.py +1 -1
  157. scitex/db/_sqlite3/_SQLite3.py +2 -4
  158. scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin.py +11 -12
  159. scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin_v01-need-_hash-col.py +19 -14
  160. scitex/db/_sqlite3/_SQLite3Mixins/_BatchMixin.py +3 -1
  161. scitex/db/_sqlite3/_SQLite3Mixins/_BlobMixin.py +7 -7
  162. scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin.py +118 -111
  163. scitex/db/_sqlite3/_SQLite3Mixins/_ConnectionMixin.py +8 -10
  164. scitex/db/_sqlite3/_SQLite3Mixins/_GitMixin.py +17 -45
  165. scitex/db/_sqlite3/_SQLite3Mixins/_ImportExportMixin.py +1 -3
  166. scitex/db/_sqlite3/_SQLite3Mixins/_IndexMixin.py +3 -1
  167. scitex/db/_sqlite3/_SQLite3Mixins/_QueryMixin.py +3 -4
  168. scitex/db/_sqlite3/_SQLite3Mixins/_RowMixin.py +9 -9
  169. scitex/db/_sqlite3/_SQLite3Mixins/_TableMixin.py +18 -11
  170. scitex/db/_sqlite3/_SQLite3Mixins/__init__.py +1 -0
  171. scitex/db/_sqlite3/__init__.py +1 -1
  172. scitex/db/_sqlite3/_delete_duplicates.py +13 -11
  173. scitex/decorators/__init__.py +29 -4
  174. scitex/decorators/_auto_order.py +43 -43
  175. scitex/decorators/_batch_fn.py +12 -6
  176. scitex/decorators/_cache_disk.py +8 -9
  177. scitex/decorators/_cache_disk_async.py +8 -7
  178. scitex/decorators/_combined.py +19 -13
  179. scitex/decorators/_converters.py +16 -3
  180. scitex/decorators/_deprecated.py +32 -22
  181. scitex/decorators/_numpy_fn.py +18 -4
  182. scitex/decorators/_pandas_fn.py +17 -5
  183. scitex/decorators/_signal_fn.py +17 -3
  184. scitex/decorators/_torch_fn.py +32 -15
  185. scitex/decorators/_xarray_fn.py +23 -9
  186. scitex/dev/_analyze_code_flow.py +0 -2
  187. scitex/dict/_DotDict.py +15 -19
  188. scitex/dict/_flatten.py +1 -0
  189. scitex/dict/_listed_dict.py +1 -0
  190. scitex/dict/_pop_keys.py +1 -0
  191. scitex/dict/_replace.py +1 -0
  192. scitex/dict/_safe_merge.py +1 -0
  193. scitex/dict/_to_str.py +2 -3
  194. scitex/dsp/__init__.py +13 -4
  195. scitex/dsp/_crop.py +3 -1
  196. scitex/dsp/_detect_ripples.py +3 -1
  197. scitex/dsp/_modulation_index.py +3 -1
  198. scitex/dsp/_time.py +3 -1
  199. scitex/dsp/_wavelet.py +0 -1
  200. scitex/dsp/example.py +0 -5
  201. scitex/dsp/filt.py +4 -0
  202. scitex/dsp/utils/__init__.py +4 -1
  203. scitex/dsp/utils/pac.py +3 -3
  204. scitex/dt/_normalize_timestamp.py +4 -1
  205. scitex/errors.py +3 -6
  206. scitex/etc/__init__.py +1 -1
  207. scitex/gen/_DimHandler.py +6 -6
  208. scitex/gen/__init__.py +5 -1
  209. scitex/gen/_deprecated_close.py +1 -0
  210. scitex/gen/_deprecated_start.py +5 -3
  211. scitex/gen/_detect_environment.py +44 -41
  212. scitex/gen/_detect_notebook_path.py +51 -47
  213. scitex/gen/_embed.py +1 -1
  214. scitex/gen/_get_notebook_path.py +81 -62
  215. scitex/gen/_inspect_module.py +0 -1
  216. scitex/gen/_norm.py +16 -7
  217. scitex/gen/_norm_cache.py +78 -65
  218. scitex/gen/_print_config.py +0 -3
  219. scitex/gen/_src.py +2 -3
  220. scitex/gen/_title_case.py +3 -2
  221. scitex/gen/_to_even.py +8 -8
  222. scitex/gen/_transpose.py +3 -3
  223. scitex/gen/misc.py +0 -3
  224. scitex/gists/_SigMacro_processFigure_S.py +2 -2
  225. scitex/gists/_SigMacro_toBlue.py +2 -2
  226. scitex/gists/__init__.py +4 -1
  227. scitex/git/_branch.py +19 -11
  228. scitex/git/_clone.py +23 -15
  229. scitex/git/_commit.py +10 -12
  230. scitex/git/_init.py +15 -38
  231. scitex/git/_remote.py +9 -3
  232. scitex/git/_result.py +3 -0
  233. scitex/git/_retry.py +2 -5
  234. scitex/git/_types.py +4 -0
  235. scitex/git/_validation.py +8 -8
  236. scitex/git/_workflow.py +4 -4
  237. scitex/io/__init__.py +2 -1
  238. scitex/io/_glob.py +2 -2
  239. scitex/io/_json2md.py +3 -3
  240. scitex/io/_load.py +11 -8
  241. scitex/io/_load_cache.py +71 -71
  242. scitex/io/_load_configs.py +2 -3
  243. scitex/io/_load_modules/_H5Explorer.py +6 -12
  244. scitex/io/_load_modules/_ZarrExplorer.py +3 -3
  245. scitex/io/_load_modules/_bibtex.py +62 -63
  246. scitex/io/_load_modules/_canvas.py +166 -0
  247. scitex/io/_load_modules/_catboost.py +7 -2
  248. scitex/io/_load_modules/_hdf5.py +2 -0
  249. scitex/io/_load_modules/_image.py +5 -1
  250. scitex/io/_load_modules/_matlab.py +3 -1
  251. scitex/io/_load_modules/_optuna.py +0 -1
  252. scitex/io/_load_modules/_pdf.py +38 -29
  253. scitex/io/_load_modules/_sqlite3.py +1 -0
  254. scitex/io/_load_modules/_txt.py +2 -0
  255. scitex/io/_load_modules/_xml.py +9 -9
  256. scitex/io/_load_modules/_zarr.py +12 -10
  257. scitex/io/_metadata.py +76 -37
  258. scitex/io/_qr_utils.py +18 -13
  259. scitex/io/_save.py +228 -63
  260. scitex/io/_save_modules/__init__.py +7 -2
  261. scitex/io/_save_modules/_bibtex.py +66 -61
  262. scitex/io/_save_modules/_canvas.py +355 -0
  263. scitex/io/_save_modules/_catboost.py +2 -2
  264. scitex/io/_save_modules/_csv.py +4 -4
  265. scitex/io/_save_modules/_excel.py +5 -9
  266. scitex/io/_save_modules/_hdf5.py +9 -21
  267. scitex/io/_save_modules/_html.py +5 -5
  268. scitex/io/_save_modules/_image.py +105 -8
  269. scitex/io/_save_modules/_joblib.py +2 -2
  270. scitex/io/_save_modules/_json.py +51 -6
  271. scitex/io/_save_modules/_listed_dfs_as_csv.py +2 -1
  272. scitex/io/_save_modules/_listed_scalars_as_csv.py +2 -1
  273. scitex/io/_save_modules/_matlab.py +2 -2
  274. scitex/io/_save_modules/_numpy.py +6 -8
  275. scitex/io/_save_modules/_pickle.py +4 -4
  276. scitex/io/_save_modules/_plotly.py +3 -3
  277. scitex/io/_save_modules/_tex.py +23 -25
  278. scitex/io/_save_modules/_text.py +2 -2
  279. scitex/io/_save_modules/_yaml.py +9 -9
  280. scitex/io/_save_modules/_zarr.py +15 -15
  281. scitex/io/utils/__init__.py +2 -1
  282. scitex/io/utils/h5_to_zarr.py +173 -155
  283. scitex/linalg/__init__.py +1 -1
  284. scitex/linalg/_geometric_median.py +4 -3
  285. scitex/logging/_Tee.py +5 -7
  286. scitex/logging/__init__.py +18 -19
  287. scitex/logging/_config.py +4 -1
  288. scitex/logging/_context.py +6 -5
  289. scitex/logging/_formatters.py +2 -3
  290. scitex/logging/_handlers.py +19 -20
  291. scitex/logging/_levels.py +9 -17
  292. scitex/logging/_logger.py +74 -15
  293. scitex/logging/_print_capture.py +17 -17
  294. scitex/nn/_BNet.py +1 -3
  295. scitex/nn/_Filters.py +6 -2
  296. scitex/nn/_ModulationIndex.py +3 -1
  297. scitex/nn/_PAC.py +3 -2
  298. scitex/nn/_PSD.py +0 -1
  299. scitex/nn/__init__.py +16 -3
  300. scitex/path/_clean.py +10 -8
  301. scitex/path/_find.py +1 -1
  302. scitex/path/_get_spath.py +1 -2
  303. scitex/path/_mk_spath.py +1 -1
  304. scitex/path/_symlink.py +5 -10
  305. scitex/pd/__init__.py +4 -1
  306. scitex/pd/_force_df.py +24 -24
  307. scitex/pd/_get_unique.py +1 -0
  308. scitex/pd/_merge_columns.py +1 -1
  309. scitex/pd/_round.py +11 -7
  310. scitex/pd/_to_xy.py +0 -1
  311. scitex/plt/REQUESTS.md +191 -0
  312. scitex/plt/__init__.py +185 -87
  313. scitex/plt/_subplots/_AxesWrapper.py +22 -6
  314. scitex/plt/_subplots/_AxisWrapper.py +100 -39
  315. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +74 -52
  316. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +183 -73
  317. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +61 -45
  318. scitex/plt/_subplots/_AxisWrapperMixins/_TrackingMixin.py +26 -14
  319. scitex/plt/_subplots/_AxisWrapperMixins/_UnitAwareMixin.py +80 -73
  320. scitex/plt/_subplots/_FigWrapper.py +93 -60
  321. scitex/plt/_subplots/_SubplotsWrapper.py +135 -68
  322. scitex/plt/_subplots/__init__.py +10 -0
  323. scitex/plt/_subplots/_export_as_csv.py +89 -47
  324. scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +1 -0
  325. scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +6 -4
  326. scitex/plt/_subplots/_export_as_csv_formatters/_format_bar.py +88 -38
  327. scitex/plt/_subplots/_export_as_csv_formatters/_format_barh.py +25 -31
  328. scitex/plt/_subplots/_export_as_csv_formatters/_format_boxplot.py +53 -23
  329. scitex/plt/_subplots/_export_as_csv_formatters/_format_contour.py +38 -25
  330. scitex/plt/_subplots/_export_as_csv_formatters/_format_contourf.py +17 -9
  331. scitex/plt/_subplots/_export_as_csv_formatters/_format_errorbar.py +70 -124
  332. scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +12 -10
  333. scitex/plt/_subplots/_export_as_csv_formatters/_format_fill.py +31 -17
  334. scitex/plt/_subplots/_export_as_csv_formatters/_format_fill_between.py +33 -21
  335. scitex/plt/_subplots/_export_as_csv_formatters/_format_hexbin.py +14 -4
  336. scitex/plt/_subplots/_export_as_csv_formatters/_format_hist.py +43 -29
  337. scitex/plt/_subplots/_export_as_csv_formatters/_format_hist2d.py +14 -4
  338. scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow.py +27 -11
  339. scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +7 -5
  340. scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +9 -7
  341. scitex/plt/_subplots/_export_as_csv_formatters/_format_pie.py +15 -6
  342. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +128 -34
  343. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_box.py +52 -27
  344. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_imshow.py +1 -0
  345. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +16 -17
  346. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +7 -5
  347. scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +10 -8
  348. scitex/plt/_subplots/_export_as_csv_formatters/_format_scatter.py +17 -6
  349. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_barplot.py +43 -26
  350. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_boxplot.py +68 -47
  351. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_heatmap.py +52 -64
  352. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_histplot.py +55 -50
  353. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +9 -11
  354. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_kdeplot.py +63 -29
  355. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +4 -4
  356. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +6 -4
  357. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_scatterplot.py +44 -40
  358. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_stripplot.py +46 -39
  359. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_swarmplot.py +46 -39
  360. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_violinplot.py +75 -94
  361. scitex/plt/_subplots/_export_as_csv_formatters/_format_stem.py +12 -3
  362. scitex/plt/_subplots/_export_as_csv_formatters/_format_step.py +12 -3
  363. scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +10 -8
  364. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_conf_mat.py +17 -15
  365. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_ecdf.py +10 -9
  366. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_fillv.py +35 -31
  367. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_heatmap.py +18 -18
  368. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_image.py +24 -18
  369. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_joyplot.py +9 -7
  370. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_line.py +34 -23
  371. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_ci.py +15 -13
  372. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_std.py +12 -10
  373. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_median_iqr.py +15 -13
  374. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_raster.py +11 -9
  375. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_rectangle.py +84 -56
  376. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter_hist.py +35 -32
  377. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_shaded_line.py +46 -30
  378. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_violin.py +51 -51
  379. scitex/plt/_subplots/_export_as_csv_formatters/_format_text.py +32 -31
  380. scitex/plt/_subplots/_export_as_csv_formatters/_format_violin.py +34 -31
  381. scitex/plt/_subplots/_export_as_csv_formatters/_format_violinplot.py +44 -37
  382. scitex/plt/_subplots/_export_as_csv_formatters/verify_formatters.py +91 -74
  383. scitex/plt/_tpl.py +6 -5
  384. scitex/plt/ax/_plot/__init__.py +24 -0
  385. scitex/plt/ax/_plot/_add_fitted_line.py +12 -11
  386. scitex/plt/ax/_plot/_plot_circular_hist.py +3 -1
  387. scitex/plt/ax/_plot/_plot_statistical_shaded_line.py +25 -19
  388. scitex/plt/ax/_plot/_stx_conf_mat.py +6 -3
  389. scitex/plt/ax/_plot/_stx_ecdf.py +5 -3
  390. scitex/plt/ax/_plot/_stx_fillv.py +4 -2
  391. scitex/plt/ax/_plot/_stx_heatmap.py +7 -4
  392. scitex/plt/ax/_plot/_stx_image.py +7 -5
  393. scitex/plt/ax/_plot/_stx_joyplot.py +32 -10
  394. scitex/plt/ax/_plot/_stx_raster.py +26 -11
  395. scitex/plt/ax/_plot/_stx_rectangle.py +2 -2
  396. scitex/plt/ax/_plot/_stx_shaded_line.py +15 -11
  397. scitex/plt/ax/_plot/_stx_violin.py +3 -1
  398. scitex/plt/ax/_style/_add_marginal_ax.py +6 -4
  399. scitex/plt/ax/_style/_auto_scale_axis.py +14 -10
  400. scitex/plt/ax/_style/_extend.py +3 -1
  401. scitex/plt/ax/_style/_force_aspect.py +5 -3
  402. scitex/plt/ax/_style/_format_units.py +2 -2
  403. scitex/plt/ax/_style/_hide_spines.py +5 -1
  404. scitex/plt/ax/_style/_map_ticks.py +5 -3
  405. scitex/plt/ax/_style/_rotate_labels.py +5 -4
  406. scitex/plt/ax/_style/_rotate_labels_v01.py +73 -63
  407. scitex/plt/ax/_style/_set_log_scale.py +120 -85
  408. scitex/plt/ax/_style/_set_meta.py +99 -76
  409. scitex/plt/ax/_style/_set_supxyt.py +33 -16
  410. scitex/plt/ax/_style/_set_xyt.py +27 -18
  411. scitex/plt/ax/_style/_share_axes.py +15 -5
  412. scitex/plt/ax/_style/_show_spines.py +58 -57
  413. scitex/plt/ax/_style/_style_barplot.py +1 -1
  414. scitex/plt/ax/_style/_style_boxplot.py +25 -14
  415. scitex/plt/ax/_style/_style_errorbar.py +0 -0
  416. scitex/plt/ax/_style/_style_scatter.py +1 -1
  417. scitex/plt/ax/_style/_style_suptitles.py +3 -3
  418. scitex/plt/ax/_style/_style_violinplot.py +8 -2
  419. scitex/plt/color/__init__.py +34 -2
  420. scitex/plt/color/_add_hue_col.py +1 -0
  421. scitex/plt/color/_colors.py +0 -1
  422. scitex/plt/color/_get_colors_from_conf_matap.py +3 -1
  423. scitex/plt/color/_vizualize_colors.py +0 -1
  424. scitex/plt/docs/FIGURE_ARCHITECTURE.md +315 -0
  425. scitex/plt/gallery/README.md +75 -0
  426. scitex/plt/gallery/__init__.py +29 -0
  427. scitex/plt/gallery/_generate.py +153 -0
  428. scitex/plt/gallery/_plots.py +594 -0
  429. scitex/plt/gallery/_registry.py +153 -0
  430. scitex/plt/styles/__init__.py +9 -9
  431. scitex/plt/styles/_plot_defaults.py +62 -61
  432. scitex/plt/styles/_plot_postprocess.py +126 -77
  433. scitex/plt/styles/_style_loader.py +0 -0
  434. scitex/plt/styles/presets.py +43 -18
  435. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_between.json +110 -0
  436. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_betweenx.json +88 -0
  437. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fill_between.json +103 -0
  438. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fillv.json +106 -0
  439. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/bar.json +92 -0
  440. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/barh.json +92 -0
  441. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/boxplot.json +92 -0
  442. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_bar.json +84 -0
  443. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_barh.json +84 -0
  444. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_box.json +83 -0
  445. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_boxplot.json +93 -0
  446. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violin.json +91 -0
  447. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violinplot.json +91 -0
  448. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/violinplot.json +91 -0
  449. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contour.json +97 -0
  450. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contourf.json +98 -0
  451. scitex/plt/templates/research-master/scitex/vis/gallery/contour/stx_contour.json +84 -0
  452. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist.json +101 -0
  453. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist2d.json +96 -0
  454. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_ecdf.json +95 -0
  455. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_joyplot.json +95 -0
  456. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_kde.json +93 -0
  457. scitex/plt/templates/research-master/scitex/vis/gallery/grid/imshow.json +95 -0
  458. scitex/plt/templates/research-master/scitex/vis/gallery/grid/matshow.json +95 -0
  459. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_conf_mat.json +83 -0
  460. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_heatmap.json +92 -0
  461. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_image.json +121 -0
  462. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_imshow.json +84 -0
  463. scitex/plt/templates/research-master/scitex/vis/gallery/line/plot.json +110 -0
  464. scitex/plt/templates/research-master/scitex/vis/gallery/line/step.json +92 -0
  465. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_line.json +95 -0
  466. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_shaded_line.json +96 -0
  467. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/hexbin.json +95 -0
  468. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/scatter.json +95 -0
  469. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stem.json +92 -0
  470. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stx_scatter.json +84 -0
  471. scitex/plt/templates/research-master/scitex/vis/gallery/special/pie.json +94 -0
  472. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_raster.json +109 -0
  473. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_rectangle.json +108 -0
  474. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/errorbar.json +93 -0
  475. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_errorbar.json +84 -0
  476. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_ci.json +96 -0
  477. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_std.json +96 -0
  478. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_median_iqr.json +96 -0
  479. scitex/plt/templates/research-master/scitex/vis/gallery/vector/quiver.json +99 -0
  480. scitex/plt/templates/research-master/scitex/vis/gallery/vector/streamplot.json +100 -0
  481. scitex/plt/utils/__init__.py +39 -2
  482. scitex/plt/utils/_close.py +8 -3
  483. scitex/plt/utils/_collect_figure_metadata.py +3033 -265
  484. scitex/plt/utils/_colorbar.py +15 -17
  485. scitex/plt/utils/_configure_mpl.py +22 -14
  486. scitex/plt/utils/_crop.py +60 -27
  487. scitex/plt/utils/_csv_column_naming.py +288 -0
  488. scitex/plt/utils/_dimension_viewer.py +7 -19
  489. scitex/plt/utils/_figure_from_axes_mm.py +70 -16
  490. scitex/plt/utils/_figure_mm.py +3 -2
  491. scitex/plt/utils/_get_actual_font.py +5 -4
  492. scitex/plt/utils/_histogram_utils.py +52 -48
  493. scitex/plt/utils/_is_valid_axis.py +19 -13
  494. scitex/plt/utils/_mk_colorbar.py +3 -3
  495. scitex/plt/utils/_scientific_captions.py +202 -139
  496. scitex/plt/utils/_scitex_config.py +98 -98
  497. scitex/plt/utils/_units.py +0 -0
  498. scitex/plt/utils/metadata/__init__.py +36 -0
  499. scitex/plt/utils/metadata/_artist_extraction.py +119 -0
  500. scitex/plt/utils/metadata/_axes_metadata.py +93 -0
  501. scitex/plt/utils/metadata/_collection_artists.py +292 -0
  502. scitex/plt/utils/metadata/_core.py +208 -0
  503. scitex/plt/utils/metadata/_csv_column_extraction.py +186 -0
  504. scitex/plt/utils/metadata/_csv_hash.py +115 -0
  505. scitex/plt/utils/metadata/_csv_verification.py +95 -0
  506. scitex/plt/utils/metadata/_data_linkage.py +263 -0
  507. scitex/plt/utils/metadata/_dimensions.py +239 -0
  508. scitex/plt/utils/metadata/_figure_metadata.py +58 -0
  509. scitex/plt/utils/metadata/_image_text_artists.py +168 -0
  510. scitex/plt/utils/metadata/_label_parsing.py +82 -0
  511. scitex/plt/utils/metadata/_legend_extraction.py +120 -0
  512. scitex/plt/utils/metadata/_line_artists.py +367 -0
  513. scitex/plt/utils/metadata/_line_semantic_handling.py +173 -0
  514. scitex/plt/utils/metadata/_patch_artists.py +211 -0
  515. scitex/plt/utils/metadata/_plot_content.py +26 -0
  516. scitex/plt/utils/metadata/_plot_type_detection.py +184 -0
  517. scitex/plt/utils/metadata/_precision.py +134 -0
  518. scitex/plt/utils/metadata/_precision_config.py +68 -0
  519. scitex/plt/utils/metadata/_precision_sections.py +211 -0
  520. scitex/plt/utils/metadata/_recipe_extraction.py +267 -0
  521. scitex/plt/utils/metadata/_style_parsing.py +174 -0
  522. scitex/repro/_RandomStateManager.py +33 -38
  523. scitex/repro/__init__.py +16 -7
  524. scitex/repro/_gen_ID.py +7 -9
  525. scitex/repro/_gen_timestamp.py +7 -6
  526. scitex/repro/_hash_array.py +8 -12
  527. scitex/reproduce/__init__.py +1 -1
  528. scitex/resource/_get_processor_usages.py +3 -1
  529. scitex/resource/_log_processor_usages.py +3 -1
  530. scitex/rng/__init__.py +1 -1
  531. scitex/schema/README.md +178 -0
  532. scitex/schema/__init__.py +144 -0
  533. scitex/schema/_canvas.py +444 -0
  534. scitex/schema/_stats.py +762 -0
  535. scitex/schema/_validation.py +590 -0
  536. scitex/scholar/.legacy/Scholar.py +5 -12
  537. scitex/scholar/.legacy/_Scholar.py +66 -99
  538. scitex/scholar/.legacy/_ScholarAPI.py +75 -66
  539. scitex/scholar/.legacy/_tmp/search_engine/_BaseSearchEngine.py +3 -3
  540. scitex/scholar/.legacy/_tmp/search_engine/_UnifiedSearcher.py +4 -9
  541. scitex/scholar/.legacy/_tmp/search_engine/__init__.py +14 -21
  542. scitex/scholar/.legacy/_tmp/search_engine/local/_LocalSearchEngine.py +40 -37
  543. scitex/scholar/.legacy/_tmp/search_engine/local/_VectorSearchEngine.py +31 -28
  544. scitex/scholar/.legacy/_tmp/search_engine/web/_ArxivSearchEngine.py +74 -65
  545. scitex/scholar/.legacy/_tmp/search_engine/web/_CrossRefSearchEngine.py +122 -116
  546. scitex/scholar/.legacy/_tmp/search_engine/web/_GoogleScholarSearchEngine.py +65 -59
  547. scitex/scholar/.legacy/_tmp/search_engine/web/_PubMedSearchEngine.py +121 -107
  548. scitex/scholar/.legacy/_tmp/search_engine/web/_SemanticScholarSearchEngine.py +5 -12
  549. scitex/scholar/.legacy/database/_DatabaseEntry.py +49 -45
  550. scitex/scholar/.legacy/database/_DatabaseIndex.py +131 -94
  551. scitex/scholar/.legacy/database/_LibraryManager.py +65 -63
  552. scitex/scholar/.legacy/database/_PaperDatabase.py +138 -124
  553. scitex/scholar/.legacy/database/_ScholarDatabaseIntegration.py +14 -36
  554. scitex/scholar/.legacy/database/_StorageIntegratedDB.py +192 -156
  555. scitex/scholar/.legacy/database/_ZoteroCompatibleDB.py +300 -237
  556. scitex/scholar/.legacy/database/__init__.py +2 -1
  557. scitex/scholar/.legacy/database/manage.py +92 -84
  558. scitex/scholar/.legacy/lookup/_LookupIndex.py +157 -101
  559. scitex/scholar/.legacy/lookup/__init__.py +2 -1
  560. scitex/scholar/.legacy/metadata/doi/batch/_MetadataHandlerForBatchDOIResolution.py +4 -9
  561. scitex/scholar/.legacy/metadata/doi/batch/_ProgressManagerForBatchDOIResolution.py +10 -23
  562. scitex/scholar/.legacy/metadata/doi/batch/_SourceStatsManagerForBatchDOIResolution.py +4 -9
  563. scitex/scholar/.legacy/metadata/doi/batch/__init__.py +3 -1
  564. scitex/scholar/.legacy/metadata/doi/resolvers/_BatchDOIResolver.py +10 -25
  565. scitex/scholar/.legacy/metadata/doi/resolvers/_BibTeXDOIResolver.py +19 -49
  566. scitex/scholar/.legacy/metadata/doi/resolvers/_DOIResolver.py +1 -0
  567. scitex/scholar/.legacy/metadata/doi/resolvers/_SingleDOIResolver.py +8 -20
  568. scitex/scholar/.legacy/metadata/doi/sources/.combined-SemanticScholarSource/_SemanticScholarSource.py +37 -35
  569. scitex/scholar/.legacy/metadata/doi/sources/.combined-SemanticScholarSource/_SemanticScholarSourceEnhanced.py +49 -37
  570. scitex/scholar/.legacy/metadata/doi/sources/_ArXivSource.py +11 -30
  571. scitex/scholar/.legacy/metadata/doi/sources/_BaseDOISource.py +19 -47
  572. scitex/scholar/.legacy/metadata/doi/sources/_CrossRefLocalSource.py +1 -0
  573. scitex/scholar/.legacy/metadata/doi/sources/_CrossRefSource.py +12 -33
  574. scitex/scholar/.legacy/metadata/doi/sources/_OpenAlexSource.py +8 -20
  575. scitex/scholar/.legacy/metadata/doi/sources/_PubMedSource.py +10 -27
  576. scitex/scholar/.legacy/metadata/doi/sources/_SemanticScholarSource.py +11 -29
  577. scitex/scholar/.legacy/metadata/doi/sources/_SourceManager.py +8 -21
  578. scitex/scholar/.legacy/metadata/doi/sources/_SourceResolutionStrategy.py +24 -55
  579. scitex/scholar/.legacy/metadata/doi/sources/_SourceRotationManager.py +8 -21
  580. scitex/scholar/.legacy/metadata/doi/sources/_URLDOISource.py +9 -16
  581. scitex/scholar/.legacy/metadata/doi/sources/_UnifiedSource.py +8 -22
  582. scitex/scholar/.legacy/metadata/doi/sources/__init__.py +1 -0
  583. scitex/scholar/.legacy/metadata/doi/utils/_PubMedConverter.py +4 -8
  584. scitex/scholar/.legacy/metadata/doi/utils/_RateLimitHandler.py +17 -43
  585. scitex/scholar/.legacy/metadata/doi/utils/_TextNormalizer.py +8 -18
  586. scitex/scholar/.legacy/metadata/doi/utils/_URLDOIExtractor.py +4 -8
  587. scitex/scholar/.legacy/metadata/doi/utils/__init__.py +1 -0
  588. scitex/scholar/.legacy/metadata/doi/utils/_to_complete_metadata_structure.py +1 -0
  589. scitex/scholar/.legacy/metadata/enrichment/_LibraryEnricher.py +2 -3
  590. scitex/scholar/.legacy/metadata/enrichment/enrichers/_ImpactFactorEnricher.py +6 -12
  591. scitex/scholar/.legacy/metadata/enrichment/enrichers/_SmartEnricher.py +5 -10
  592. scitex/scholar/.legacy/metadata/enrichment/sources/_UnifiedMetadataSource.py +4 -5
  593. scitex/scholar/.legacy/metadata/query_to_full_meta_json.py +8 -12
  594. scitex/scholar/.legacy/metadata/urls/_URLMetadataHandler.py +3 -3
  595. scitex/scholar/.legacy/metadata/urls/_ZoteroTranslatorRunner.py +15 -21
  596. scitex/scholar/.legacy/metadata/urls/__init__.py +3 -3
  597. scitex/scholar/.legacy/metadata/urls/_finder.py +4 -6
  598. scitex/scholar/.legacy/metadata/urls/_handler.py +7 -15
  599. scitex/scholar/.legacy/metadata/urls/_resolver.py +6 -12
  600. scitex/scholar/.legacy/search/_Embedder.py +74 -69
  601. scitex/scholar/.legacy/search/_SemanticSearch.py +91 -90
  602. scitex/scholar/.legacy/search/_SemanticSearchEngine.py +104 -109
  603. scitex/scholar/.legacy/search/_UnifiedSearcher.py +530 -471
  604. scitex/scholar/.legacy/search/_VectorDatabase.py +111 -92
  605. scitex/scholar/.legacy/search/__init__.py +1 -0
  606. scitex/scholar/.legacy/storage/_EnhancedStorageManager.py +182 -154
  607. scitex/scholar/.legacy/storage/__init__.py +2 -1
  608. scitex/scholar/__init__.py +0 -2
  609. scitex/scholar/__main__.py +1 -3
  610. scitex/scholar/auth/ScholarAuthManager.py +13 -36
  611. scitex/scholar/auth/core/AuthenticationGateway.py +15 -29
  612. scitex/scholar/auth/core/BrowserAuthenticator.py +22 -57
  613. scitex/scholar/auth/core/StrategyResolver.py +10 -27
  614. scitex/scholar/auth/core/__init__.py +5 -1
  615. scitex/scholar/auth/gateway/_OpenURLLinkFinder.py +11 -21
  616. scitex/scholar/auth/gateway/_OpenURLResolver.py +10 -18
  617. scitex/scholar/auth/gateway/_resolve_functions.py +3 -3
  618. scitex/scholar/auth/providers/BaseAuthenticator.py +1 -0
  619. scitex/scholar/auth/providers/EZProxyAuthenticator.py +7 -14
  620. scitex/scholar/auth/providers/OpenAthensAuthenticator.py +29 -57
  621. scitex/scholar/auth/providers/ShibbolethAuthenticator.py +87 -73
  622. scitex/scholar/auth/session/AuthCacheManager.py +12 -22
  623. scitex/scholar/auth/session/SessionManager.py +4 -6
  624. scitex/scholar/auth/sso/BaseSSOAutomator.py +13 -19
  625. scitex/scholar/auth/sso/OpenAthensSSOAutomator.py +16 -45
  626. scitex/scholar/auth/sso/SSOAutomator.py +8 -15
  627. scitex/scholar/auth/sso/UniversityOfMelbourneSSOAutomator.py +13 -23
  628. scitex/scholar/browser/ScholarBrowserManager.py +31 -56
  629. scitex/scholar/browser/__init__.py +1 -0
  630. scitex/scholar/browser/utils/click_and_wait.py +3 -4
  631. scitex/scholar/browser/utils/close_unwanted_pages.py +4 -7
  632. scitex/scholar/browser/utils/wait_redirects.py +15 -40
  633. scitex/scholar/citation_graph/__init__.py +0 -0
  634. scitex/scholar/citation_graph/builder.py +3 -7
  635. scitex/scholar/citation_graph/database.py +4 -11
  636. scitex/scholar/citation_graph/example.py +5 -10
  637. scitex/scholar/citation_graph/models.py +0 -0
  638. scitex/scholar/cli/_url_utils.py +1 -1
  639. scitex/scholar/cli/chrome.py +5 -3
  640. scitex/scholar/cli/download_pdf.py +13 -14
  641. scitex/scholar/cli/handlers/bibtex_handler.py +4 -12
  642. scitex/scholar/cli/handlers/doi_handler.py +1 -3
  643. scitex/scholar/cli/handlers/project_handler.py +6 -20
  644. scitex/scholar/cli/open_browser.py +41 -39
  645. scitex/scholar/cli/open_browser_auto.py +31 -39
  646. scitex/scholar/cli/open_browser_monitored.py +27 -24
  647. scitex/scholar/config/ScholarConfig.py +5 -8
  648. scitex/scholar/config/__init__.py +1 -0
  649. scitex/scholar/config/core/_CascadeConfig.py +3 -3
  650. scitex/scholar/config/core/_PathManager.py +16 -28
  651. scitex/scholar/core/Paper.py +79 -78
  652. scitex/scholar/core/Papers.py +16 -27
  653. scitex/scholar/core/Scholar.py +98 -229
  654. scitex/scholar/core/journal_normalizer.py +52 -49
  655. scitex/scholar/core/oa_cache.py +27 -23
  656. scitex/scholar/core/open_access.py +17 -8
  657. scitex/scholar/docs/template.py +4 -3
  658. scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/clf_svm.py +0 -0
  659. scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/download.py +0 -0
  660. scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/plot_conf_mat.py +0 -0
  661. scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/plot_digits.py +0 -0
  662. scitex/scholar/docs/to_claude/examples/example-python-project-scitex/scripts/mnist/plot_umap_space.py +0 -0
  663. scitex/scholar/examples/00_config.py +10 -9
  664. scitex/scholar/examples/01_auth.py +3 -0
  665. scitex/scholar/examples/02_browser.py +14 -10
  666. scitex/scholar/examples/03_01-engine.py +3 -0
  667. scitex/scholar/examples/03_02-engine-for-bibtex.py +4 -3
  668. scitex/scholar/examples/04_01-url.py +9 -9
  669. scitex/scholar/examples/04_02-url-for-bibtex.py +7 -3
  670. scitex/scholar/examples/04_02-url-for-dois.py +87 -97
  671. scitex/scholar/examples/05_download_pdf.py +10 -4
  672. scitex/scholar/examples/06_find_and_download.py +6 -6
  673. scitex/scholar/examples/06_parse_bibtex.py +17 -17
  674. scitex/scholar/examples/07_storage_integration.py +6 -9
  675. scitex/scholar/examples/99_fullpipeline-for-bibtex.py +14 -15
  676. scitex/scholar/examples/99_fullpipeline-for-one-entry.py +31 -23
  677. scitex/scholar/examples/99_maintenance.py +3 -0
  678. scitex/scholar/examples/dev.py +2 -3
  679. scitex/scholar/examples/zotero_integration.py +11 -18
  680. scitex/scholar/impact_factor/ImpactFactorEngine.py +7 -9
  681. scitex/scholar/impact_factor/estimation/__init__.py +4 -4
  682. scitex/scholar/impact_factor/estimation/core/__init__.py +3 -7
  683. scitex/scholar/impact_factor/estimation/core/cache_manager.py +223 -211
  684. scitex/scholar/impact_factor/estimation/core/calculator.py +165 -131
  685. scitex/scholar/impact_factor/estimation/core/journal_matcher.py +217 -172
  686. scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +6 -14
  687. scitex/scholar/impact_factor/jcr/build_database.py +4 -3
  688. scitex/scholar/integration/base.py +9 -17
  689. scitex/scholar/integration/mendeley/exporter.py +2 -4
  690. scitex/scholar/integration/mendeley/importer.py +3 -3
  691. scitex/scholar/integration/mendeley/linker.py +3 -3
  692. scitex/scholar/integration/mendeley/mapper.py +9 -6
  693. scitex/scholar/integration/zotero/__main__.py +26 -43
  694. scitex/scholar/integration/zotero/exporter.py +15 -11
  695. scitex/scholar/integration/zotero/importer.py +12 -10
  696. scitex/scholar/integration/zotero/linker.py +8 -12
  697. scitex/scholar/integration/zotero/mapper.py +17 -12
  698. scitex/scholar/metadata_engines/.combined-SemanticScholarSource/_SemanticScholarSource.py +37 -35
  699. scitex/scholar/metadata_engines/.combined-SemanticScholarSource/_SemanticScholarSourceEnhanced.py +47 -35
  700. scitex/scholar/metadata_engines/ScholarEngine.py +21 -43
  701. scitex/scholar/metadata_engines/__init__.py +1 -0
  702. scitex/scholar/metadata_engines/individual/ArXivEngine.py +15 -37
  703. scitex/scholar/metadata_engines/individual/CrossRefEngine.py +15 -42
  704. scitex/scholar/metadata_engines/individual/CrossRefLocalEngine.py +24 -45
  705. scitex/scholar/metadata_engines/individual/OpenAlexEngine.py +11 -21
  706. scitex/scholar/metadata_engines/individual/PubMedEngine.py +10 -27
  707. scitex/scholar/metadata_engines/individual/SemanticScholarEngine.py +28 -35
  708. scitex/scholar/metadata_engines/individual/URLDOIEngine.py +11 -22
  709. scitex/scholar/metadata_engines/individual/_BaseDOIEngine.py +20 -49
  710. scitex/scholar/metadata_engines/utils/_PubMedConverter.py +4 -8
  711. scitex/scholar/metadata_engines/utils/_URLDOIExtractor.py +5 -10
  712. scitex/scholar/metadata_engines/utils/__init__.py +2 -0
  713. scitex/scholar/metadata_engines/utils/_metadata2bibtex.py +3 -0
  714. scitex/scholar/metadata_engines/utils/_standardize_metadata.py +2 -3
  715. scitex/scholar/pdf_download/ScholarPDFDownloader.py +25 -37
  716. scitex/scholar/pdf_download/strategies/chrome_pdf_viewer.py +11 -19
  717. scitex/scholar/pdf_download/strategies/direct_download.py +5 -9
  718. scitex/scholar/pdf_download/strategies/manual_download_fallback.py +3 -3
  719. scitex/scholar/pdf_download/strategies/manual_download_utils.py +6 -13
  720. scitex/scholar/pdf_download/strategies/open_access_download.py +49 -31
  721. scitex/scholar/pdf_download/strategies/response_body.py +8 -19
  722. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +9 -18
  723. scitex/scholar/pipelines/ScholarPipelineMetadataParallel.py +25 -26
  724. scitex/scholar/pipelines/ScholarPipelineMetadataSingle.py +62 -23
  725. scitex/scholar/pipelines/ScholarPipelineParallel.py +13 -30
  726. scitex/scholar/pipelines/ScholarPipelineSearchParallel.py +299 -220
  727. scitex/scholar/pipelines/ScholarPipelineSearchSingle.py +202 -165
  728. scitex/scholar/pipelines/ScholarPipelineSingle.py +25 -51
  729. scitex/scholar/pipelines/SearchQueryParser.py +55 -55
  730. scitex/scholar/search_engines/ScholarSearchEngine.py +31 -27
  731. scitex/scholar/search_engines/_BaseSearchEngine.py +20 -23
  732. scitex/scholar/search_engines/individual/ArXivSearchEngine.py +53 -35
  733. scitex/scholar/search_engines/individual/CrossRefSearchEngine.py +47 -40
  734. scitex/scholar/search_engines/individual/OpenAlexSearchEngine.py +55 -50
  735. scitex/scholar/search_engines/individual/PubMedSearchEngine.py +8 -10
  736. scitex/scholar/search_engines/individual/SemanticScholarSearchEngine.py +55 -49
  737. scitex/scholar/storage/BibTeXHandler.py +150 -95
  738. scitex/scholar/storage/PaperIO.py +3 -6
  739. scitex/scholar/storage/ScholarLibrary.py +70 -49
  740. scitex/scholar/storage/_DeduplicationManager.py +52 -25
  741. scitex/scholar/storage/_LibraryCacheManager.py +19 -46
  742. scitex/scholar/storage/_LibraryManager.py +65 -175
  743. scitex/scholar/url_finder/ScholarURLFinder.py +9 -25
  744. scitex/scholar/url_finder/strategies/find_pdf_urls_by_direct_links.py +1 -1
  745. scitex/scholar/url_finder/strategies/find_pdf_urls_by_href.py +6 -10
  746. scitex/scholar/url_finder/strategies/find_pdf_urls_by_navigation.py +4 -6
  747. scitex/scholar/url_finder/strategies/find_pdf_urls_by_publisher_patterns.py +8 -15
  748. scitex/scholar/url_finder/strategies/find_pdf_urls_by_zotero_translators.py +3 -3
  749. scitex/scholar/url_finder/strategies/find_supplementary_urls_by_href.py +3 -3
  750. scitex/scholar/url_finder/translators/core/patterns.py +6 -4
  751. scitex/scholar/url_finder/translators/core/registry.py +6 -9
  752. scitex/scholar/url_finder/translators/individual/BOFiP_Impots.py +60 -52
  753. scitex/scholar/url_finder/translators/individual/Baidu_Scholar.py +54 -62
  754. scitex/scholar/url_finder/translators/individual/Bangkok_Post.py +38 -44
  755. scitex/scholar/url_finder/translators/individual/Baruch_Foundation.py +43 -47
  756. scitex/scholar/url_finder/translators/individual/Beobachter.py +46 -50
  757. scitex/scholar/url_finder/translators/individual/Bezneng_Gajit.py +37 -41
  758. scitex/scholar/url_finder/translators/individual/BibLaTeX.py +59 -52
  759. scitex/scholar/url_finder/translators/individual/BibTeX.py +83 -79
  760. scitex/scholar/url_finder/translators/individual/Biblio_com.py +48 -51
  761. scitex/scholar/url_finder/translators/individual/Bibliontology_RDF.py +58 -56
  762. scitex/scholar/url_finder/translators/individual/Camara_Brasileira_do_Livro_ISBN.py +102 -99
  763. scitex/scholar/url_finder/translators/individual/CanLII.py +49 -43
  764. scitex/scholar/url_finder/translators/individual/Canada_com.py +36 -40
  765. scitex/scholar/url_finder/translators/individual/Canadian_Letters_and_Images.py +43 -43
  766. scitex/scholar/url_finder/translators/individual/Canadiana_ca.py +77 -66
  767. scitex/scholar/url_finder/translators/individual/Cascadilla_Proceedings_Project.py +68 -62
  768. scitex/scholar/url_finder/translators/individual/Central_and_Eastern_European_Online_Library_Journals.py +60 -60
  769. scitex/scholar/url_finder/translators/individual/Champlain_Society_Collection.py +63 -61
  770. scitex/scholar/url_finder/translators/individual/Chicago_Journal_of_Theoretical_Computer_Science.py +74 -58
  771. scitex/scholar/url_finder/translators/individual/Christian_Science_Monitor.py +32 -38
  772. scitex/scholar/url_finder/translators/individual/Columbia_University_Press.py +51 -47
  773. scitex/scholar/url_finder/translators/individual/Common_Place.py +66 -57
  774. scitex/scholar/url_finder/translators/individual/Cornell_LII.py +66 -62
  775. scitex/scholar/url_finder/translators/individual/Cornell_University_Press.py +38 -45
  776. scitex/scholar/url_finder/translators/individual/CourtListener.py +52 -56
  777. scitex/scholar/url_finder/translators/individual/DAI_Zenon.py +53 -54
  778. scitex/scholar/url_finder/translators/individual/access_medicine.py +27 -33
  779. scitex/scholar/url_finder/translators/individual/acm.py +1 -1
  780. scitex/scholar/url_finder/translators/individual/acm_digital_library.py +93 -63
  781. scitex/scholar/url_finder/translators/individual/airiti.py +3 -1
  782. scitex/scholar/url_finder/translators/individual/aosic.py +3 -1
  783. scitex/scholar/url_finder/translators/individual/archive_ouverte_aosic.py +3 -1
  784. scitex/scholar/url_finder/translators/individual/archive_ouverte_en_sciences_de_l_information_et_de_la_communication___aosic_.py +6 -2
  785. scitex/scholar/url_finder/translators/individual/artforum.py +35 -27
  786. scitex/scholar/url_finder/translators/individual/arxiv.py +1 -1
  787. scitex/scholar/url_finder/translators/individual/arxiv_org.py +8 -4
  788. scitex/scholar/url_finder/translators/individual/atlanta_journal_constitution.py +22 -18
  789. scitex/scholar/url_finder/translators/individual/atypon_journals.py +19 -11
  790. scitex/scholar/url_finder/translators/individual/austlii_and_nzlii.py +48 -44
  791. scitex/scholar/url_finder/translators/individual/australian_dictionary_of_biography.py +21 -17
  792. scitex/scholar/url_finder/translators/individual/bailii.py +22 -19
  793. scitex/scholar/url_finder/translators/individual/bbc.py +46 -42
  794. scitex/scholar/url_finder/translators/individual/bbc_genome.py +37 -25
  795. scitex/scholar/url_finder/translators/individual/biblioteca_nacional_de_maestros.py +24 -20
  796. scitex/scholar/url_finder/translators/individual/bibliotheque_archives_nationale_quebec_pistard.py +42 -43
  797. scitex/scholar/url_finder/translators/individual/bibliotheque_archives_nationales_quebec.py +87 -81
  798. scitex/scholar/url_finder/translators/individual/bibliotheque_nationale_france.py +39 -37
  799. scitex/scholar/url_finder/translators/individual/bibsys.py +32 -28
  800. scitex/scholar/url_finder/translators/individual/bioconductor.py +58 -52
  801. scitex/scholar/url_finder/translators/individual/biomed_central.py +23 -15
  802. scitex/scholar/url_finder/translators/individual/biorxiv.py +26 -13
  803. scitex/scholar/url_finder/translators/individual/blogger.py +39 -43
  804. scitex/scholar/url_finder/translators/individual/bloomberg.py +48 -52
  805. scitex/scholar/url_finder/translators/individual/bloomsbury_food_library.py +37 -37
  806. scitex/scholar/url_finder/translators/individual/bluesky.py +30 -28
  807. scitex/scholar/url_finder/translators/individual/bnf_isbn.py +1 -1
  808. scitex/scholar/url_finder/translators/individual/bocc.py +66 -60
  809. scitex/scholar/url_finder/translators/individual/boe.py +52 -52
  810. scitex/scholar/url_finder/translators/individual/brill.py +3 -1
  811. scitex/scholar/url_finder/translators/individual/business_standard.py +36 -38
  812. scitex/scholar/url_finder/translators/individual/cabi_cab_abstracts.py +39 -41
  813. scitex/scholar/url_finder/translators/individual/cambridge.py +3 -1
  814. scitex/scholar/url_finder/translators/individual/cambridge_core.py +30 -24
  815. scitex/scholar/url_finder/translators/individual/caod.py +50 -46
  816. scitex/scholar/url_finder/translators/individual/cbc.py +91 -67
  817. scitex/scholar/url_finder/translators/individual/ccfr_bnf.py +49 -53
  818. scitex/scholar/url_finder/translators/individual/cia_world_factbook.py +43 -33
  819. scitex/scholar/url_finder/translators/individual/crossref_rest.py +208 -174
  820. scitex/scholar/url_finder/translators/individual/current_affairs.py +29 -35
  821. scitex/scholar/url_finder/translators/individual/dabi.py +70 -66
  822. scitex/scholar/url_finder/translators/individual/dagens_nyheter.py +3 -1
  823. scitex/scholar/url_finder/translators/individual/dagstuhl.py +10 -15
  824. scitex/scholar/url_finder/translators/individual/dar_almandumah.py +13 -9
  825. scitex/scholar/url_finder/translators/individual/dart_europe.py +19 -22
  826. scitex/scholar/url_finder/translators/individual/data_gov.py +2 -2
  827. scitex/scholar/url_finder/translators/individual/databrary.py +27 -28
  828. scitex/scholar/url_finder/translators/individual/datacite_json.py +152 -137
  829. scitex/scholar/url_finder/translators/individual/dataverse.py +68 -64
  830. scitex/scholar/url_finder/translators/individual/daum_news.py +38 -38
  831. scitex/scholar/url_finder/translators/individual/dblp.py +4 -8
  832. scitex/scholar/url_finder/translators/individual/dblp_computer_science_bibliography.py +8 -3
  833. scitex/scholar/url_finder/translators/individual/dbpia.py +5 -3
  834. scitex/scholar/url_finder/translators/individual/defense_technical_information_center.py +30 -28
  835. scitex/scholar/url_finder/translators/individual/delpher.py +102 -79
  836. scitex/scholar/url_finder/translators/individual/demographic_research.py +35 -31
  837. scitex/scholar/url_finder/translators/individual/denik_cz.py +58 -54
  838. scitex/scholar/url_finder/translators/individual/depatisnet.py +7 -10
  839. scitex/scholar/url_finder/translators/individual/der_freitag.py +81 -66
  840. scitex/scholar/url_finder/translators/individual/der_spiegel.py +56 -54
  841. scitex/scholar/url_finder/translators/individual/digibib_net.py +3 -1
  842. scitex/scholar/url_finder/translators/individual/digizeitschriften.py +3 -1
  843. scitex/scholar/url_finder/translators/individual/dpla.py +13 -14
  844. scitex/scholar/url_finder/translators/individual/dspace.py +2 -2
  845. scitex/scholar/url_finder/translators/individual/ebrary.py +3 -1
  846. scitex/scholar/url_finder/translators/individual/ebscohost.py +3 -1
  847. scitex/scholar/url_finder/translators/individual/electronic_colloquium_on_computational_complexity.py +3 -1
  848. scitex/scholar/url_finder/translators/individual/elife.py +3 -1
  849. scitex/scholar/url_finder/translators/individual/elsevier_health_journals.py +3 -1
  850. scitex/scholar/url_finder/translators/individual/emerald.py +3 -1
  851. scitex/scholar/url_finder/translators/individual/emerald_insight.py +3 -1
  852. scitex/scholar/url_finder/translators/individual/epicurious.py +3 -1
  853. scitex/scholar/url_finder/translators/individual/eurogamerusgamer.py +3 -1
  854. scitex/scholar/url_finder/translators/individual/fachportal_padagogik.py +3 -1
  855. scitex/scholar/url_finder/translators/individual/frontiers.py +1 -1
  856. scitex/scholar/url_finder/translators/individual/gale_databases.py +3 -1
  857. scitex/scholar/url_finder/translators/individual/gms_german_medical_science.py +6 -2
  858. scitex/scholar/url_finder/translators/individual/ieee_computer_society.py +6 -2
  859. scitex/scholar/url_finder/translators/individual/ieee_xplore.py +41 -35
  860. scitex/scholar/url_finder/translators/individual/inter_research_science_center.py +6 -2
  861. scitex/scholar/url_finder/translators/individual/jisc_historical_texts.py +3 -1
  862. scitex/scholar/url_finder/translators/individual/jstor.py +14 -12
  863. scitex/scholar/url_finder/translators/individual/korean_national_library.py +3 -1
  864. scitex/scholar/url_finder/translators/individual/la_times.py +3 -1
  865. scitex/scholar/url_finder/translators/individual/landesbibliographie_baden_wurttemberg.py +3 -1
  866. scitex/scholar/url_finder/translators/individual/legislative_insight.py +3 -1
  867. scitex/scholar/url_finder/translators/individual/libraries_tasmania.py +3 -1
  868. scitex/scholar/url_finder/translators/individual/library_catalog__koha_.py +3 -1
  869. scitex/scholar/url_finder/translators/individual/lingbuzz.py +2 -2
  870. scitex/scholar/url_finder/translators/individual/max_planck_institute_for_the_history_of_science_virtual_laboratory_library.py +3 -1
  871. scitex/scholar/url_finder/translators/individual/mdpi.py +12 -6
  872. scitex/scholar/url_finder/translators/individual/microbiology_society_journals.py +3 -1
  873. scitex/scholar/url_finder/translators/individual/midas_journals.py +3 -1
  874. scitex/scholar/url_finder/translators/individual/nagoya_university_opac.py +3 -1
  875. scitex/scholar/url_finder/translators/individual/nature_publishing_group.py +32 -19
  876. scitex/scholar/url_finder/translators/individual/ntsb_accident_reports.py +3 -1
  877. scitex/scholar/url_finder/translators/individual/openedition_journals.py +8 -4
  878. scitex/scholar/url_finder/translators/individual/orcid.py +16 -15
  879. scitex/scholar/url_finder/translators/individual/oxford.py +25 -19
  880. scitex/scholar/url_finder/translators/individual/oxford_dictionaries_premium.py +3 -1
  881. scitex/scholar/url_finder/translators/individual/ozon_ru.py +3 -1
  882. scitex/scholar/url_finder/translators/individual/plos.py +9 -12
  883. scitex/scholar/url_finder/translators/individual/polygon.py +3 -1
  884. scitex/scholar/url_finder/translators/individual/primo.py +3 -1
  885. scitex/scholar/url_finder/translators/individual/project_muse.py +3 -1
  886. scitex/scholar/url_finder/translators/individual/pubfactory_journals.py +3 -1
  887. scitex/scholar/url_finder/translators/individual/pubmed.py +71 -65
  888. scitex/scholar/url_finder/translators/individual/pubmed_central.py +8 -6
  889. scitex/scholar/url_finder/translators/individual/rechtspraak_nl.py +3 -1
  890. scitex/scholar/url_finder/translators/individual/sage_journals.py +25 -17
  891. scitex/scholar/url_finder/translators/individual/sciencedirect.py +36 -17
  892. scitex/scholar/url_finder/translators/individual/semantics_visual_library.py +3 -1
  893. scitex/scholar/url_finder/translators/individual/silverchair.py +70 -52
  894. scitex/scholar/url_finder/translators/individual/sora.py +3 -1
  895. scitex/scholar/url_finder/translators/individual/springer.py +15 -11
  896. scitex/scholar/url_finder/translators/individual/ssrn.py +3 -3
  897. scitex/scholar/url_finder/translators/individual/stanford_encyclopedia_of_philosophy.py +3 -1
  898. scitex/scholar/url_finder/translators/individual/superlib.py +3 -1
  899. scitex/scholar/url_finder/translators/individual/treesearch.py +3 -1
  900. scitex/scholar/url_finder/translators/individual/university_of_chicago_press_books.py +3 -1
  901. scitex/scholar/url_finder/translators/individual/vlex.py +3 -1
  902. scitex/scholar/url_finder/translators/individual/web_of_science.py +3 -1
  903. scitex/scholar/url_finder/translators/individual/web_of_science_nextgen.py +3 -1
  904. scitex/scholar/url_finder/translators/individual/wiley.py +31 -25
  905. scitex/scholar/url_finder/translators/individual/wilson_center_digital_archive.py +3 -1
  906. scitex/scholar/utils/bibtex/_parse_bibtex.py +3 -3
  907. scitex/scholar/utils/cleanup/_cleanup_scholar_processes.py +5 -9
  908. scitex/scholar/utils/text/_TextNormalizer.py +249 -176
  909. scitex/scholar/utils/validation/DOIValidator.py +31 -28
  910. scitex/scholar/utils/validation/__init__.py +0 -0
  911. scitex/scholar/utils/validation/validate_library_dois.py +61 -57
  912. scitex/scholar/zotero/__init__.py +1 -1
  913. scitex/security/cli.py +7 -20
  914. scitex/security/github.py +45 -32
  915. scitex/session/__init__.py +8 -9
  916. scitex/session/_decorator.py +60 -41
  917. scitex/session/_lifecycle.py +39 -39
  918. scitex/session/_manager.py +24 -20
  919. scitex/sh/__init__.py +4 -3
  920. scitex/sh/_execute.py +10 -7
  921. scitex/sh/_security.py +3 -3
  922. scitex/sh/_types.py +2 -3
  923. scitex/stats/__init__.py +57 -6
  924. scitex/stats/_schema.py +42 -569
  925. scitex/stats/auto/__init__.py +188 -0
  926. scitex/stats/auto/_context.py +331 -0
  927. scitex/stats/auto/_formatting.py +679 -0
  928. scitex/stats/auto/_rules.py +901 -0
  929. scitex/stats/auto/_selector.py +554 -0
  930. scitex/stats/auto/_styles.py +721 -0
  931. scitex/stats/correct/__init__.py +4 -4
  932. scitex/stats/correct/_correct_bonferroni.py +43 -34
  933. scitex/stats/correct/_correct_fdr.py +14 -40
  934. scitex/stats/correct/_correct_fdr_.py +39 -46
  935. scitex/stats/correct/_correct_holm.py +14 -32
  936. scitex/stats/correct/_correct_sidak.py +36 -21
  937. scitex/stats/descriptive/_circular.py +20 -21
  938. scitex/stats/descriptive/_describe.py +19 -5
  939. scitex/stats/descriptive/_nan.py +5 -7
  940. scitex/stats/descriptive/_real.py +4 -3
  941. scitex/stats/effect_sizes/__init__.py +10 -11
  942. scitex/stats/effect_sizes/_cliffs_delta.py +35 -32
  943. scitex/stats/effect_sizes/_cohens_d.py +30 -31
  944. scitex/stats/effect_sizes/_epsilon_squared.py +19 -22
  945. scitex/stats/effect_sizes/_eta_squared.py +23 -27
  946. scitex/stats/effect_sizes/_prob_superiority.py +18 -21
  947. scitex/stats/posthoc/__init__.py +3 -3
  948. scitex/stats/posthoc/_dunnett.py +75 -55
  949. scitex/stats/posthoc/_games_howell.py +61 -43
  950. scitex/stats/posthoc/_tukey_hsd.py +42 -34
  951. scitex/stats/power/__init__.py +2 -2
  952. scitex/stats/power/_power.py +56 -56
  953. scitex/stats/tests/__init__.py +1 -1
  954. scitex/stats/tests/correlation/__init__.py +1 -1
  955. scitex/stats/tests/correlation/_test_pearson.py +28 -38
  956. scitex/stats/utils/__init__.py +14 -17
  957. scitex/stats/utils/_effect_size.py +85 -78
  958. scitex/stats/utils/_formatters.py +49 -43
  959. scitex/stats/utils/_normalizers.py +7 -14
  960. scitex/stats/utils/_power.py +56 -56
  961. scitex/str/__init__.py +1 -0
  962. scitex/str/_clean_path.py +3 -3
  963. scitex/str/_factor_out_digits.py +86 -58
  964. scitex/str/_format_plot_text.py +180 -111
  965. scitex/str/_latex.py +19 -19
  966. scitex/str/_latex_fallback.py +9 -10
  967. scitex/str/_parse.py +3 -6
  968. scitex/str/_print_debug.py +13 -13
  969. scitex/str/_printc.py +2 -0
  970. scitex/str/_search.py +3 -3
  971. scitex/template/.legacy/_clone_project.py +9 -13
  972. scitex/template/__init__.py +10 -2
  973. scitex/template/_clone_project.py +7 -2
  974. scitex/template/_copy.py +1 -0
  975. scitex/template/_customize.py +3 -6
  976. scitex/template/_git_strategy.py +2 -3
  977. scitex/template/_rename.py +1 -0
  978. scitex/template/clone_pip_project.py +6 -7
  979. scitex/template/clone_research.py +7 -10
  980. scitex/template/clone_singularity.py +6 -7
  981. scitex/template/clone_writer_directory.py +6 -7
  982. scitex/tex/_preview.py +26 -11
  983. scitex/tex/_to_vec.py +10 -7
  984. scitex/torch/__init__.py +11 -1
  985. scitex/types/_ArrayLike.py +2 -0
  986. scitex/types/_is_listed_X.py +3 -3
  987. scitex/units.py +110 -77
  988. scitex/utils/_compress_hdf5.py +3 -3
  989. scitex/utils/_email.py +8 -4
  990. scitex/utils/_notify.py +14 -8
  991. scitex/utils/_search.py +6 -6
  992. scitex/utils/_verify_scitex_format.py +17 -42
  993. scitex/utils/_verify_scitex_format_v01.py +12 -34
  994. scitex/utils/template.py +4 -3
  995. scitex/vis/README.md +246 -615
  996. scitex/vis/__init__.py +138 -78
  997. scitex/vis/backend/__init__.py +3 -3
  998. scitex/vis/backend/{export.py → _export.py} +1 -1
  999. scitex/vis/backend/{parser.py → _parser.py} +1 -3
  1000. scitex/vis/backend/{render.py → _render.py} +1 -1
  1001. scitex/vis/canvas.py +435 -0
  1002. scitex/vis/docs/CANVAS_ARCHITECTURE.md +307 -0
  1003. scitex/vis/editor/__init__.py +1 -1
  1004. scitex/vis/editor/_dearpygui_editor.py +1976 -0
  1005. scitex/vis/editor/_defaults.py +140 -110
  1006. scitex/vis/editor/_edit.py +90 -42
  1007. scitex/vis/editor/_flask_editor.py +37 -0
  1008. scitex/vis/editor/_mpl_editor.py +63 -48
  1009. scitex/vis/editor/_qt_editor.py +916 -0
  1010. scitex/vis/editor/_tkinter_editor.py +146 -89
  1011. scitex/vis/editor/flask_editor/__init__.py +21 -0
  1012. scitex/vis/editor/flask_editor/_bbox.py +529 -0
  1013. scitex/vis/editor/flask_editor/_core.py +168 -0
  1014. scitex/vis/editor/flask_editor/_plotter.py +567 -0
  1015. scitex/vis/editor/flask_editor/_renderer.py +393 -0
  1016. scitex/vis/editor/flask_editor/_utils.py +80 -0
  1017. scitex/vis/editor/flask_editor/templates/__init__.py +33 -0
  1018. scitex/vis/editor/flask_editor/templates/_html.py +513 -0
  1019. scitex/vis/editor/flask_editor/templates/_scripts.py +1261 -0
  1020. scitex/vis/editor/flask_editor/templates/_styles.py +739 -0
  1021. scitex/vis/io/__init__.py +84 -21
  1022. scitex/vis/io/_canvas.py +230 -0
  1023. scitex/vis/io/_data.py +208 -0
  1024. scitex/vis/io/_directory.py +205 -0
  1025. scitex/vis/io/_export.py +463 -0
  1026. scitex/vis/io/{load.py → _load.py} +1 -1
  1027. scitex/vis/io/_panel.py +432 -0
  1028. scitex/vis/io/{save.py → _save.py} +0 -0
  1029. scitex/vis/model/__init__.py +7 -7
  1030. scitex/vis/model/{annotations.py → _annotations.py} +2 -4
  1031. scitex/vis/model/{axes.py → _axes.py} +1 -1
  1032. scitex/vis/model/{figure.py → _figure.py} +0 -0
  1033. scitex/vis/model/{guides.py → _guides.py} +1 -1
  1034. scitex/vis/model/{plot.py → _plot.py} +2 -4
  1035. scitex/vis/model/{plot_types.py → _plot_types.py} +0 -0
  1036. scitex/vis/model/{styles.py → _styles.py} +0 -0
  1037. scitex/vis/utils/__init__.py +2 -2
  1038. scitex/vis/utils/{defaults.py → _defaults.py} +1 -2
  1039. scitex/vis/utils/{validate.py → _validate.py} +3 -9
  1040. scitex/web/__init__.py +7 -1
  1041. scitex/web/_scraping.py +54 -38
  1042. scitex/web/_search_pubmed.py +30 -14
  1043. scitex/writer/.legacy/Writer_v01-refactored.py +4 -4
  1044. scitex/writer/.legacy/_compile.py +18 -28
  1045. scitex/writer/Writer.py +8 -21
  1046. scitex/writer/__init__.py +11 -11
  1047. scitex/writer/_clone_writer_project.py +2 -6
  1048. scitex/writer/_compile/__init__.py +1 -0
  1049. scitex/writer/_compile/_parser.py +1 -0
  1050. scitex/writer/_compile/_runner.py +35 -38
  1051. scitex/writer/_compile/_validator.py +1 -0
  1052. scitex/writer/_compile/manuscript.py +1 -0
  1053. scitex/writer/_compile/revision.py +1 -0
  1054. scitex/writer/_compile/supplementary.py +1 -0
  1055. scitex/writer/_compile_async.py +5 -12
  1056. scitex/writer/_project/__init__.py +1 -0
  1057. scitex/writer/_project/_create.py +10 -25
  1058. scitex/writer/_project/_trees.py +4 -9
  1059. scitex/writer/_project/_validate.py +2 -3
  1060. scitex/writer/_validate_tree_structures.py +7 -18
  1061. scitex/writer/dataclasses/__init__.py +8 -10
  1062. scitex/writer/dataclasses/config/_CONSTANTS.py +2 -3
  1063. scitex/writer/dataclasses/config/_WriterConfig.py +4 -9
  1064. scitex/writer/dataclasses/contents/_ManuscriptContents.py +14 -25
  1065. scitex/writer/dataclasses/contents/_RevisionContents.py +21 -16
  1066. scitex/writer/dataclasses/contents/_SupplementaryContents.py +21 -24
  1067. scitex/writer/dataclasses/core/_Document.py +2 -3
  1068. scitex/writer/dataclasses/core/_DocumentSection.py +8 -23
  1069. scitex/writer/dataclasses/results/_CompilationResult.py +2 -3
  1070. scitex/writer/dataclasses/results/_LaTeXIssue.py +3 -6
  1071. scitex/writer/dataclasses/results/_SaveSectionsResponse.py +20 -9
  1072. scitex/writer/dataclasses/results/_SectionReadResponse.py +24 -10
  1073. scitex/writer/dataclasses/tree/_ConfigTree.py +7 -4
  1074. scitex/writer/dataclasses/tree/_ManuscriptTree.py +10 -13
  1075. scitex/writer/dataclasses/tree/_RevisionTree.py +16 -17
  1076. scitex/writer/dataclasses/tree/_ScriptsTree.py +10 -5
  1077. scitex/writer/dataclasses/tree/_SharedTree.py +10 -13
  1078. scitex/writer/dataclasses/tree/_SupplementaryTree.py +15 -14
  1079. scitex/writer/utils/.legacy_git_retry.py +3 -8
  1080. scitex/writer/utils/_parse_latex_logs.py +2 -3
  1081. scitex/writer/utils/_parse_script_args.py +20 -23
  1082. scitex/writer/utils/_watch.py +5 -5
  1083. {scitex-2.4.3.dist-info → scitex-2.7.0.dist-info}/METADATA +12 -11
  1084. {scitex-2.4.3.dist-info → scitex-2.7.0.dist-info}/RECORD +1075 -958
  1085. scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin_v01-indentation-issues.py +0 -583
  1086. scitex/plt/_subplots/_export_as_csv_formatters.py +0 -112
  1087. scitex/vis/DJANGO_INTEGRATION.md +0 -677
  1088. scitex/vis/editor/_web_editor.py +0 -1440
  1089. scitex/vis/tmp.txt +0 -239
  1090. {scitex-2.4.3.dist-info → scitex-2.7.0.dist-info}/WHEEL +0 -0
  1091. {scitex-2.4.3.dist-info → scitex-2.7.0.dist-info}/entry_points.txt +0 -0
  1092. {scitex-2.4.3.dist-info → scitex-2.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -47,9 +47,7 @@ def style_colorbar(cbar):
47
47
 
48
48
  # Style the ticks
49
49
  cbar.ax.tick_params(
50
- width=line_width,
51
- length=tick_length,
52
- labelsize=COLORBAR_TICK_FONTSIZE
50
+ width=line_width, length=tick_length, labelsize=COLORBAR_TICK_FONTSIZE
53
51
  )
54
52
 
55
53
  # Style the colorbar axis spines
@@ -85,9 +83,9 @@ def colorbar(mappable, ax=None, n_ticks=4, **kwargs):
85
83
 
86
84
  # Set better defaults for colorbar placement
87
85
  defaults = {
88
- 'fraction': 0.046, # Fraction of axes to use for colorbar
89
- 'pad': 0.04, # Padding between axes and colorbar
90
- 'aspect': 20, # Aspect ratio of colorbar
86
+ "fraction": 0.046, # Fraction of axes to use for colorbar
87
+ "pad": 0.04, # Padding between axes and colorbar
88
+ "aspect": 20, # Aspect ratio of colorbar
91
89
  }
92
90
 
93
91
  # Update defaults with any user-provided kwargs
@@ -99,7 +97,7 @@ def colorbar(mappable, ax=None, n_ticks=4, **kwargs):
99
97
  cbar = plt.colorbar(mappable, ax=ax, **kwargs)
100
98
 
101
99
  # Limit number of ticks to match main axes style (3-4 ticks)
102
- cbar.locator = MaxNLocator(nbins=n_ticks, min_n_ticks=2, prune='both')
100
+ cbar.locator = MaxNLocator(nbins=n_ticks, min_n_ticks=2, prune="both")
103
101
  cbar.update_ticks()
104
102
 
105
103
  # Apply publication-quality styling
@@ -107,17 +105,17 @@ def colorbar(mappable, ax=None, n_ticks=4, **kwargs):
107
105
 
108
106
  # If using constrained_layout, ensure the figure updates
109
107
  if ax is not None:
110
- fig = ax.figure if hasattr(ax, 'figure') else ax[0].figure
111
- if hasattr(fig, 'get_constrained_layout') and fig.get_constrained_layout():
108
+ fig = ax.figure if hasattr(ax, "figure") else ax[0].figure
109
+ if hasattr(fig, "get_constrained_layout") and fig.get_constrained_layout():
112
110
  # Force a layout update
113
111
  fig.canvas.draw_idle()
114
112
 
115
113
  return cbar
116
114
 
117
115
 
118
- def add_shared_colorbar(fig, axes, mappable, location='right', **kwargs):
116
+ def add_shared_colorbar(fig, axes, mappable, location="right", **kwargs):
119
117
  """Add a single colorbar shared by multiple axes.
120
-
118
+
121
119
  Parameters
122
120
  ----------
123
121
  fig : matplotlib.figure.Figure
@@ -130,22 +128,22 @@ def add_shared_colorbar(fig, axes, mappable, location='right', **kwargs):
130
128
  Where to place the colorbar (default: 'right')
131
129
  **kwargs : dict
132
130
  Additional keyword arguments passed to fig.colorbar
133
-
131
+
134
132
  Returns
135
133
  -------
136
134
  colorbar : matplotlib.colorbar.Colorbar
137
135
  The colorbar instance
138
136
  """
139
137
  defaults = {
140
- 'shrink': 0.8, # Shrink colorbar to match axes height
141
- 'aspect': 30, # Make it thinner for shared colorbars
138
+ "shrink": 0.8, # Shrink colorbar to match axes height
139
+ "aspect": 30, # Make it thinner for shared colorbars
142
140
  }
143
-
141
+
144
142
  # Update defaults with any user-provided kwargs
145
143
  for key, value in defaults.items():
146
144
  if key not in kwargs:
147
145
  kwargs[key] = value
148
-
146
+
149
147
  # Create the shared colorbar
150
148
  cbar = fig.colorbar(mappable, ax=axes, location=location, **kwargs)
151
149
 
@@ -155,4 +153,4 @@ def add_shared_colorbar(fig, axes, mappable, location='right', **kwargs):
155
153
  return cbar
156
154
 
157
155
 
158
- # EOF
156
+ # EOF
@@ -180,9 +180,7 @@ def configure_mpl(
180
180
  # Spine width from YAML (converted from mm to pt)
181
181
  "axes.linewidth": axes_linewidth,
182
182
  # Custom color cycle
183
- "axes.prop_cycle": plt.cycler(
184
- color=list(RGBA_NORM_FOR_CYCLE.values())
185
- ),
183
+ "axes.prop_cycle": plt.cycler(color=list(RGBA_NORM_FOR_CYCLE.values())),
186
184
  # Line width from YAML (converted from mm to pt)
187
185
  "lines.linewidth": line_width,
188
186
  "lines.markersize": 6.0,
@@ -227,12 +225,8 @@ def configure_mpl(
227
225
 
228
226
  except Exception as e:
229
227
  if verbose:
230
- print(
231
- f"⚠️ LaTeX rendering failed, falling back to mathtext: {e}"
232
- )
233
- print(
234
- " This may be due to missing LaTeX fonts or Node.js conflicts"
235
- )
228
+ print(f"⚠️ LaTeX rendering failed, falling back to mathtext: {e}")
229
+ print(" This may be due to missing LaTeX fonts or Node.js conflicts")
236
230
 
237
231
  # Enhanced fallback to mathtext with better configuration
238
232
  mpl_config.update(
@@ -271,7 +265,8 @@ def configure_mpl(
271
265
  except Exception:
272
266
  # Search for Arial font files and register them
273
267
  arial_paths = [
274
- f for f in fm.findSystemFonts()
268
+ f
269
+ for f in fm.findSystemFonts()
275
270
  if os.path.basename(f).lower().startswith("arial")
276
271
  ]
277
272
 
@@ -295,7 +290,12 @@ def configure_mpl(
295
290
  {
296
291
  "text.usetex": False,
297
292
  "font.family": "Arial",
298
- "font.sans-serif": ["Arial", "Helvetica", "DejaVu Sans", "Liberation Sans"],
293
+ "font.sans-serif": [
294
+ "Arial",
295
+ "Helvetica",
296
+ "DejaVu Sans",
297
+ "Liberation Sans",
298
+ ],
299
299
  "mathtext.fontset": "dejavusans",
300
300
  "mathtext.default": "regular",
301
301
  }
@@ -306,7 +306,12 @@ def configure_mpl(
306
306
  {
307
307
  "text.usetex": False,
308
308
  "font.family": "sans-serif",
309
- "font.sans-serif": ["Helvetica", "DejaVu Sans", "Liberation Sans", "sans-serif"],
309
+ "font.sans-serif": [
310
+ "Helvetica",
311
+ "DejaVu Sans",
312
+ "Liberation Sans",
313
+ "sans-serif",
314
+ ],
310
315
  "mathtext.fontset": "dejavusans",
311
316
  "mathtext.default": "regular",
312
317
  }
@@ -315,6 +320,7 @@ def configure_mpl(
315
320
  # Warn user about missing Arial using scitex.logging
316
321
  try:
317
322
  from scitex.logging import getLogger
323
+
318
324
  logger = getLogger(__name__)
319
325
  logger.warning(
320
326
  "Arial font not found. Using fallback fonts (Helvetica/DejaVu Sans). "
@@ -323,17 +329,19 @@ def configure_mpl(
323
329
  except ImportError:
324
330
  # Fallback to warnings if scitex.logging not available
325
331
  import warnings
332
+
326
333
  warnings.warn(
327
334
  "Arial font not found on system. Using fallback fonts (Helvetica/DejaVu Sans). "
328
335
  "For publication-quality figures with Arial, install Microsoft Core Fonts: "
329
336
  "sudo apt-get install ttf-mscorefonts-installer && fc-cache -fv",
330
337
  UserWarning,
331
- stacklevel=2
338
+ stacklevel=2,
332
339
  )
333
340
 
334
341
  # Suppress matplotlib's own font warnings
335
342
  import logging
336
- logging.getLogger('matplotlib.font_manager').setLevel(logging.ERROR)
343
+
344
+ logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR)
337
345
 
338
346
  # Set fallback mode to mathtext
339
347
  try:
scitex/plt/utils/_crop.py CHANGED
@@ -54,10 +54,10 @@ def find_content_area(image_path: str) -> Tuple[int, int, int, int]:
54
54
  # Sample background color from corners (more robust than assuming white)
55
55
  h, w = img_array.shape[:2]
56
56
  corners = [
57
- img_array[0, 0], # top-left
58
- img_array[0, w-1], # top-right
59
- img_array[h-1, 0], # bottom-left
60
- img_array[h-1, w-1], # bottom-right
57
+ img_array[0, 0], # top-left
58
+ img_array[0, w - 1], # top-right
59
+ img_array[h - 1, 0], # bottom-left
60
+ img_array[h - 1, w - 1], # bottom-right
61
61
  ]
62
62
  # Use median of corners as background color (robust to one corner having content)
63
63
  bg_color = np.median(corners, axis=0).astype(np.uint8)
@@ -68,7 +68,12 @@ def find_content_area(image_path: str) -> Tuple[int, int, int, int]:
68
68
  else:
69
69
  # Grayscale: detect background from corners
70
70
  h, w = img_array.shape
71
- corners = [img_array[0, 0], img_array[0, w-1], img_array[h-1, 0], img_array[h-1, w-1]]
71
+ corners = [
72
+ img_array[0, 0],
73
+ img_array[0, w - 1],
74
+ img_array[h - 1, 0],
75
+ img_array[h - 1, w - 1],
76
+ ]
72
77
  bg_value = np.median(corners)
73
78
  is_content = np.abs(img_array.astype(np.int16) - bg_value) > 10
74
79
 
@@ -91,6 +96,7 @@ def crop(
91
96
  margin: int = 12,
92
97
  overwrite: bool = False,
93
98
  verbose: bool = False,
99
+ return_offset: bool = False,
94
100
  ) -> str:
95
101
  """
96
102
  Crop a figure image to its content area with a specified margin.
@@ -112,11 +118,16 @@ def crop(
112
118
  Whether to overwrite the input file (default: False)
113
119
  verbose : bool, optional
114
120
  Whether to print detailed information (default: False)
121
+ return_offset : bool, optional
122
+ If True, also return the crop offset (left, upper) for metadata adjustment.
123
+ Default is False.
115
124
 
116
125
  Returns
117
126
  -------
118
- str
119
- Path to the saved cropped image
127
+ str or tuple
128
+ Path to the saved cropped image. If return_offset=True, returns
129
+ (path, offset_dict) where offset_dict has keys 'left', 'upper', 'right', 'lower'
130
+ representing the crop boundaries.
120
131
 
121
132
  Raises
122
133
  ------
@@ -150,14 +161,16 @@ def crop(
150
161
 
151
162
  if verbose:
152
163
  print(f"Original image dimensions: {original_width}x{original_height}")
153
- if 'dpi' in img.info:
164
+ if "dpi" in img.info:
154
165
  print(f"Original DPI: {img.info['dpi']}")
155
166
 
156
167
  # Find the content area (returns left, upper, right, lower)
157
168
  left, upper, right, lower = find_content_area(input_path)
158
169
 
159
170
  if verbose:
160
- print(f"Content area detected at: left={left}, upper={upper}, right={right}, lower={lower}")
171
+ print(
172
+ f"Content area detected at: left={left}, upper={upper}, right={right}, lower={lower}"
173
+ )
161
174
 
162
175
  # Calculate the coordinates with margin, clamping to the image boundaries
163
176
  left = max(left - margin, 0)
@@ -167,7 +180,7 @@ def crop(
167
180
 
168
181
  if verbose:
169
182
  print(f"Cropping to: left={left}, upper={upper}, right={right}, lower={lower}")
170
- print(f"New dimensions: {right-left}x{lower-upper}")
183
+ print(f"New dimensions: {right - left}x{lower - upper}")
171
184
 
172
185
  # Crop the image using PIL (lossless operation)
173
186
  cropped_img = img.crop((left, upper, right, lower))
@@ -176,17 +189,20 @@ def crop(
176
189
  save_kwargs = {}
177
190
 
178
191
  # Preserve DPI if it exists
179
- if 'dpi' in img.info:
180
- save_kwargs['dpi'] = img.info['dpi']
192
+ if "dpi" in img.info:
193
+ save_kwargs["dpi"] = img.info["dpi"]
181
194
 
182
195
  ext = os.path.splitext(output_path)[1].lower()
183
- if ext in ['.png']:
196
+ if ext in [".png"]:
184
197
  # PNG: lossless compression, preserve all metadata including text chunks
185
- save_kwargs['compress_level'] = 0 # No compression for maximum quality and speed
186
- save_kwargs['optimize'] = False
198
+ save_kwargs["compress_level"] = (
199
+ 0 # No compression for maximum quality and speed
200
+ )
201
+ save_kwargs["optimize"] = False
187
202
 
188
203
  # Preserve PNG text chunks (tEXt, zTXt, iTXt) where scitex metadata is stored
189
204
  from PIL import PngImagePlugin
205
+
190
206
  pnginfo = PngImagePlugin.PngInfo()
191
207
 
192
208
  # Copy all text chunks from original image
@@ -197,30 +213,30 @@ def crop(
197
213
  except Exception:
198
214
  pass # Skip if can't add this chunk
199
215
 
200
- save_kwargs['pnginfo'] = pnginfo
201
- elif ext in ['.jpg', '.jpeg']:
216
+ save_kwargs["pnginfo"] = pnginfo
217
+ elif ext in [".jpg", ".jpeg"]:
202
218
  # JPEG: maximum quality for daily use (quality=100, no compression artifacts)
203
- save_kwargs['quality'] = 100
204
- save_kwargs['subsampling'] = 0 # No chroma subsampling (best quality)
205
- save_kwargs['optimize'] = False
219
+ save_kwargs["quality"] = 100
220
+ save_kwargs["subsampling"] = 0 # No chroma subsampling (best quality)
221
+ save_kwargs["optimize"] = False
206
222
 
207
223
  # Preserve EXIF metadata where scitex metadata is stored
208
224
  try:
209
225
  import piexif
210
226
 
211
227
  # Try to load existing EXIF data
212
- if 'exif' in img.info:
228
+ if "exif" in img.info:
213
229
  # piexif.load() reads the EXIF bytes
214
- exif_dict = piexif.load(img.info['exif'])
230
+ exif_dict = piexif.load(img.info["exif"])
215
231
  # Re-dump to bytes for saving
216
232
  exif_bytes = piexif.dump(exif_dict)
217
- save_kwargs['exif'] = exif_bytes
233
+ save_kwargs["exif"] = exif_bytes
218
234
  except ImportError:
219
235
  # piexif not available, try PIL's built-in EXIF
220
- if hasattr(img, 'getexif'):
236
+ if hasattr(img, "getexif"):
221
237
  exif = img.getexif()
222
238
  if exif:
223
- save_kwargs['exif'] = exif
239
+ save_kwargs["exif"] = exif
224
240
  except Exception:
225
241
  # If EXIF reading fails, continue without it
226
242
  pass
@@ -230,16 +246,33 @@ def crop(
230
246
 
231
247
  # Calculate space saved
232
248
  final_width, final_height = cropped_img.size
233
- area_reduction = 1 - ((final_width * final_height) / (original_width * original_height))
249
+ area_reduction = 1 - (
250
+ (final_width * final_height) / (original_width * original_height)
251
+ )
234
252
  area_reduction_pct = area_reduction * 100
235
253
 
236
254
  if verbose:
237
255
  print(f"Image processed: {input_path}")
238
- print(f"Size changed from {original_width}x{original_height} to {final_width}x{final_height}")
256
+ print(
257
+ f"Size changed from {original_width}x{original_height} to {final_width}x{final_height}"
258
+ )
239
259
  print(f"Saved {area_reduction_pct:.1f}% of the original area")
240
260
  if output_path != input_path:
241
261
  print(f"Saved to: {output_path}")
242
262
 
263
+ if return_offset:
264
+ offset = {
265
+ 'left': left,
266
+ 'upper': upper,
267
+ 'right': right,
268
+ 'lower': lower,
269
+ 'original_width': original_width,
270
+ 'original_height': original_height,
271
+ 'new_width': final_width,
272
+ 'new_height': final_height,
273
+ }
274
+ return output_path, offset
275
+
243
276
  return output_path
244
277
 
245
278
 
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: 2025-12-08
4
+ # File: ./src/scitex/plt/utils/_csv_column_naming.py
5
+
6
+ """
7
+ Single source of truth for CSV column naming in scitex.
8
+
9
+ This module ensures consistent column naming between:
10
+ - CSV export (_export_as_csv)
11
+ - JSON metadata (_collect_figure_metadata)
12
+ - GUI editors (reading CSV data back)
13
+
14
+ Column naming convention:
15
+ {domain-name-value}_{domain-name-value}_...
16
+
17
+ - Underscore (_) separates different domains
18
+ - Hyphen (-) within domain name and between name-value
19
+
20
+ Format:
21
+ ax-row-{row}-col-{col}_trace-id-{trace_id}_variable-{variable}
22
+
23
+ Where:
24
+ - ax-row-{row}-col-{col}: axes position in grid
25
+ - trace-id-{id}: unique identifier for the trace, which can be:
26
+ * User-provided id kwarg (e.g., "sine", "my-data")
27
+ * Generated from label (e.g., "sin-x" from "sin(x)")
28
+ * Auto-generated index (e.g., "0", "1")
29
+ - variable-{var}: type of data variable (e.g., "x", "y", "bins", "heights")
30
+
31
+ Examples:
32
+ ax-row-0-col-0_trace-id-sine_variable-x (row 0, col 0, id "sine", x)
33
+ ax-row-0-col-0_trace-id-sine_variable-y (row 0, col 0, id "sine", y)
34
+ ax-row-0-col-1_trace-id-0_variable-x (row 0, col 1, auto id 0, x)
35
+ ax-row-1-col-0_trace-id-my-data_variable-bins (row 1, col 0, "my-data", bins)
36
+ """
37
+
38
+ __all__ = [
39
+ "get_csv_column_name",
40
+ "get_csv_column_prefix",
41
+ "parse_csv_column_name",
42
+ "sanitize_trace_id",
43
+ ]
44
+
45
+
46
+ def sanitize_trace_id(trace_id: str) -> str:
47
+ """Sanitize trace ID for use in CSV column names.
48
+
49
+ Removes or replaces characters that could cause issues in column names.
50
+ Uses hyphen (-) for word separation within values.
51
+
52
+ Parameters
53
+ ----------
54
+ trace_id : str
55
+ Raw trace identifier (label, id kwarg, or generated)
56
+
57
+ Returns
58
+ -------
59
+ str
60
+ Sanitized trace ID safe for CSV column names
61
+
62
+ Examples
63
+ --------
64
+ >>> sanitize_trace_id("sin(x)")
65
+ 'sin-x'
66
+ >>> sanitize_trace_id("My Data")
67
+ 'my-data'
68
+ """
69
+ if not trace_id:
70
+ return "unnamed"
71
+
72
+ # Replace problematic characters with hyphen (word separator within values)
73
+ sanitized = str(trace_id).lower()
74
+ result = []
75
+ for char in sanitized:
76
+ if char.isalnum():
77
+ result.append(char)
78
+ elif char in (" ", "_", "(", ")", "[", "]", "{", "}", "/", "\\", ".", "-"):
79
+ result.append("-")
80
+ # Skip other characters
81
+
82
+ sanitized = "".join(result)
83
+
84
+ # Remove consecutive hyphens
85
+ while "--" in sanitized:
86
+ sanitized = sanitized.replace("--", "-")
87
+
88
+ # Remove leading/trailing hyphens
89
+ sanitized = sanitized.strip("-")
90
+
91
+ return sanitized if sanitized else "unnamed"
92
+
93
+
94
+ def get_csv_column_prefix(
95
+ ax_row: int = 0, ax_col: int = 0, trace_id: str = None, trace_index: int = None
96
+ ) -> str:
97
+ """Get CSV column prefix for a trace.
98
+
99
+ Format: ax-row-{row}-col-{col}_trace-id-{id}_variable-
100
+ - Underscore (_) separates domains
101
+ - Hyphen (-) within domain names and between name-value
102
+
103
+ Parameters
104
+ ----------
105
+ ax_row : int
106
+ Row position of axes in grid (default: 0)
107
+ ax_col : int
108
+ Column position of axes in grid (default: 0)
109
+ trace_id : str, optional
110
+ Trace identifier (from label or id kwarg). If None, uses trace_index.
111
+ trace_index : int, optional
112
+ Index of trace when no trace_id is provided (default: 0)
113
+
114
+ Returns
115
+ -------
116
+ str
117
+ Column prefix like "ax-row-0-col-0_trace-id-sine_variable-"
118
+
119
+ Examples
120
+ --------
121
+ >>> get_csv_column_prefix(trace_id="sine")
122
+ 'ax-row-0-col-0_trace-id-sine_variable-'
123
+ >>> get_csv_column_prefix(ax_row=1, ax_col=2, trace_index=0)
124
+ 'ax-row-1-col-2_trace-id-0_variable-'
125
+ """
126
+ if trace_id:
127
+ safe_id = sanitize_trace_id(trace_id)
128
+ elif trace_index is not None:
129
+ safe_id = str(trace_index)
130
+ else:
131
+ safe_id = "0"
132
+
133
+ return f"ax-row-{ax_row}-col-{ax_col}_trace-id-{safe_id}_variable-"
134
+
135
+
136
+ def get_csv_column_name(
137
+ variable: str,
138
+ ax_row: int = 0,
139
+ ax_col: int = 0,
140
+ trace_id: str = None,
141
+ trace_index: int = None,
142
+ ) -> str:
143
+ """Get full CSV column name for a data field.
144
+
145
+ Format: ax-row-{row}-col-{col}_trace-id-{id}_variable-{var}
146
+ - Underscore (_) separates domains
147
+ - Hyphen (-) within domain names and between name-value
148
+
149
+ Parameters
150
+ ----------
151
+ variable : str
152
+ Variable name (e.g., "x", "y", "bins", "heights")
153
+ ax_row : int
154
+ Row position of axes in grid (default: 0)
155
+ ax_col : int
156
+ Column position of axes in grid (default: 0)
157
+ trace_id : str, optional
158
+ Trace identifier (from label or id kwarg)
159
+ trace_index : int, optional
160
+ Index of trace when no trace_id is provided
161
+
162
+ Returns
163
+ -------
164
+ str
165
+ Full column name like "ax-row-0-col-0_trace-id-sine_variable-x"
166
+
167
+ Examples
168
+ --------
169
+ >>> get_csv_column_name("x", trace_id="sin(x)")
170
+ 'ax-row-0-col-0_trace-id-sin-x_variable-x'
171
+ >>> get_csv_column_name("y", ax_row=1, ax_col=2, trace_index=0)
172
+ 'ax-row-1-col-2_trace-id-0_variable-y'
173
+ """
174
+ prefix = get_csv_column_prefix(ax_row, ax_col, trace_id, trace_index)
175
+ # Variable names are simple (x, y, bins, etc.)
176
+ safe_variable = variable.lower()
177
+ return f"{prefix}{safe_variable}"
178
+
179
+
180
+ def parse_csv_column_name(column_name: str) -> dict:
181
+ """Parse CSV column name to extract components.
182
+
183
+ Format: ax-row-{row}-col-{col}_trace-id-{id}_variable-{var}
184
+ - Underscore (_) separates domains
185
+ - Hyphen (-) within domain names and between name-value
186
+
187
+ Parameters
188
+ ----------
189
+ column_name : str
190
+ Full column name (e.g., "ax-row-0-col-0_trace-id-sine_variable-x")
191
+
192
+ Returns
193
+ -------
194
+ dict
195
+ Dictionary with keys:
196
+ - ax_row: int
197
+ - ax_col: int
198
+ - trace_id: str
199
+ - variable: str
200
+ - valid: bool (True if parsing succeeded)
201
+
202
+ Examples
203
+ --------
204
+ >>> parse_csv_column_name("ax-row-0-col-0_trace-id-sine_variable-x")
205
+ {'ax_row': 0, 'ax_col': 0, 'trace_id': 'sine', 'variable': 'x', 'valid': True}
206
+ >>> parse_csv_column_name("ax-row-1-col-2_trace-id-my-data_variable-bins")
207
+ {'ax_row': 1, 'ax_col': 2, 'trace_id': 'my-data', 'variable': 'bins', 'valid': True}
208
+ """
209
+ result = {
210
+ "ax_row": 0,
211
+ "ax_col": 0,
212
+ "trace_id": "",
213
+ "variable": "",
214
+ "valid": False,
215
+ }
216
+
217
+ if not column_name or not column_name.startswith("ax-row-"):
218
+ return result
219
+
220
+ try:
221
+ # Split by underscore to get domain groups
222
+ parts = column_name.split("_")
223
+ # Expected: ["ax-row-0-col-0", "trace-id-sine", "variable-x"]
224
+
225
+ for part in parts:
226
+ if part.startswith("ax-row-"):
227
+ # Parse ax-row-{row}-col-{col}
228
+ # Remove "ax-row-" prefix and split by "-col-"
229
+ rest = part[7:] # Remove "ax-row-"
230
+ if "-col-" in rest:
231
+ row_str, col_str = rest.split("-col-")
232
+ result["ax_row"] = int(row_str)
233
+ result["ax_col"] = int(col_str)
234
+ elif part.startswith("trace-id-"):
235
+ # Extract trace id (everything after "trace-id-")
236
+ result["trace_id"] = part[9:]
237
+ elif part.startswith("variable-"):
238
+ # Extract variable (everything after "variable-")
239
+ result["variable"] = part[9:]
240
+
241
+ # Validate we got all required fields
242
+ if result["variable"]:
243
+ result["valid"] = True
244
+
245
+ except (ValueError, IndexError):
246
+ pass
247
+
248
+ return result
249
+
250
+
251
+ def get_trace_columns_from_df(
252
+ df, trace_id: str = None, trace_index: int = None, ax_row: int = 0, ax_col: int = 0
253
+ ) -> dict:
254
+ """Find CSV columns for a specific trace in a DataFrame.
255
+
256
+ Parameters
257
+ ----------
258
+ df : pandas.DataFrame
259
+ DataFrame with CSV data
260
+ trace_id : str, optional
261
+ Trace identifier to search for
262
+ trace_index : int, optional
263
+ Trace index to search for (if trace_id not provided)
264
+ ax_row : int
265
+ Row position of axes
266
+ ax_col : int
267
+ Column position of axes
268
+
269
+ Returns
270
+ -------
271
+ dict
272
+ Dictionary mapping variable names to column names, e.g.:
273
+ {'x': 'ax-row-0-col-0_trace-id-sine_variable-x',
274
+ 'y': 'ax-row-0-col-0_trace-id-sine_variable-y'}
275
+ """
276
+ result = {}
277
+ prefix = get_csv_column_prefix(ax_row, ax_col, trace_id, trace_index)
278
+
279
+ for col in df.columns:
280
+ if col.startswith(prefix):
281
+ # Extract variable from column name
282
+ variable = col[len(prefix):]
283
+ result[variable] = col
284
+
285
+ return result
286
+
287
+
288
+ # EOF