scitex 2.11.0__py3-none-any.whl → 2.13.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.
- scitex/__main__.py +24 -5
- scitex/__version__.py +1 -1
- scitex/_optional_deps.py +33 -0
- scitex/ai/classification/reporters/_ClassificationReporter.py +1 -1
- scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +2 -2
- scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +2 -2
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +2 -2
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +2 -2
- scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +2 -2
- scitex/ai/classification/timeseries/_normalize_timestamp.py +1 -1
- scitex/ai/metrics/_calc_seizure_prediction_metrics.py +1 -1
- scitex/ai/plt/_plot_feature_importance.py +1 -1
- scitex/ai/plt/_plot_learning_curve.py +1 -1
- scitex/ai/plt/_plot_optuna_study.py +1 -1
- scitex/ai/plt/_plot_pre_rec_curve.py +1 -1
- scitex/ai/plt/_plot_roc_curve.py +1 -1
- scitex/ai/plt/_stx_conf_mat.py +1 -1
- scitex/ai/training/_LearningCurveLogger.py +1 -1
- scitex/audio/mcp_server.py +38 -8
- scitex/browser/automation/CookieHandler.py +1 -1
- scitex/browser/core/BrowserMixin.py +1 -1
- scitex/browser/core/ChromeProfileManager.py +1 -1
- scitex/browser/debugging/_browser_logger.py +1 -1
- scitex/browser/debugging/_highlight_element.py +1 -1
- scitex/browser/debugging/_show_grid.py +1 -1
- scitex/browser/interaction/click_center.py +1 -1
- scitex/browser/interaction/click_with_fallbacks.py +1 -1
- scitex/browser/interaction/close_popups.py +1 -1
- scitex/browser/interaction/fill_with_fallbacks.py +1 -1
- scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +1 -1
- scitex/browser/pdf/detect_chrome_pdf_viewer.py +1 -1
- scitex/browser/stealth/HumanBehavior.py +1 -1
- scitex/browser/stealth/StealthManager.py +1 -1
- scitex/canvas/_mcp_handlers.py +372 -0
- scitex/canvas/_mcp_tool_schemas.py +219 -0
- scitex/canvas/mcp_server.py +151 -0
- scitex/capture/mcp_server.py +41 -12
- scitex/cli/audio.py +233 -0
- scitex/cli/capture.py +307 -0
- scitex/cli/main.py +27 -4
- scitex/cli/repro.py +233 -0
- scitex/cli/resource.py +240 -0
- scitex/cli/stats.py +325 -0
- scitex/cli/template.py +236 -0
- scitex/cli/tex.py +286 -0
- scitex/cli/web.py +11 -12
- scitex/dev/__init__.py +3 -0
- scitex/dev/_pyproject.py +405 -0
- scitex/dev/plt/__init__.py +2 -2
- scitex/dev/plt/mpl/get_dir_ax.py +1 -1
- scitex/dev/plt/mpl/get_signatures.py +1 -1
- scitex/dev/plt/mpl/get_signatures_details.py +1 -1
- scitex/diagram/_mcp_handlers.py +400 -0
- scitex/diagram/_mcp_tool_schemas.py +157 -0
- scitex/diagram/mcp_server.py +151 -0
- scitex/dsp/_demo_sig.py +51 -5
- scitex/dsp/_mne.py +13 -2
- scitex/dsp/_modulation_index.py +15 -3
- scitex/dsp/_pac.py +23 -5
- scitex/dsp/_psd.py +16 -4
- scitex/dsp/_resample.py +24 -4
- scitex/dsp/_transform.py +16 -3
- scitex/dsp/add_noise.py +15 -1
- scitex/dsp/norm.py +17 -2
- scitex/dsp/reference.py +17 -1
- scitex/dsp/utils/_differential_bandpass_filters.py +20 -2
- scitex/dsp/utils/_zero_pad.py +18 -4
- scitex/dt/_normalize_timestamp.py +1 -1
- scitex/git/_session.py +1 -1
- scitex/io/_load_modules/_con.py +12 -1
- scitex/io/_load_modules/_eeg.py +12 -1
- scitex/io/_load_modules/_optuna.py +21 -63
- scitex/io/_load_modules/_torch.py +11 -3
- scitex/io/_save_modules/_optuna_study_as_csv_and_pngs.py +13 -2
- scitex/io/_save_modules/_torch.py +11 -3
- scitex/mcp_server.py +159 -0
- scitex/plt/_mcp_handlers.py +361 -0
- scitex/plt/_mcp_tool_schemas.py +169 -0
- scitex/plt/mcp_server.py +205 -0
- scitex/repro/README_RandomStateManager.md +3 -3
- scitex/repro/_RandomStateManager.py +14 -14
- scitex/repro/_gen_ID.py +1 -1
- scitex/repro/_gen_timestamp.py +1 -1
- scitex/repro/_hash_array.py +4 -4
- scitex/scholar/__main__.py +24 -2
- scitex/scholar/_mcp_handlers.py +685 -0
- scitex/scholar/_mcp_tool_schemas.py +339 -0
- scitex/scholar/docs/template.py +1 -1
- scitex/scholar/examples/07_storage_integration.py +1 -1
- scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +1 -1
- scitex/scholar/impact_factor/jcr/build_database.py +1 -1
- scitex/scholar/mcp_server.py +315 -0
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +1 -1
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +1 -1
- scitex/scholar/pipelines/ScholarPipelineParallel.py +1 -1
- scitex/scholar/pipelines/ScholarPipelineSingle.py +1 -1
- scitex/scholar/storage/PaperIO.py +1 -1
- scitex/session/README.md +4 -4
- scitex/session/__init__.py +1 -1
- scitex/session/_decorator.py +9 -9
- scitex/session/_lifecycle.py +5 -5
- scitex/session/template.py +1 -1
- scitex/stats/__main__.py +281 -0
- scitex/stats/_mcp_handlers.py +1191 -0
- scitex/stats/_mcp_tool_schemas.py +384 -0
- scitex/stats/correct/_correct_bonferroni.py +1 -1
- scitex/stats/correct/_correct_fdr.py +1 -1
- scitex/stats/correct/_correct_fdr_.py +1 -1
- scitex/stats/correct/_correct_holm.py +1 -1
- scitex/stats/correct/_correct_sidak.py +1 -1
- scitex/stats/effect_sizes/_cliffs_delta.py +1 -1
- scitex/stats/effect_sizes/_cohens_d.py +1 -1
- scitex/stats/effect_sizes/_epsilon_squared.py +1 -1
- scitex/stats/effect_sizes/_eta_squared.py +1 -1
- scitex/stats/effect_sizes/_prob_superiority.py +1 -1
- scitex/stats/mcp_server.py +405 -0
- scitex/stats/posthoc/_dunnett.py +1 -1
- scitex/stats/posthoc/_games_howell.py +1 -1
- scitex/stats/posthoc/_tukey_hsd.py +1 -1
- scitex/stats/power/_power.py +1 -1
- scitex/stats/utils/_effect_size.py +1 -1
- scitex/stats/utils/_formatters.py +1 -1
- scitex/stats/utils/_power.py +1 -1
- scitex/template/_mcp_handlers.py +259 -0
- scitex/template/_mcp_tool_schemas.py +112 -0
- scitex/template/mcp_server.py +186 -0
- scitex/utils/_verify_scitex_format.py +2 -2
- scitex/utils/template.py +1 -1
- scitex/web/__init__.py +12 -11
- scitex/web/_scraping.py +26 -265
- scitex/web/download_images.py +316 -0
- scitex/writer/Writer.py +1 -1
- scitex/writer/_clone_writer_project.py +1 -1
- scitex/writer/_validate_tree_structures.py +1 -1
- scitex/writer/dataclasses/config/_WriterConfig.py +1 -1
- scitex/writer/dataclasses/contents/_ManuscriptContents.py +1 -1
- scitex/writer/dataclasses/core/_Document.py +1 -1
- scitex/writer/dataclasses/core/_DocumentSection.py +1 -1
- scitex/writer/dataclasses/results/_CompilationResult.py +1 -1
- scitex/writer/dataclasses/results/_LaTeXIssue.py +1 -1
- scitex/writer/utils/.legacy_git_retry.py +7 -5
- scitex/writer/utils/_parse_latex_logs.py +1 -1
- {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/METADATA +431 -269
- {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/RECORD +147 -118
- scitex-2.13.0.dist-info/entry_points.txt +11 -0
- scitex-2.11.0.dist-info/entry_points.txt +0 -2
- {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/WHEEL +0 -0
- {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/licenses/LICENSE +0 -0
scitex/session/README.md
CHANGED
|
@@ -22,7 +22,7 @@ def main(
|
|
|
22
22
|
CONFIG=scitex.INJECTED,
|
|
23
23
|
plt=scitex.INJECTED,
|
|
24
24
|
COLORS=scitex.INJECTED,
|
|
25
|
-
|
|
25
|
+
rng=scitex.INJECTED,
|
|
26
26
|
):
|
|
27
27
|
"""Args injected by @scitex.session decorator"""
|
|
28
28
|
print(f"Session ID: {CONFIG['ID']}")
|
|
@@ -46,7 +46,7 @@ def main(
|
|
|
46
46
|
CONFIG=scitex.INJECTED,
|
|
47
47
|
plt=scitex.INJECTED,
|
|
48
48
|
COLORS=scitex.INJECTED,
|
|
49
|
-
|
|
49
|
+
rng=scitex.INJECTED,
|
|
50
50
|
):
|
|
51
51
|
"""Args injected by @scitex.session decorator"""
|
|
52
52
|
print(f"Session ID: {CONFIG['ID']}")
|
|
@@ -59,7 +59,7 @@ The decorator automatically injects the following parameters:
|
|
|
59
59
|
- `CONFIG`: Configuration dictionary with session metadata
|
|
60
60
|
- `plt`: Configured matplotlib.pyplot module
|
|
61
61
|
- `COLORS`: Color cycle dictionary
|
|
62
|
-
- `
|
|
62
|
+
- `rng`: RandomStateManager instance
|
|
63
63
|
|
|
64
64
|
Using `scitex.INJECTED` as default values makes it explicit that these parameters are injected by the decorator.
|
|
65
65
|
|
|
@@ -249,4 +249,4 @@ if __name__ == "__main__":
|
|
|
249
249
|
- Automatically fixes seeds for all libraries
|
|
250
250
|
- Reproducible across runs
|
|
251
251
|
|
|
252
|
-
<!-- EOF -->
|
|
252
|
+
<!-- EOF -->
|
scitex/session/__init__.py
CHANGED
|
@@ -22,7 +22,7 @@ Usage:
|
|
|
22
22
|
from scitex import session
|
|
23
23
|
|
|
24
24
|
# Start a session
|
|
25
|
-
CONFIG, sys.stdout, sys.stderr, plt, COLORS,
|
|
25
|
+
CONFIG, sys.stdout, sys.stderr, plt, COLORS, rng = session.start(sys, plt)
|
|
26
26
|
|
|
27
27
|
# Your experiment code here
|
|
28
28
|
|
scitex/session/_decorator.py
CHANGED
|
@@ -79,7 +79,7 @@ def session(
|
|
|
79
79
|
# - CONFIG: Session configuration dict
|
|
80
80
|
# - plt: Matplotlib pyplot (configured for session)
|
|
81
81
|
# - COLORS: Custom Colors
|
|
82
|
-
# -
|
|
82
|
+
# - rng: RandomStateManager (fixes seeds, creates named generators)
|
|
83
83
|
logger.info(f"Session ID: {CONFIG['ID']}")
|
|
84
84
|
logger.info(f"Output directory: {CONFIG['SDIR_RUN']}")
|
|
85
85
|
# ... training code ...
|
|
@@ -100,8 +100,8 @@ def session(
|
|
|
100
100
|
- CONFIG (dict): Session configuration with ID, SDIR, paths, etc.
|
|
101
101
|
- plt (module): matplotlib.pyplot configured with session settings
|
|
102
102
|
- COLORS (CustomColors): Custom Colors for consistent plotting
|
|
103
|
-
-
|
|
104
|
-
and creating named generators via
|
|
103
|
+
- rng (RandomStateManager): Manages reproducibility by fixing global seeds
|
|
104
|
+
and creating named generators via rng("name")
|
|
105
105
|
"""
|
|
106
106
|
|
|
107
107
|
def decorator(func: Callable) -> Callable:
|
|
@@ -163,7 +163,7 @@ def _run_with_session(
|
|
|
163
163
|
# Start session
|
|
164
164
|
import matplotlib.pyplot as plt
|
|
165
165
|
|
|
166
|
-
CONFIG, stdout, stderr, plt, COLORS,
|
|
166
|
+
CONFIG, stdout, stderr, plt, COLORS, rng = start(
|
|
167
167
|
sys=sys_module,
|
|
168
168
|
plt=plt,
|
|
169
169
|
args=cleaned_args,
|
|
@@ -182,7 +182,7 @@ def _run_with_session(
|
|
|
182
182
|
func_globals["CONFIG"] = CONFIG
|
|
183
183
|
func_globals["plt"] = plt
|
|
184
184
|
func_globals["COLORS"] = COLORS
|
|
185
|
-
func_globals["
|
|
185
|
+
func_globals["rng"] = rng
|
|
186
186
|
func_globals["logger"] = script_logger
|
|
187
187
|
|
|
188
188
|
# Log injected globals for user awareness (only in verbose mode)
|
|
@@ -195,7 +195,7 @@ def _run_with_session(
|
|
|
195
195
|
_decorator_logger.info(f" - CONFIG['PID']: {CONFIG['PID']}")
|
|
196
196
|
_decorator_logger.info(" • plt - matplotlib.pyplot (configured for session)")
|
|
197
197
|
_decorator_logger.info(" • COLORS - CustomColors (for consistent plotting)")
|
|
198
|
-
_decorator_logger.info(" •
|
|
198
|
+
_decorator_logger.info(" • rng - RandomStateManager (for reproducibility)")
|
|
199
199
|
_decorator_logger.info(" • logger - SciTeX logger (configured for your script)")
|
|
200
200
|
_decorator_logger.info("=" * 60)
|
|
201
201
|
|
|
@@ -216,7 +216,7 @@ def _run_with_session(
|
|
|
216
216
|
"CONFIG": CONFIG,
|
|
217
217
|
"plt": plt,
|
|
218
218
|
"COLORS": COLORS,
|
|
219
|
-
"
|
|
219
|
+
"rng": rng,
|
|
220
220
|
"logger": script_logger,
|
|
221
221
|
}
|
|
222
222
|
|
|
@@ -419,7 +419,7 @@ Global Variables Injected by @session Decorator:
|
|
|
419
419
|
plt.plot(x, y, color=COLORS.blue)
|
|
420
420
|
plt.plot(x, y, color=COLORS['blue'])
|
|
421
421
|
|
|
422
|
-
|
|
422
|
+
rng (RandomStateManager)
|
|
423
423
|
Manages reproducible randomness
|
|
424
424
|
|
|
425
425
|
logger (SciTeXLogger)
|
|
@@ -596,7 +596,7 @@ def run(func: Callable, parse_args: Callable = None, **session_kwargs) -> Any:
|
|
|
596
596
|
# Start session
|
|
597
597
|
import matplotlib.pyplot as plt
|
|
598
598
|
|
|
599
|
-
CONFIG, stdout, stderr, plt, COLORS,
|
|
599
|
+
CONFIG, stdout, stderr, plt, COLORS, rng = start(
|
|
600
600
|
sys=sys_module,
|
|
601
601
|
plt=plt,
|
|
602
602
|
args=args,
|
scitex/session/_lifecycle.py
CHANGED
|
@@ -411,12 +411,12 @@ def start(
|
|
|
411
411
|
Returns
|
|
412
412
|
-------
|
|
413
413
|
tuple
|
|
414
|
-
(CONFIGS, stdout, stderr, plt, COLORS,
|
|
414
|
+
(CONFIGS, stdout, stderr, plt, COLORS, rng)
|
|
415
415
|
- CONFIGS: Configuration dictionary
|
|
416
416
|
- stdout, stderr: Redirected output streams
|
|
417
417
|
- plt: Configured matplotlib.pyplot module
|
|
418
418
|
- COLORS: Color cycle dictionary
|
|
419
|
-
-
|
|
419
|
+
- rng: Global RandomStateManager instance for reproducible random generation
|
|
420
420
|
"""
|
|
421
421
|
IS_DEBUG = _get_debug_mode()
|
|
422
422
|
ID, PID = _initialize_env(IS_DEBUG)
|
|
@@ -516,7 +516,7 @@ def start(
|
|
|
516
516
|
pass
|
|
517
517
|
|
|
518
518
|
# Initialize RandomStateManager (automatically fixes all seeds)
|
|
519
|
-
|
|
519
|
+
rng = RandomStateManager(seed=seed, verbose=verbose)
|
|
520
520
|
if verbose:
|
|
521
521
|
logger.info(f"Initialized RandomStateManager with seed {seed}")
|
|
522
522
|
|
|
@@ -554,9 +554,9 @@ def start(
|
|
|
554
554
|
|
|
555
555
|
# Return appropriate values based on whether sys was provided
|
|
556
556
|
if sys is not None:
|
|
557
|
-
return CONFIGS, sys.stdout, sys.stderr, plt, COLORS,
|
|
557
|
+
return CONFIGS, sys.stdout, sys.stderr, plt, COLORS, rng
|
|
558
558
|
else:
|
|
559
|
-
return CONFIGS, None, None, plt, COLORS,
|
|
559
|
+
return CONFIGS, None, None, plt, COLORS, rng
|
|
560
560
|
|
|
561
561
|
|
|
562
562
|
def _format_diff_time(diff_time):
|
scitex/session/template.py
CHANGED
scitex/stats/__main__.py
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2026-01-08
|
|
3
|
+
# File: src/scitex/stats/__main__.py
|
|
4
|
+
# ----------------------------------------
|
|
5
|
+
|
|
6
|
+
"""Stats CLI entry point.
|
|
7
|
+
|
|
8
|
+
Subcommand-based interface:
|
|
9
|
+
- recommend: Recommend statistical tests based on data characteristics
|
|
10
|
+
- test: Run a statistical test
|
|
11
|
+
- power: Power analysis and sample size calculation
|
|
12
|
+
- mcp: Start MCP server for LLM integration
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import asyncio
|
|
19
|
+
import json
|
|
20
|
+
import sys
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def create_parser():
|
|
24
|
+
"""Create main argument parser with subcommands."""
|
|
25
|
+
parser = argparse.ArgumentParser(
|
|
26
|
+
prog="python -m scitex.stats",
|
|
27
|
+
description="""
|
|
28
|
+
SciTeX Stats - Statistical Testing Framework
|
|
29
|
+
═══════════════════════════════════════════
|
|
30
|
+
|
|
31
|
+
Subcommand interface:
|
|
32
|
+
recommend - Recommend statistical tests
|
|
33
|
+
test - Run a statistical test
|
|
34
|
+
power - Power analysis
|
|
35
|
+
mcp - Start MCP server for LLM integration
|
|
36
|
+
""",
|
|
37
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
subparsers = parser.add_subparsers(
|
|
41
|
+
dest="command",
|
|
42
|
+
help="Available commands",
|
|
43
|
+
required=True,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# ========================================
|
|
47
|
+
# Subcommand: recommend
|
|
48
|
+
# ========================================
|
|
49
|
+
recommend_parser = subparsers.add_parser(
|
|
50
|
+
"recommend",
|
|
51
|
+
help="Recommend statistical tests",
|
|
52
|
+
description="Recommend appropriate statistical tests based on data characteristics",
|
|
53
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
54
|
+
)
|
|
55
|
+
recommend_parser.add_argument(
|
|
56
|
+
"--n-groups",
|
|
57
|
+
type=int,
|
|
58
|
+
default=2,
|
|
59
|
+
help="Number of groups to compare (default: 2)",
|
|
60
|
+
)
|
|
61
|
+
recommend_parser.add_argument(
|
|
62
|
+
"--sample-sizes",
|
|
63
|
+
type=int,
|
|
64
|
+
nargs="+",
|
|
65
|
+
help="Sample sizes for each group",
|
|
66
|
+
)
|
|
67
|
+
recommend_parser.add_argument(
|
|
68
|
+
"--outcome",
|
|
69
|
+
type=str,
|
|
70
|
+
choices=["continuous", "ordinal", "categorical", "binary"],
|
|
71
|
+
default="continuous",
|
|
72
|
+
help="Outcome variable type (default: continuous)",
|
|
73
|
+
)
|
|
74
|
+
recommend_parser.add_argument(
|
|
75
|
+
"--design",
|
|
76
|
+
type=str,
|
|
77
|
+
choices=["between", "within", "mixed"],
|
|
78
|
+
default="between",
|
|
79
|
+
help="Study design (default: between)",
|
|
80
|
+
)
|
|
81
|
+
recommend_parser.add_argument(
|
|
82
|
+
"--paired",
|
|
83
|
+
action="store_true",
|
|
84
|
+
help="Data is paired/matched",
|
|
85
|
+
)
|
|
86
|
+
recommend_parser.add_argument(
|
|
87
|
+
"--has-control",
|
|
88
|
+
action="store_true",
|
|
89
|
+
help="Has a control group",
|
|
90
|
+
)
|
|
91
|
+
recommend_parser.add_argument(
|
|
92
|
+
"--top-k",
|
|
93
|
+
type=int,
|
|
94
|
+
default=3,
|
|
95
|
+
help="Number of recommendations (default: 3)",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# ========================================
|
|
99
|
+
# Subcommand: test
|
|
100
|
+
# ========================================
|
|
101
|
+
test_parser = subparsers.add_parser(
|
|
102
|
+
"test",
|
|
103
|
+
help="Run a statistical test",
|
|
104
|
+
description="Execute a statistical test on provided data",
|
|
105
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
106
|
+
)
|
|
107
|
+
test_parser.add_argument(
|
|
108
|
+
"test_name",
|
|
109
|
+
type=str,
|
|
110
|
+
help="Name of the test to run",
|
|
111
|
+
)
|
|
112
|
+
test_parser.add_argument(
|
|
113
|
+
"--data",
|
|
114
|
+
type=str,
|
|
115
|
+
help="JSON array of group data, e.g., '[[1,2,3],[4,5,6]]'",
|
|
116
|
+
)
|
|
117
|
+
test_parser.add_argument(
|
|
118
|
+
"--alternative",
|
|
119
|
+
type=str,
|
|
120
|
+
choices=["two-sided", "less", "greater"],
|
|
121
|
+
default="two-sided",
|
|
122
|
+
help="Alternative hypothesis (default: two-sided)",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# ========================================
|
|
126
|
+
# Subcommand: power
|
|
127
|
+
# ========================================
|
|
128
|
+
power_parser = subparsers.add_parser(
|
|
129
|
+
"power",
|
|
130
|
+
help="Power analysis",
|
|
131
|
+
description="Calculate statistical power or required sample size",
|
|
132
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
133
|
+
)
|
|
134
|
+
power_parser.add_argument(
|
|
135
|
+
"--test-type",
|
|
136
|
+
type=str,
|
|
137
|
+
choices=["ttest", "anova", "correlation", "chi2"],
|
|
138
|
+
default="ttest",
|
|
139
|
+
help="Type of statistical test (default: ttest)",
|
|
140
|
+
)
|
|
141
|
+
power_parser.add_argument(
|
|
142
|
+
"--effect-size",
|
|
143
|
+
type=float,
|
|
144
|
+
help="Expected effect size (Cohen's d, f, r, or w)",
|
|
145
|
+
)
|
|
146
|
+
power_parser.add_argument(
|
|
147
|
+
"--n",
|
|
148
|
+
type=int,
|
|
149
|
+
help="Sample size per group (for power calculation)",
|
|
150
|
+
)
|
|
151
|
+
power_parser.add_argument(
|
|
152
|
+
"--power",
|
|
153
|
+
type=float,
|
|
154
|
+
default=0.8,
|
|
155
|
+
help="Desired power (default: 0.8)",
|
|
156
|
+
)
|
|
157
|
+
power_parser.add_argument(
|
|
158
|
+
"--alpha",
|
|
159
|
+
type=float,
|
|
160
|
+
default=0.05,
|
|
161
|
+
help="Significance level (default: 0.05)",
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# ========================================
|
|
165
|
+
# Subcommand: mcp
|
|
166
|
+
# ========================================
|
|
167
|
+
subparsers.add_parser(
|
|
168
|
+
"mcp",
|
|
169
|
+
help="Start MCP server for LLM integration",
|
|
170
|
+
description="Start the MCP (Model Context Protocol) server for Claude/LLM integration",
|
|
171
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
return parser
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def run_recommend(args):
|
|
178
|
+
"""Run test recommendation."""
|
|
179
|
+
from scitex.stats.auto import StatContext, recommend_tests
|
|
180
|
+
from scitex.stats.auto._rules import TEST_RULES
|
|
181
|
+
|
|
182
|
+
ctx = StatContext(
|
|
183
|
+
n_groups=args.n_groups,
|
|
184
|
+
sample_sizes=args.sample_sizes or [30] * args.n_groups,
|
|
185
|
+
outcome_type=args.outcome,
|
|
186
|
+
design=args.design,
|
|
187
|
+
paired=args.paired,
|
|
188
|
+
has_control_group=args.has_control,
|
|
189
|
+
n_factors=1,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
tests = recommend_tests(ctx, top_k=args.top_k)
|
|
193
|
+
|
|
194
|
+
print("\n=== Recommended Statistical Tests ===\n")
|
|
195
|
+
for i, test_name in enumerate(tests, 1):
|
|
196
|
+
rule = TEST_RULES.get(test_name)
|
|
197
|
+
if rule:
|
|
198
|
+
print(f"{i}. {test_name}")
|
|
199
|
+
print(f" Family: {rule.family}")
|
|
200
|
+
print(f" Priority: {rule.priority}")
|
|
201
|
+
if rule.needs_normality:
|
|
202
|
+
print(" Requires: normality assumption")
|
|
203
|
+
if rule.needs_equal_variance:
|
|
204
|
+
print(" Requires: equal variance assumption")
|
|
205
|
+
print()
|
|
206
|
+
|
|
207
|
+
return 0
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def run_test(args):
|
|
211
|
+
"""Run a statistical test."""
|
|
212
|
+
if not args.data:
|
|
213
|
+
print("Error: --data is required")
|
|
214
|
+
return 1
|
|
215
|
+
|
|
216
|
+
data = json.loads(args.data)
|
|
217
|
+
|
|
218
|
+
from scitex.stats._mcp_handlers import run_test_handler
|
|
219
|
+
|
|
220
|
+
result = asyncio.run(
|
|
221
|
+
run_test_handler(
|
|
222
|
+
test_name=args.test_name,
|
|
223
|
+
data=data,
|
|
224
|
+
alternative=args.alternative,
|
|
225
|
+
)
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
print(json.dumps(result, indent=2))
|
|
229
|
+
return 0 if result.get("success") else 1
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def run_power(args):
|
|
233
|
+
"""Run power analysis."""
|
|
234
|
+
from scitex.stats._mcp_handlers import power_analysis_handler
|
|
235
|
+
|
|
236
|
+
result = asyncio.run(
|
|
237
|
+
power_analysis_handler(
|
|
238
|
+
test_type=args.test_type,
|
|
239
|
+
effect_size=args.effect_size,
|
|
240
|
+
n=args.n,
|
|
241
|
+
power=args.power,
|
|
242
|
+
alpha=args.alpha,
|
|
243
|
+
)
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
print(json.dumps(result, indent=2))
|
|
247
|
+
return 0 if result.get("success") else 1
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
async def run_mcp_server():
|
|
251
|
+
"""Run MCP server."""
|
|
252
|
+
from .mcp_server import main as mcp_main
|
|
253
|
+
|
|
254
|
+
print("Starting Stats MCP server...", file=sys.stderr)
|
|
255
|
+
await mcp_main()
|
|
256
|
+
return 0
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def main():
|
|
260
|
+
"""Main entry point."""
|
|
261
|
+
parser = create_parser()
|
|
262
|
+
args = parser.parse_args()
|
|
263
|
+
|
|
264
|
+
if args.command == "recommend":
|
|
265
|
+
return run_recommend(args)
|
|
266
|
+
elif args.command == "test":
|
|
267
|
+
return run_test(args)
|
|
268
|
+
elif args.command == "power":
|
|
269
|
+
return run_power(args)
|
|
270
|
+
elif args.command == "mcp":
|
|
271
|
+
return asyncio.run(run_mcp_server())
|
|
272
|
+
else:
|
|
273
|
+
print(f"Unknown command: {args.command}")
|
|
274
|
+
return 1
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
if __name__ == "__main__":
|
|
278
|
+
sys.exit(main())
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
# EOF
|