Skip to content

Commit 995e512

Browse files
committed
Add meta command, to run meta-analyses
1 parent ecf7a4c commit 995e512

4 files changed

Lines changed: 338 additions & 10 deletions

File tree

autonima/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
# Import LLM module components
3434
from .llm.client import GenericLLMClient
3535

36+
# Import meta-analysis module components
37+
from .meta import run_meta_analyses
38+
3639
__all__ = [
3740
"AutonimaPipeline",
3841
"PipelineConfig",
@@ -44,5 +47,6 @@
4447
"ParseAnalysesOutput",
4548
"parse_tables",
4649
"CoordinateParsingClient",
47-
"GenericLLMClient"
50+
"GenericLLMClient",
51+
"run_meta_analyses"
4852
]

autonima/cli.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,85 @@ def validate(config: str, output_folder: str, debug: bool):
216216
sys.exit(1)
217217

218218

219+
@click.command()
220+
@click.argument('output_folder', type=click.Path(exists=True))
221+
@click.option('--estimator',
222+
type=click.Choice(['ale', 'mkdadensity', 'kda']),
223+
default='mkdadensity',
224+
help='CBMA estimator to use (default: mkdadensity)')
225+
@click.option('--estimator-args',
226+
type=str,
227+
default='{}',
228+
help='JSON string of arguments for the estimator (default: {})')
229+
@click.option('--corrector',
230+
type=click.Choice(['fdr', 'montecarlo', 'bonferroni']),
231+
default='fdr',
232+
help='Corrector to use (default: fdr)')
233+
@click.option('--corrector-args',
234+
type=str,
235+
default='{}',
236+
help='JSON string of arguments for the corrector (default: {})')
237+
@click.option('--debug', is_flag=True,
238+
help='Enable debug mode with post-mortem debugging on errors')
239+
def meta(output_folder: str, estimator: str, estimator_args: str,
240+
corrector: str, corrector_args: str, debug: bool):
241+
"""
242+
Run meta-analyses on Autonima output using NiMARE.
243+
244+
This command runs coordinate-based meta-analyses on the results
245+
from an Autonima systematic review pipeline.
246+
247+
Arguments:
248+
OUTPUT_FOLDER Output folder containing NiMADS files
249+
250+
Options:
251+
--estimator CBMA estimator to use (ale, mkdadensity, kda)
252+
--estimator-args JSON string of arguments for the estimator
253+
--corrector Corrector to use (fdr, montecarlo, bonferroni)
254+
--corrector-args JSON string of arguments for the corrector
255+
256+
Examples:
257+
autonima meta results/outputs
258+
autonima meta results/outputs --estimator ale --corrector montecarlo
259+
autonima meta results/outputs --estimator-args '{"n_iters": 1000}' --corrector-args '{"alpha": 0.01}'
260+
"""
261+
try:
262+
import json
263+
from pathlib import Path
264+
265+
# Parse estimator and corrector arguments
266+
try:
267+
estimator_args_dict = json.loads(estimator_args)
268+
corrector_args_dict = json.loads(corrector_args)
269+
except json.JSONDecodeError as e:
270+
log_error_with_debug(logger, f"Error parsing JSON arguments: {e}")
271+
if debug:
272+
import pdb
273+
pdb.post_mortem()
274+
sys.exit(1)
275+
276+
# Import the meta-analysis function
277+
from .meta import run_meta_analyses
278+
279+
# Run meta-analyses
280+
results = run_meta_analyses(
281+
output_folder,
282+
estimator_name=estimator,
283+
estimator_args=estimator_args_dict,
284+
corrector_name=corrector,
285+
corrector_args=corrector_args_dict
286+
)
287+
288+
print(f"Completed meta-analyses for {len(results)} columns")
289+
290+
except Exception as e:
291+
log_error_with_debug(logger, f"Meta-analysis execution failed: {e}")
292+
if debug:
293+
import pdb
294+
pdb.post_mortem()
295+
sys.exit(1)
296+
297+
219298
@click.command()
220299
def create_sample_config():
221300
"""
@@ -261,6 +340,7 @@ def cli():
261340
cli.add_command(run)
262341
cli.add_command(validate)
263342
cli.add_command(create_sample_config)
343+
cli.add_command(meta)
264344

265345

266346
def main():

autonima/coordinates/nimads_models.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ class Point:
2828
label_id: Optional[str] = None
2929
values: List[PointValue] = field(default_factory=list)
3030
analysis_id: Optional[str] = None
31+
id: Optional[str] = None
3132

3233
def to_dict(self) -> dict:
3334
"""Convert to dictionary representation."""
3435
return {
36+
"id": self.id,
3537
"coordinates": self.coordinates,
3638
"space": self.space,
3739
"kind": self.kind,
@@ -155,7 +157,7 @@ def to_dict(self) -> dict:
155157
}
156158

157159

158-
def convert_to_nimads_point(analysis_id: str, point: CoordinatePoint, study_space: Optional[str] = None) -> Point:
160+
def convert_to_nimads_point(analysis_id: str, point: CoordinatePoint, study_space: Optional[str] = None, point_id: Optional[str] = None) -> Point:
159161
"""Convert a coordinate point to a NiMADS point."""
160162
# Sanitize the coordinate space
161163
sanitized_space = sanitize_coordinate_space(point.space, study_space)
@@ -166,7 +168,8 @@ def convert_to_nimads_point(analysis_id: str, point: CoordinatePoint, study_spac
166168
nimads_point = Point(
167169
coordinates=sanitized_coordinates,
168170
space=sanitized_space,
169-
analysis_id=analysis_id
171+
analysis_id=analysis_id,
172+
id=point_id
170173
)
171174

172175
# Convert point values if they exist
@@ -193,8 +196,9 @@ def convert_to_nimads_analysis(analysis_id: str, analysis: Analysis, study_id: s
193196
)
194197

195198
# Convert points
196-
for point in analysis.points:
197-
nimads_point = convert_to_nimads_point(analysis_id, point, study_space)
199+
for i, point in enumerate(analysis.points):
200+
point_id = f"{analysis_id}_point_{i}"
201+
nimads_point = convert_to_nimads_point(analysis_id, point, study_space, point_id)
198202
nimads_analysis.points.append(nimads_point)
199203

200204
return nimads_analysis
@@ -211,8 +215,11 @@ def convert_to_nimads_study(study_id: str, autonima_study: 'autonima.models.type
211215
except (ValueError, IndexError):
212216
pass
213217

218+
# Use the study's PMID as the study_id if available
219+
nimads_study_id = autonima_study.pmid if autonima_study.pmid else study_id
220+
214221
nimads_study = Study(
215-
id=study_id,
222+
id=nimads_study_id,
216223
doi=autonima_study.doi,
217224
name=autonima_study.title,
218225
description=autonima_study.abstract,
@@ -227,8 +234,8 @@ def convert_to_nimads_study(study_id: str, autonima_study: 'autonima.models.type
227234

228235
# Convert analyses
229236
for i, analysis in enumerate(autonima_study.analyses):
230-
analysis_id = f"{study_id}_analysis_{i}"
231-
nimads_analysis = convert_to_nimads_analysis(analysis_id, analysis, study_id, study_space)
237+
analysis_id = f"{nimads_study_id}_analysis_{i}"
238+
nimads_analysis = convert_to_nimads_analysis(analysis_id, analysis, nimads_study_id, study_space)
232239
nimads_study.analyses.append(nimads_analysis)
233240

234241
return nimads_study
@@ -282,8 +289,9 @@ def convert_to_nimads_studyset(studyset_id: str, studies: List['autonima.models.
282289
)
283290

284291
# Convert studies
285-
for i, study in enumerate(studies):
286-
study_id = f"study_{i}"
292+
for study in studies:
293+
# Use the study's PMID as the study_id if available, otherwise generate one
294+
study_id = study.pmid if study.pmid else f"study_{len(studyset.studies)}"
287295
nimads_study = convert_to_nimads_study(study_id, study)
288296
studyset.studies.append(nimads_study)
289297

0 commit comments

Comments
 (0)