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/cli/resource.py
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SciTeX CLI - Resource Commands (System Monitoring)
|
|
4
|
+
|
|
5
|
+
Provides system resource monitoring and specifications.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
|
|
14
|
+
def resource():
|
|
15
|
+
"""
|
|
16
|
+
System resource monitoring
|
|
17
|
+
|
|
18
|
+
\b
|
|
19
|
+
Commands:
|
|
20
|
+
specs Show system specifications
|
|
21
|
+
usage Show current resource usage
|
|
22
|
+
monitor Continuously monitor resource usage
|
|
23
|
+
|
|
24
|
+
\b
|
|
25
|
+
Examples:
|
|
26
|
+
scitex resource specs # Show system specs
|
|
27
|
+
scitex resource usage # Current CPU/memory/GPU usage
|
|
28
|
+
scitex resource monitor --interval 5
|
|
29
|
+
"""
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@resource.command()
|
|
34
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
35
|
+
@click.option(
|
|
36
|
+
"--category",
|
|
37
|
+
"-c",
|
|
38
|
+
multiple=True,
|
|
39
|
+
type=click.Choice(["cpu", "memory", "disk", "network", "gpu", "os", "python"]),
|
|
40
|
+
help="Specific category to show",
|
|
41
|
+
)
|
|
42
|
+
def specs(as_json, category):
|
|
43
|
+
"""
|
|
44
|
+
Show system specifications
|
|
45
|
+
|
|
46
|
+
\b
|
|
47
|
+
Categories:
|
|
48
|
+
cpu - Processor information
|
|
49
|
+
memory - RAM information
|
|
50
|
+
disk - Storage information
|
|
51
|
+
network - Network interfaces
|
|
52
|
+
gpu - GPU/CUDA information
|
|
53
|
+
os - Operating system details
|
|
54
|
+
python - Python environment
|
|
55
|
+
|
|
56
|
+
\b
|
|
57
|
+
Examples:
|
|
58
|
+
scitex resource specs
|
|
59
|
+
scitex resource specs --json
|
|
60
|
+
scitex resource specs --category cpu --category gpu
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
from scitex.resource import get_specs
|
|
64
|
+
|
|
65
|
+
specs_data = get_specs()
|
|
66
|
+
|
|
67
|
+
# Filter categories if specified
|
|
68
|
+
if category:
|
|
69
|
+
category_map = {
|
|
70
|
+
"cpu": "_cpu_info",
|
|
71
|
+
"memory": "_memory_info",
|
|
72
|
+
"disk": "_disk_info",
|
|
73
|
+
"network": "_network_info",
|
|
74
|
+
"gpu": "_supple_nvidia_info",
|
|
75
|
+
"os": "_supple_os_info",
|
|
76
|
+
"python": "_supple_python_info",
|
|
77
|
+
}
|
|
78
|
+
filtered = {}
|
|
79
|
+
for cat in category:
|
|
80
|
+
key = category_map.get(cat, cat)
|
|
81
|
+
if key in specs_data:
|
|
82
|
+
filtered[key] = specs_data[key]
|
|
83
|
+
elif cat in specs_data:
|
|
84
|
+
filtered[cat] = specs_data[cat]
|
|
85
|
+
specs_data = filtered
|
|
86
|
+
|
|
87
|
+
if as_json:
|
|
88
|
+
import json
|
|
89
|
+
|
|
90
|
+
click.echo(json.dumps(specs_data, indent=2, default=str))
|
|
91
|
+
else:
|
|
92
|
+
click.secho("System Specifications", fg="cyan", bold=True)
|
|
93
|
+
click.echo("=" * 50)
|
|
94
|
+
|
|
95
|
+
for section, data in specs_data.items():
|
|
96
|
+
section_name = (
|
|
97
|
+
section.replace("_info", "").replace("_supple_", "").upper()
|
|
98
|
+
)
|
|
99
|
+
click.secho(f"\n{section_name}:", fg="yellow")
|
|
100
|
+
if isinstance(data, dict):
|
|
101
|
+
for key, value in data.items():
|
|
102
|
+
click.echo(f" {key}: {value}")
|
|
103
|
+
else:
|
|
104
|
+
click.echo(f" {data}")
|
|
105
|
+
|
|
106
|
+
except Exception as e:
|
|
107
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
108
|
+
sys.exit(1)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@resource.command()
|
|
112
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
113
|
+
def usage(as_json):
|
|
114
|
+
"""
|
|
115
|
+
Show current resource usage (CPU, memory, GPU)
|
|
116
|
+
|
|
117
|
+
\b
|
|
118
|
+
Examples:
|
|
119
|
+
scitex resource usage
|
|
120
|
+
scitex resource usage --json
|
|
121
|
+
"""
|
|
122
|
+
try:
|
|
123
|
+
from scitex.resource import get_processor_usages
|
|
124
|
+
|
|
125
|
+
usage_data = get_processor_usages()
|
|
126
|
+
|
|
127
|
+
if as_json:
|
|
128
|
+
import json
|
|
129
|
+
|
|
130
|
+
click.echo(json.dumps(usage_data, indent=2, default=str))
|
|
131
|
+
else:
|
|
132
|
+
click.secho("Resource Usage", fg="cyan", bold=True)
|
|
133
|
+
click.echo("=" * 50)
|
|
134
|
+
|
|
135
|
+
# CPU
|
|
136
|
+
cpu = usage_data.get("cpu", {})
|
|
137
|
+
click.secho("\nCPU:", fg="yellow")
|
|
138
|
+
click.echo(f" Usage: {cpu.get('percent', 'N/A')}%")
|
|
139
|
+
click.echo(f" Cores: {cpu.get('count', 'N/A')}")
|
|
140
|
+
|
|
141
|
+
# Memory
|
|
142
|
+
mem = usage_data.get("memory", {})
|
|
143
|
+
click.secho("\nMemory:", fg="yellow")
|
|
144
|
+
click.echo(f" Used: {mem.get('percent', 'N/A')}%")
|
|
145
|
+
click.echo(f" Total: {mem.get('total_gb', 'N/A')} GB")
|
|
146
|
+
click.echo(f" Available: {mem.get('available_gb', 'N/A')} GB")
|
|
147
|
+
|
|
148
|
+
# GPU (if available)
|
|
149
|
+
gpu = usage_data.get("gpu", {})
|
|
150
|
+
if gpu:
|
|
151
|
+
click.secho("\nGPU:", fg="yellow")
|
|
152
|
+
for i, g in enumerate(gpu.get("devices", [])):
|
|
153
|
+
click.echo(f" [{i}] {g.get('name', 'Unknown')}")
|
|
154
|
+
click.echo(
|
|
155
|
+
f" Memory: {g.get('memory_used', 'N/A')} / {g.get('memory_total', 'N/A')} MB"
|
|
156
|
+
)
|
|
157
|
+
click.echo(f" Utilization: {g.get('utilization', 'N/A')}%")
|
|
158
|
+
|
|
159
|
+
except Exception as e:
|
|
160
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
161
|
+
sys.exit(1)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@resource.command()
|
|
165
|
+
@click.option(
|
|
166
|
+
"--interval",
|
|
167
|
+
"-i",
|
|
168
|
+
type=float,
|
|
169
|
+
default=2.0,
|
|
170
|
+
help="Update interval in seconds (default: 2.0)",
|
|
171
|
+
)
|
|
172
|
+
@click.option("--count", "-n", type=int, help="Number of updates (default: continuous)")
|
|
173
|
+
@click.option("--log", "-l", type=click.Path(), help="Log to file")
|
|
174
|
+
def monitor(interval, count, log):
|
|
175
|
+
"""
|
|
176
|
+
Continuously monitor resource usage
|
|
177
|
+
|
|
178
|
+
\b
|
|
179
|
+
Examples:
|
|
180
|
+
scitex resource monitor
|
|
181
|
+
scitex resource monitor --interval 5
|
|
182
|
+
scitex resource monitor --count 10 --log usage.log
|
|
183
|
+
"""
|
|
184
|
+
try:
|
|
185
|
+
import time
|
|
186
|
+
|
|
187
|
+
from scitex.resource import get_processor_usages
|
|
188
|
+
|
|
189
|
+
click.echo(f"Monitoring resources (interval: {interval}s)")
|
|
190
|
+
click.echo("Press Ctrl+C to stop")
|
|
191
|
+
click.echo()
|
|
192
|
+
|
|
193
|
+
log_file = None
|
|
194
|
+
if log:
|
|
195
|
+
log_file = open(log, "w")
|
|
196
|
+
log_file.write("timestamp,cpu_percent,memory_percent,gpu_percent\n")
|
|
197
|
+
|
|
198
|
+
iteration = 0
|
|
199
|
+
try:
|
|
200
|
+
while True:
|
|
201
|
+
if count and iteration >= count:
|
|
202
|
+
break
|
|
203
|
+
|
|
204
|
+
usage_data = get_processor_usages()
|
|
205
|
+
cpu_pct = usage_data.get("cpu", {}).get("percent", 0)
|
|
206
|
+
mem_pct = usage_data.get("memory", {}).get("percent", 0)
|
|
207
|
+
gpu_pct = 0
|
|
208
|
+
gpu_info = usage_data.get("gpu", {})
|
|
209
|
+
if gpu_info and gpu_info.get("devices"):
|
|
210
|
+
gpu_pct = gpu_info["devices"][0].get("utilization", 0)
|
|
211
|
+
|
|
212
|
+
# Display
|
|
213
|
+
from datetime import datetime
|
|
214
|
+
|
|
215
|
+
ts = datetime.now().strftime("%H:%M:%S")
|
|
216
|
+
line = f"[{ts}] CPU: {cpu_pct:5.1f}% MEM: {mem_pct:5.1f}% GPU: {gpu_pct:5.1f}%"
|
|
217
|
+
click.echo(line)
|
|
218
|
+
|
|
219
|
+
# Log
|
|
220
|
+
if log_file:
|
|
221
|
+
log_file.write(f"{ts},{cpu_pct},{mem_pct},{gpu_pct}\n")
|
|
222
|
+
log_file.flush()
|
|
223
|
+
|
|
224
|
+
iteration += 1
|
|
225
|
+
time.sleep(interval)
|
|
226
|
+
|
|
227
|
+
except KeyboardInterrupt:
|
|
228
|
+
click.echo("\nMonitoring stopped")
|
|
229
|
+
finally:
|
|
230
|
+
if log_file:
|
|
231
|
+
log_file.close()
|
|
232
|
+
click.echo(f"Log saved: {log}")
|
|
233
|
+
|
|
234
|
+
except Exception as e:
|
|
235
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
236
|
+
sys.exit(1)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
if __name__ == "__main__":
|
|
240
|
+
resource()
|
scitex/cli/stats.py
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SciTeX CLI - Stats Commands (Statistical Analysis)
|
|
4
|
+
|
|
5
|
+
Provides statistical testing, test recommendation, and result management.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
|
|
15
|
+
def stats():
|
|
16
|
+
"""
|
|
17
|
+
Statistical analysis and testing utilities
|
|
18
|
+
|
|
19
|
+
\b
|
|
20
|
+
Commands:
|
|
21
|
+
recommend Get recommended statistical tests for your data
|
|
22
|
+
describe Compute descriptive statistics
|
|
23
|
+
save Save statistical results to bundle
|
|
24
|
+
load Load statistical results from bundle
|
|
25
|
+
|
|
26
|
+
\b
|
|
27
|
+
Examples:
|
|
28
|
+
scitex stats recommend --n-groups 2 --design between
|
|
29
|
+
scitex stats describe data.csv
|
|
30
|
+
scitex stats save results.json --output analysis.stats
|
|
31
|
+
"""
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@stats.command()
|
|
36
|
+
@click.option(
|
|
37
|
+
"--n-groups", "-n", type=int, required=True, help="Number of groups to compare"
|
|
38
|
+
)
|
|
39
|
+
@click.option(
|
|
40
|
+
"--sample-sizes",
|
|
41
|
+
"-s",
|
|
42
|
+
multiple=True,
|
|
43
|
+
type=int,
|
|
44
|
+
help="Sample size for each group (can specify multiple times)",
|
|
45
|
+
)
|
|
46
|
+
@click.option(
|
|
47
|
+
"--outcome-type",
|
|
48
|
+
"-o",
|
|
49
|
+
type=click.Choice(["continuous", "binary", "ordinal", "count", "time_to_event"]),
|
|
50
|
+
default="continuous",
|
|
51
|
+
help="Type of outcome variable (default: continuous)",
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
"--design",
|
|
55
|
+
"-d",
|
|
56
|
+
type=click.Choice(["between", "within", "mixed"]),
|
|
57
|
+
default="between",
|
|
58
|
+
help="Study design (default: between)",
|
|
59
|
+
)
|
|
60
|
+
@click.option("--paired", is_flag=True, help="Whether measurements are paired")
|
|
61
|
+
@click.option("--has-control", is_flag=True, help="Whether there is a control group")
|
|
62
|
+
@click.option("--n-factors", type=int, default=1, help="Number of factors (default: 1)")
|
|
63
|
+
@click.option(
|
|
64
|
+
"--top-k", "-k", type=int, default=3, help="Number of recommendations (default: 3)"
|
|
65
|
+
)
|
|
66
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
67
|
+
def recommend(
|
|
68
|
+
n_groups,
|
|
69
|
+
sample_sizes,
|
|
70
|
+
outcome_type,
|
|
71
|
+
design,
|
|
72
|
+
paired,
|
|
73
|
+
has_control,
|
|
74
|
+
n_factors,
|
|
75
|
+
top_k,
|
|
76
|
+
as_json,
|
|
77
|
+
):
|
|
78
|
+
"""
|
|
79
|
+
Get recommended statistical tests for your experimental design
|
|
80
|
+
|
|
81
|
+
\b
|
|
82
|
+
Examples:
|
|
83
|
+
# Two-group comparison
|
|
84
|
+
scitex stats recommend --n-groups 2 --sample-sizes 30 --sample-sizes 32
|
|
85
|
+
|
|
86
|
+
# Three-group ANOVA
|
|
87
|
+
scitex stats recommend --n-groups 3 --design between
|
|
88
|
+
|
|
89
|
+
# Paired t-test scenario
|
|
90
|
+
scitex stats recommend --n-groups 2 --paired --design within
|
|
91
|
+
|
|
92
|
+
# Binary outcome (chi-square)
|
|
93
|
+
scitex stats recommend --n-groups 2 --outcome-type binary
|
|
94
|
+
"""
|
|
95
|
+
try:
|
|
96
|
+
from scitex.stats import StatContext, recommend_tests
|
|
97
|
+
|
|
98
|
+
# Build context
|
|
99
|
+
ctx = StatContext(
|
|
100
|
+
n_groups=n_groups,
|
|
101
|
+
sample_sizes=list(sample_sizes) if sample_sizes else [30] * n_groups,
|
|
102
|
+
outcome_type=outcome_type,
|
|
103
|
+
design=design,
|
|
104
|
+
paired=paired,
|
|
105
|
+
has_control_group=has_control,
|
|
106
|
+
n_factors=n_factors,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
tests = recommend_tests(ctx, top_k=top_k)
|
|
110
|
+
|
|
111
|
+
if as_json:
|
|
112
|
+
import json
|
|
113
|
+
|
|
114
|
+
output = {
|
|
115
|
+
"context": {
|
|
116
|
+
"n_groups": n_groups,
|
|
117
|
+
"sample_sizes": list(sample_sizes)
|
|
118
|
+
if sample_sizes
|
|
119
|
+
else [30] * n_groups,
|
|
120
|
+
"outcome_type": outcome_type,
|
|
121
|
+
"design": design,
|
|
122
|
+
"paired": paired,
|
|
123
|
+
"has_control_group": has_control,
|
|
124
|
+
"n_factors": n_factors,
|
|
125
|
+
},
|
|
126
|
+
"recommended_tests": tests,
|
|
127
|
+
}
|
|
128
|
+
click.echo(json.dumps(output, indent=2))
|
|
129
|
+
else:
|
|
130
|
+
click.secho("Recommended Statistical Tests", fg="cyan", bold=True)
|
|
131
|
+
click.echo("=" * 40)
|
|
132
|
+
click.echo("\nContext:")
|
|
133
|
+
click.echo(f" Groups: {n_groups}")
|
|
134
|
+
click.echo(f" Design: {design}")
|
|
135
|
+
click.echo(f" Outcome: {outcome_type}")
|
|
136
|
+
click.echo(f" Paired: {paired}")
|
|
137
|
+
click.echo(f"\nTop {top_k} Recommendations:")
|
|
138
|
+
for i, test in enumerate(tests, 1):
|
|
139
|
+
click.secho(f" {i}. {test}", fg="green")
|
|
140
|
+
|
|
141
|
+
except Exception as e:
|
|
142
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
143
|
+
sys.exit(1)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@stats.command()
|
|
147
|
+
@click.argument("data_path", type=click.Path(exists=True))
|
|
148
|
+
@click.option("--column", "-c", multiple=True, help="Specific column(s) to describe")
|
|
149
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
150
|
+
def describe(data_path, column, as_json):
|
|
151
|
+
"""
|
|
152
|
+
Compute descriptive statistics for data
|
|
153
|
+
|
|
154
|
+
\b
|
|
155
|
+
Examples:
|
|
156
|
+
scitex stats describe data.csv
|
|
157
|
+
scitex stats describe data.csv --column age --column score
|
|
158
|
+
scitex stats describe data.csv --json
|
|
159
|
+
"""
|
|
160
|
+
try:
|
|
161
|
+
import pandas as pd
|
|
162
|
+
|
|
163
|
+
from scitex.stats import describe as describe_data
|
|
164
|
+
|
|
165
|
+
# Load data
|
|
166
|
+
path = Path(data_path)
|
|
167
|
+
if path.suffix == ".csv":
|
|
168
|
+
df = pd.read_csv(path)
|
|
169
|
+
elif path.suffix in (".xls", ".xlsx"):
|
|
170
|
+
df = pd.read_excel(path)
|
|
171
|
+
elif path.suffix == ".json":
|
|
172
|
+
df = pd.read_json(path)
|
|
173
|
+
else:
|
|
174
|
+
click.secho(f"Unsupported file format: {path.suffix}", fg="red", err=True)
|
|
175
|
+
sys.exit(1)
|
|
176
|
+
|
|
177
|
+
# Filter columns if specified
|
|
178
|
+
if column:
|
|
179
|
+
df = df[list(column)]
|
|
180
|
+
|
|
181
|
+
# Get descriptive stats
|
|
182
|
+
result = describe_data(df)
|
|
183
|
+
|
|
184
|
+
if as_json:
|
|
185
|
+
import json
|
|
186
|
+
|
|
187
|
+
# Convert to JSON-serializable format
|
|
188
|
+
if hasattr(result, "to_dict"):
|
|
189
|
+
click.echo(json.dumps(result.to_dict(), indent=2, default=str))
|
|
190
|
+
else:
|
|
191
|
+
click.echo(json.dumps(result, indent=2, default=str))
|
|
192
|
+
else:
|
|
193
|
+
click.secho(f"Descriptive Statistics: {path.name}", fg="cyan", bold=True)
|
|
194
|
+
click.echo("=" * 50)
|
|
195
|
+
click.echo(result)
|
|
196
|
+
|
|
197
|
+
except ImportError:
|
|
198
|
+
click.secho(
|
|
199
|
+
"Error: pandas required. Install: pip install pandas", fg="red", err=True
|
|
200
|
+
)
|
|
201
|
+
sys.exit(1)
|
|
202
|
+
except Exception as e:
|
|
203
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
204
|
+
sys.exit(1)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@stats.command()
|
|
208
|
+
@click.argument("input_path", type=click.Path(exists=True))
|
|
209
|
+
@click.option(
|
|
210
|
+
"--output",
|
|
211
|
+
"-o",
|
|
212
|
+
type=click.Path(),
|
|
213
|
+
required=True,
|
|
214
|
+
help="Output bundle path (.stats)",
|
|
215
|
+
)
|
|
216
|
+
@click.option("--as-zip", is_flag=True, help="Save as ZIP archive")
|
|
217
|
+
def save(input_path, output, as_zip):
|
|
218
|
+
"""
|
|
219
|
+
Save statistical results to a SciTeX bundle
|
|
220
|
+
|
|
221
|
+
\b
|
|
222
|
+
Examples:
|
|
223
|
+
scitex stats save results.json --output analysis.stats
|
|
224
|
+
scitex stats save comparisons.json --output analysis.stats --as-zip
|
|
225
|
+
"""
|
|
226
|
+
try:
|
|
227
|
+
import json
|
|
228
|
+
|
|
229
|
+
from scitex.stats import save_stats
|
|
230
|
+
|
|
231
|
+
# Load input
|
|
232
|
+
with open(input_path) as f:
|
|
233
|
+
data = json.load(f)
|
|
234
|
+
|
|
235
|
+
# Handle different input formats
|
|
236
|
+
if isinstance(data, list):
|
|
237
|
+
comparisons = data
|
|
238
|
+
elif isinstance(data, dict) and "comparisons" in data:
|
|
239
|
+
comparisons = data["comparisons"]
|
|
240
|
+
else:
|
|
241
|
+
comparisons = [data]
|
|
242
|
+
|
|
243
|
+
# Save bundle
|
|
244
|
+
result_path = save_stats(comparisons, output, as_zip=as_zip)
|
|
245
|
+
click.secho(f"Stats bundle saved: {result_path}", fg="green")
|
|
246
|
+
|
|
247
|
+
except Exception as e:
|
|
248
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
249
|
+
sys.exit(1)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@stats.command()
|
|
253
|
+
@click.argument("bundle_path", type=click.Path(exists=True))
|
|
254
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
255
|
+
def load(bundle_path, as_json):
|
|
256
|
+
"""
|
|
257
|
+
Load statistical results from a SciTeX bundle
|
|
258
|
+
|
|
259
|
+
\b
|
|
260
|
+
Examples:
|
|
261
|
+
scitex stats load analysis.stats
|
|
262
|
+
scitex stats load analysis.stats --json
|
|
263
|
+
"""
|
|
264
|
+
try:
|
|
265
|
+
from scitex.stats import load_stats
|
|
266
|
+
|
|
267
|
+
data = load_stats(bundle_path)
|
|
268
|
+
|
|
269
|
+
if as_json:
|
|
270
|
+
import json
|
|
271
|
+
|
|
272
|
+
click.echo(json.dumps(data, indent=2, default=str))
|
|
273
|
+
else:
|
|
274
|
+
click.secho(f"Statistics Bundle: {bundle_path}", fg="cyan", bold=True)
|
|
275
|
+
click.echo("=" * 50)
|
|
276
|
+
|
|
277
|
+
comparisons = data.get("comparisons", [])
|
|
278
|
+
click.echo(f"\nComparisons ({len(comparisons)}):")
|
|
279
|
+
for comp in comparisons:
|
|
280
|
+
name = comp.get("name", "unnamed")
|
|
281
|
+
method = comp.get("method", "unknown")
|
|
282
|
+
p_val = comp.get("p_value", "N/A")
|
|
283
|
+
formatted = comp.get("formatted", "")
|
|
284
|
+
click.echo(f" - {name}: {method}, p={p_val} {formatted}")
|
|
285
|
+
|
|
286
|
+
except Exception as e:
|
|
287
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
288
|
+
sys.exit(1)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
@stats.command()
|
|
292
|
+
def tests():
|
|
293
|
+
"""
|
|
294
|
+
List available statistical tests
|
|
295
|
+
|
|
296
|
+
\b
|
|
297
|
+
Example:
|
|
298
|
+
scitex stats tests
|
|
299
|
+
"""
|
|
300
|
+
try:
|
|
301
|
+
from scitex.stats import TEST_RULES
|
|
302
|
+
|
|
303
|
+
click.secho("Available Statistical Tests", fg="cyan", bold=True)
|
|
304
|
+
click.echo("=" * 50)
|
|
305
|
+
|
|
306
|
+
# Group by category
|
|
307
|
+
categories = {}
|
|
308
|
+
for rule in TEST_RULES:
|
|
309
|
+
cat = getattr(rule, "category", "other")
|
|
310
|
+
if cat not in categories:
|
|
311
|
+
categories[cat] = []
|
|
312
|
+
categories[cat].append(rule.name)
|
|
313
|
+
|
|
314
|
+
for cat, tests_list in sorted(categories.items()):
|
|
315
|
+
click.secho(f"\n{cat.title()}:", fg="yellow")
|
|
316
|
+
for test in sorted(tests_list):
|
|
317
|
+
click.echo(f" - {test}")
|
|
318
|
+
|
|
319
|
+
except Exception as e:
|
|
320
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
321
|
+
sys.exit(1)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
if __name__ == "__main__":
|
|
325
|
+
stats()
|