Coverage for nilearn/datasets/struct.py: 18%

207 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-20 10:58 +0200

1"""Downloading NeuroImaging datasets: structural datasets.""" 

2 

3import functools 

4import warnings 

5from pathlib import Path 

6 

7import numpy as np 

8import pandas as pd 

9from scipy.ndimage import binary_closing 

10from sklearn.utils import Bunch 

11 

12from nilearn._utils import check_niimg, fill_doc 

13from nilearn._utils.logger import find_stack_level 

14from nilearn._utils.param_validation import check_params 

15from nilearn.datasets._utils import ( 

16 ALLOWED_DATA_TYPES, 

17 ALLOWED_MESH_TYPES, 

18 PACKAGE_DIRECTORY, 

19 fetch_files, 

20 get_dataset_descr, 

21 get_dataset_dir, 

22) 

23from nilearn.image import get_data, new_img_like, resampling 

24from nilearn.surface import ( 

25 FileMesh, 

26 PolyMesh, 

27 SurfaceImage, 

28) 

29 

30MNI152_FILE_PATH = ( 

31 PACKAGE_DIRECTORY 

32 / "data" 

33 / "mni_icbm152_t1_tal_nlin_sym_09a_converted.nii.gz" 

34) 

35GM_MNI152_FILE_PATH = ( 

36 PACKAGE_DIRECTORY 

37 / "data" 

38 / "mni_icbm152_gm_tal_nlin_sym_09a_converted.nii.gz" 

39) 

40WM_MNI152_FILE_PATH = ( 

41 PACKAGE_DIRECTORY 

42 / "data" 

43 / "mni_icbm152_wm_tal_nlin_sym_09a_converted.nii.gz" 

44) 

45FSAVERAGE5_PATH = PACKAGE_DIRECTORY / "data" / "fsaverage5" 

46 

47 

48@fill_doc 

49def fetch_icbm152_2009(data_dir=None, url=None, resume=True, verbose=1): 

50 """Download and load the ICBM152 template (dated 2009). 

51 

52 %(templateflow)s 

53 

54 Parameters 

55 ---------- 

56 %(data_dir)s 

57 %(url)s 

58 %(resume)s 

59 %(verbose)s 

60 

61 Returns 

62 ------- 

63 data : :obj:`sklearn.utils.Bunch` 

64 Dictionary-like object, interest keys are: 

65 

66 - "t1": str, 

67 Path to T1-weighted anatomical image 

68 - "t2": str, 

69 Path to T2-weighted anatomical image 

70 - "t2_relax": str, 

71 Path to anatomical image obtained with the T2 relaxometry 

72 - "pd": str, 

73 Path to the proton density weighted anatomical image 

74 - "gm": str, 

75 Path to gray matter segmented image 

76 - "wm": str, 

77 Path to white matter segmented image 

78 - "csf": str, 

79 Path to cerebrospinal fluid segmented image 

80 - "eye_mask": str, 

81 Path to eye mask useful to mask out part of MRI images 

82 - "face_mask": str, 

83 Path to face mask useful to mask out part of MRI images 

84 - "mask": str, 

85 Path to whole brain mask useful to mask out skull areas 

86 

87 See Also 

88 -------- 

89 nilearn.datasets.load_mni152_template: to load MNI152 T1 template. 

90 

91 nilearn.datasets.load_mni152_gm_template: to load MNI152 gray matter 

92 template. 

93 

94 nilearn.datasets.load_mni152_wm_template: to load MNI152 white matter 

95 template. 

96 

97 nilearn.datasets.load_mni152_brain_mask: to load MNI152 whole brain mask. 

98 

99 nilearn.datasets.load_mni152_gm_mask: to load MNI152 gray matter mask. 

100 

101 nilearn.datasets.load_mni152_wm_mask: to load MNI152 white matter mask. 

102 

103 nilearn.datasets.fetch_icbm152_brain_gm_mask: to fetch only ICBM gray 

104 matter mask. 

105 

106 Notes 

107 ----- 

108 For more information 

109 see the :ref:`dataset description <icbm_152_template>`. 

110 

111 """ 

112 check_params(locals()) 

113 

114 if url is None: 

115 # The URL can be retrieved from the nilearn account on OSF (Open 

116 # Science Framework), https://osf.io/4r3jt/quickfiles/ 

117 # Clicking on the "share" button gives the root of the URL. 

118 url = "https://osf.io/7pj92/download" 

119 opts = {"uncompress": True} 

120 

121 keys = ( 

122 "csf", 

123 "gm", 

124 "wm", 

125 "pd", 

126 "t1", 

127 "t2", 

128 "t2_relax", 

129 "eye_mask", 

130 "face_mask", 

131 "mask", 

132 ) 

133 filenames = [ 

134 (Path("mni_icbm152_nlin_sym_09a", name), url, opts) 

135 for name in ( 

136 "mni_icbm152_csf_tal_nlin_sym_09a.nii.gz", 

137 "mni_icbm152_gm_tal_nlin_sym_09a.nii.gz", 

138 "mni_icbm152_wm_tal_nlin_sym_09a.nii.gz", 

139 "mni_icbm152_pd_tal_nlin_sym_09a.nii.gz", 

140 "mni_icbm152_t1_tal_nlin_sym_09a.nii.gz", 

141 "mni_icbm152_t2_tal_nlin_sym_09a.nii.gz", 

142 "mni_icbm152_t2_relx_tal_nlin_sym_09a.nii.gz", 

143 "mni_icbm152_t1_tal_nlin_sym_09a_eye_mask.nii.gz", 

144 "mni_icbm152_t1_tal_nlin_sym_09a_face_mask.nii.gz", 

145 "mni_icbm152_t1_tal_nlin_sym_09a_mask.nii.gz", 

146 ) 

147 ] 

148 

149 dataset_name = "icbm152_2009" 

150 data_dir = get_dataset_dir( 

151 dataset_name, data_dir=data_dir, verbose=verbose 

152 ) 

153 sub_files = fetch_files( 

154 data_dir, filenames, resume=resume, verbose=verbose 

155 ) 

156 

157 fdescr = get_dataset_descr(dataset_name) 

158 

159 params = dict([("description", fdescr), *list(zip(keys, sub_files))]) 

160 return Bunch(**params) 

161 

162 

163@functools.lru_cache(maxsize=3) 

164@fill_doc 

165def load_mni152_template(resolution=None): 

166 """Load the MNI152 skullstripped T1 template. 

167 

168 This function takes the skullstripped, 

169 re-scaled 1mm-resolution version of the :term:`MNI` ICBM152 T1 template 

170 and re-samples it using a different resolution, if specified. 

171 

172 %(templateflow)s 

173 

174 Parameters 

175 ---------- 

176 %(resolution)s 

177 

178 .. versionadded:: 0.8.1 

179 

180 Returns 

181 ------- 

182 mni152_template : Nifti1Image, image representing the re-sampled 

183 whole-brain template 

184 

185 See Also 

186 -------- 

187 nilearn.datasets.fetch_icbm152_2009: for details regarding the difference 

188 between NiLearn and :term:`fMRIPrep` ICBM152 template. 

189 

190 nilearn.datasets.load_mni152_gm_template : for details about version of the 

191 MNI152 grey-matter template. 

192 

193 nilearn.datasets.load_mni152_wm_template : for details about version of the 

194 MNI152 white-matter template. 

195 

196 Notes 

197 ----- 

198 For more information 

199 see the :ref:`dataset description <icbm_152_template>`. 

200 

201 """ 

202 resolution = resolution or 1 

203 

204 brain_template = check_niimg(MNI152_FILE_PATH) 

205 

206 # Typecasting 

207 brain_data = get_data(brain_template).astype("float32") 

208 

209 # Re-scale template from 0 to 1 

210 brain_data /= brain_data.max() 

211 new_brain_template = new_img_like(brain_template, brain_data) 

212 

213 # Resample template according to the pre-specified resolution, if different 

214 # than 1 

215 if resolution != 1: 

216 # TODO switch to force_resample=True 

217 # when bumping to version > 0.13 

218 new_brain_template = resampling.resample_img( 

219 new_brain_template, 

220 np.eye(3) * resolution, 

221 copy_header=True, 

222 force_resample=False, 

223 ) 

224 

225 return new_brain_template 

226 

227 

228@fill_doc 

229def load_mni152_gm_template(resolution=None): 

230 """Load the MNI152 grey-matter template. 

231 

232 This function takes the re-scaled 1mm-resolution version of the grey-matter 

233 MNI ICBM152 template and re-samples it using a different resolution, 

234 if specified. 

235 

236 %(templateflow)s 

237 

238 .. versionadded:: 0.8.1 

239 

240 Parameters 

241 ---------- 

242 %(resolution)s 

243 

244 Returns 

245 ------- 

246 gm_mni152_template : Nifti1Image, image representing the resampled 

247 grey-matter template 

248 

249 See Also 

250 -------- 

251 nilearn.datasets.load_mni152_template : for details about version of the 

252 MNI152 T1 template. 

253 

254 nilearn.datasets.load_mni152_wm_template : for details about version of the 

255 MNI152 white-matter template. 

256 

257 Notes 

258 ----- 

259 For more information 

260 see the :ref:`dataset description <icbm_152_template>`. 

261 

262 """ 

263 resolution = resolution or 1 

264 

265 gm_template = check_niimg(GM_MNI152_FILE_PATH) 

266 

267 # Typecasting 

268 gm_data = get_data(gm_template).astype("float32") 

269 

270 # Re-scale template from 0 to 1 

271 gm_data /= gm_data.max() 

272 new_gm_template = new_img_like(gm_template, gm_data) 

273 

274 # Resample template according to the pre-specified resolution, if different 

275 # than 1 

276 if resolution != 1: 

277 # TODO switch to force_resample=True 

278 # when bumping to version > 0.13 

279 new_gm_template = resampling.resample_img( 

280 new_gm_template, 

281 np.eye(3) * resolution, 

282 copy_header=True, 

283 force_resample=False, 

284 ) 

285 

286 return new_gm_template 

287 

288 

289@fill_doc 

290def load_mni152_wm_template(resolution=None): 

291 """Load the MNI152 white-matter template. 

292 

293 This function takes the re-scaled 1mm-resolution version of the 

294 white-matter :term:`MNI` ICBM152 template 

295 and re-samples it using a different 

296 resolution, if specified. 

297 

298 %(templateflow)s 

299 

300 .. versionadded:: 0.8.1 

301 

302 Parameters 

303 ---------- 

304 %(resolution)s 

305 

306 Returns 

307 ------- 

308 wm_mni152_template : Nifti1Image, image representing the resampled 

309 white-matter template 

310 

311 See Also 

312 -------- 

313 nilearn.datasets.load_mni152_template : for details about version of the 

314 MNI152 T1 template. 

315 

316 nilearn.datasets.load_mni152_gm_template : for details about version of the 

317 MNI152 grey-matter template. 

318 

319 Notes 

320 ----- 

321 For more information 

322 see the :ref:`dataset description <icbm_152_template>`. 

323 

324 """ 

325 resolution = resolution or 1 

326 

327 wm_template = check_niimg(WM_MNI152_FILE_PATH) 

328 

329 # Typecasting 

330 wm_data = get_data(wm_template).astype("float32") 

331 

332 # Re-scale template from 0 to 1 

333 wm_data /= wm_data.max() 

334 new_wm_template = new_img_like(wm_template, wm_data) 

335 

336 # Resample template according to the pre-specified resolution, if different 

337 # than 1 

338 if resolution != 1: 

339 # TODO switch to force_resample=True 

340 # when bumping to version > 0.13 

341 new_wm_template = resampling.resample_img( 

342 new_wm_template, 

343 np.eye(3) * resolution, 

344 copy_header=True, 

345 force_resample=False, 

346 ) 

347 

348 return new_wm_template 

349 

350 

351@fill_doc 

352def load_mni152_brain_mask(resolution=None, threshold=0.2): 

353 """Load the MNI152 whole-brain mask. 

354 

355 This function takes the whole-brain MNI152 T1 template and threshold it, 

356 in order to obtain the corresponding whole-brain mask. 

357 

358 %(templateflow)s 

359 

360 .. versionadded:: 0.2.5 

361 

362 Parameters 

363 ---------- 

364 %(resolution)s 

365 

366 .. versionadded:: 0.8.1 

367 

368 threshold : :obj:`float`, default=0.2 

369 Values of the MNI152 T1 template above this threshold will be included. 

370 

371 Returns 

372 ------- 

373 mask_img : Nifti1Image, image corresponding to the whole-brain mask. 

374 

375 See Also 

376 -------- 

377 nilearn.datasets.load_mni152_template : for details about version of the 

378 MNI152 T1 template and related. 

379 

380 Notes 

381 ----- 

382 For more information 

383 see the :ref:`dataset description <icbm_152_template>`. 

384 

385 """ 

386 resolution = resolution or 1 

387 

388 # Load MNI template 

389 target_img = load_mni152_template(resolution=resolution) 

390 mask_voxels = (get_data(target_img) > threshold).astype("int8") 

391 mask_img = new_img_like(target_img, mask_voxels) 

392 

393 return mask_img 

394 

395 

396@fill_doc 

397def load_mni152_gm_mask(resolution=None, threshold=0.2, n_iter=2): 

398 """Load the MNI152 grey-matter mask. 

399 

400 This function takes the grey-matter MNI152 template and threshold it, in 

401 order to obtain the corresponding grey-matter mask. 

402 

403 %(templateflow)s 

404 

405 .. versionadded:: 0.8.1 

406 

407 Parameters 

408 ---------- 

409 %(resolution)s 

410 

411 threshold : :obj:`float`, default=0.2 

412 Values of the grey-matter MNI152 template above this threshold will be 

413 included. 

414 

415 n_iter : :obj:`int`, default=2 

416 Number of repetitions of :term:`dilation<Dilation>` 

417 and :term:`erosion<Erosion>` steps performed in 

418 scipy.ndimage.binary_closing function. 

419 

420 Returns 

421 ------- 

422 gm_mask_img : Nifti1Image, image corresponding to the grey-matter mask. 

423 

424 See Also 

425 -------- 

426 nilearn.datasets.load_mni152_gm_template : for details about version of the 

427 MNI152 grey-matter template and related. 

428 

429 Notes 

430 ----- 

431 For more information 

432 see the :ref:`dataset description <icbm_152_template>`. 

433 

434 """ 

435 resolution = resolution or 1 

436 

437 # Load MNI template 

438 gm_target = load_mni152_gm_template(resolution=resolution) 

439 gm_target_img = check_niimg(gm_target) 

440 gm_target_data = get_data(gm_target_img) 

441 

442 gm_target_mask = (gm_target_data > threshold).astype("int8") 

443 

444 gm_target_mask = binary_closing(gm_target_mask, iterations=n_iter) 

445 gm_mask_img = new_img_like(gm_target_img, gm_target_mask) 

446 

447 return gm_mask_img 

448 

449 

450@fill_doc 

451def load_mni152_wm_mask(resolution=None, threshold=0.2, n_iter=2): 

452 """Load the MNI152 white-matter mask. 

453 

454 This function takes the white-matter MNI152 template and threshold it, in 

455 order to obtain the corresponding white-matter mask. 

456 

457 %(templateflow)s 

458 

459 .. versionadded:: 0.8.1 

460 

461 Parameters 

462 ---------- 

463 %(resolution)s 

464 

465 threshold : :obj:`float`, default=0.2 

466 Values of the white-matter MNI152 template above this threshold will be 

467 included. 

468 

469 n_iter : :obj:`int`, default=2 

470 Number of repetitions of :term:`dilation<Dilation>` 

471 and :term:`erosion<Erosion>` steps performed in 

472 scipy.ndimage.binary_closing function. 

473 

474 Returns 

475 ------- 

476 wm_mask_img : Nifti1Image, image corresponding to the white-matter mask. 

477 

478 See Also 

479 -------- 

480 nilearn.datasets.load_mni152_wm_template : for details about version of the 

481 MNI152 white-matter template and related. 

482 

483 Notes 

484 ----- 

485 For more information 

486 see the :ref:`dataset description <icbm_152_template>`. 

487 

488 """ 

489 resolution = resolution or 1 

490 

491 # Load MNI template 

492 wm_target = load_mni152_wm_template(resolution=resolution) 

493 wm_target_img = check_niimg(wm_target) 

494 wm_target_data = get_data(wm_target_img) 

495 

496 wm_target_mask = (wm_target_data > threshold).astype("int8") 

497 

498 wm_target_mask = binary_closing(wm_target_mask, iterations=n_iter) 

499 wm_mask_img = new_img_like(wm_target_img, wm_target_mask) 

500 

501 return wm_mask_img 

502 

503 

504@fill_doc 

505def fetch_icbm152_brain_gm_mask( 

506 data_dir=None, threshold=0.2, resume=True, n_iter=2, verbose=1 

507): 

508 """Download ICBM152 template first, then loads the 'gm' mask. 

509 

510 %(templateflow)s 

511 

512 .. versionadded:: 0.2.5 

513 

514 Parameters 

515 ---------- 

516 %(data_dir)s 

517 

518 threshold : :obj:`float`, default=0.2 

519 Values of the ICBM152 grey-matter template above this threshold will be 

520 included. 

521 

522 %(resume)s 

523 

524 n_iter : :obj:`int`, default=2 

525 Number of repetitions of :term:`dilation<Dilation>` 

526 and :term:`erosion<Erosion>` steps performed in 

527 scipy.ndimage.binary_closing function. 

528 

529 .. versionadded:: 0.8.1 

530 

531 %(verbose)s 

532 

533 Returns 

534 ------- 

535 gm_mask_img : Nifti1Image, image corresponding to the brain gray matter 

536 from ICBM152 template. 

537 

538 See Also 

539 -------- 

540 nilearn.datasets.fetch_icbm152_2009: for details regarding the ICBM152 

541 template. 

542 

543 nilearn.datasets.load_mni152_template: for details about version of MNI152 

544 template and related. 

545 

546 Notes 

547 ----- 

548 This function relies on ICBM152 templates where we particularly pick 

549 gray matter template and threshold the template at .2 to take one fifth 

550 of the values. Then, do a bit post processing such as binary closing 

551 operation to more compact mask image. 

552 

553 .. note:: 

554 It is advised to check the mask image with your own data processing. 

555 

556 For more information 

557 see the :ref:`dataset description <icbm_152_template>`. 

558 

559 """ 

560 check_params(locals()) 

561 

562 # Fetching ICBM152 gray matter mask image 

563 icbm = fetch_icbm152_2009( 

564 data_dir=data_dir, resume=resume, verbose=verbose 

565 ) 

566 gm = icbm["gm"] 

567 gm_img = check_niimg(gm) 

568 gm_data = get_data(gm_img) 

569 

570 # getting one fifth of the values 

571 gm_mask = (gm_data > threshold).astype("int8") 

572 

573 gm_mask = binary_closing(gm_mask, iterations=n_iter) 

574 gm_mask_img = new_img_like(gm_img, gm_mask) 

575 

576 return gm_mask_img 

577 

578 

579def oasis_missing_subjects(): 

580 """Return list of missing subjects in OASIS dataset.""" 

581 return [ 

582 8, 

583 24, 

584 36, 

585 48, 

586 89, 

587 93, 

588 100, 

589 118, 

590 128, 

591 149, 

592 154, 

593 171, 

594 172, 

595 175, 

596 187, 

597 194, 

598 196, 

599 215, 

600 219, 

601 225, 

602 242, 

603 245, 

604 248, 

605 251, 

606 252, 

607 257, 

608 276, 

609 297, 

610 306, 

611 320, 

612 324, 

613 334, 

614 347, 

615 360, 

616 364, 

617 391, 

618 393, 

619 412, 

620 414, 

621 427, 

622 436, 

623 ] 

624 

625 

626@fill_doc 

627def fetch_oasis_vbm( 

628 n_subjects=None, 

629 dartel_version=True, 

630 data_dir=None, 

631 url=None, 

632 resume=True, 

633 verbose=1, 

634): 

635 """Download and load Oasis "cross-sectional MRI" dataset (416 subjects). 

636 

637 .. admonition:: Data Usage Agreement 

638 :class: attention 

639 

640 Using data available through the OASIS project requires agreeing with 

641 the Data Usage Agreement that can be found at 

642 https://sites.wustl.edu/oasisbrains/ 

643 

644 Parameters 

645 ---------- 

646 n_subjects : :obj:`int`, default=None 

647 The number of subjects to load. If None is given, all the 

648 subjects are used. 

649 

650 dartel_version : :obj:`bool`, default=True 

651 Whether or not to use data normalized with DARTEL instead of standard 

652 SPM8 normalization. 

653 %(data_dir)s 

654 %(url)s 

655 %(resume)s 

656 %(verbose)s 

657 

658 Returns 

659 ------- 

660 data : Bunch 

661 Dictionary-like object, the interest attributes are : 

662 

663 - 'gray_matter_maps': string list 

664 Paths to nifti gray matter density probability maps 

665 - 'white_matter_maps' string list 

666 Paths to nifti white matter density probability maps 

667 - 'ext_vars': pandas.DataFrame 

668 Data from the .csv file with information about selected subjects 

669 - 'data_usage_agreement': string 

670 Path to the .txt file containing the data usage agreement. 

671 

672 Notes 

673 ----- 

674 For more information 

675 see the :ref:`dataset description <oasis_maps>`. 

676 

677 """ 

678 check_params(locals()) 

679 

680 # check number of subjects 

681 if n_subjects is None: 

682 n_subjects = 403 if dartel_version else 415 

683 if dartel_version: # DARTEL version has 13 identified outliers 

684 if n_subjects > 403: 

685 warnings.warn( 

686 "Only 403 subjects are available in the " 

687 "DARTEL-normalized version of the dataset. " 

688 f"All of them will be used instead of the wanted {n_subjects}", 

689 stacklevel=find_stack_level(), 

690 ) 

691 n_subjects = 403 

692 elif n_subjects > 415: 

693 warnings.warn( 

694 "Only 415 subjects are available in the " 

695 "non-DARTEL-normalized version of the dataset. " 

696 f"All of them will be used instead of the wanted {n_subjects}", 

697 stacklevel=find_stack_level(), 

698 ) 

699 n_subjects = 415 

700 if n_subjects < 1: 

701 raise ValueError(f"Incorrect number of subjects ({n_subjects})") 

702 

703 # pick the archive corresponding to preprocessings type 

704 if url is None: 

705 if dartel_version: 

706 url_images = ( 

707 "https://www.nitrc.org/frs/download.php/" 

708 "6364/archive_dartel.tgz?i_agree=1&download_now=1" 

709 ) 

710 else: 

711 url_images = ( 

712 "https://www.nitrc.org/frs/download.php/" 

713 "6359/archive.tgz?i_agree=1&download_now=1" 

714 ) 

715 # covariates and license are in separate files on NITRC 

716 url_csv = ( 

717 "https://www.nitrc.org/frs/download.php/" 

718 "6348/oasis_cross-sectional.csv?i_agree=1&download_now=1" 

719 ) 

720 url_dua = ( 

721 "https://www.nitrc.org/frs/download.php/" 

722 "6349/data_usage_agreement.txt?i_agree=1&download_now=1" 

723 ) 

724 else: # local URL used in tests 

725 url_csv = url + "/oasis_cross-sectional.csv" 

726 url_dua = url + "/data_usage_agreement.txt" 

727 if dartel_version: 

728 url_images = url + "/archive_dartel.tgz" 

729 else: 

730 url_images = url + "/archive.tgz" 

731 

732 opts = {"uncompress": True} 

733 

734 # missing subjects create shifts in subjects ids 

735 missing_subjects = oasis_missing_subjects() 

736 

737 if dartel_version: 

738 # DARTEL produces outliers that are hidden by nilearn API 

739 removed_outliers = [ 

740 27, 

741 57, 

742 66, 

743 83, 

744 122, 

745 157, 

746 222, 

747 269, 

748 282, 

749 287, 

750 309, 

751 428, 

752 ] 

753 missing_subjects = sorted(missing_subjects + removed_outliers) 

754 file_names_gm = [ 

755 ( 

756 Path( 

757 f"OAS1_{s:04d}_MR1", 

758 f"mwrc1OAS1_{s:04d}_MR1_mpr_anon_fslswapdim_bet.nii.gz", 

759 ), 

760 url_images, 

761 opts, 

762 ) 

763 for s in range(1, 457) 

764 if s not in missing_subjects 

765 ][:n_subjects] 

766 file_names_wm = [ 

767 ( 

768 Path( 

769 f"OAS1_{s:04d}_MR1", 

770 f"mwrc2OAS1_{s:04d}_MR1_mpr_anon_fslswapdim_bet.nii.gz", 

771 ), 

772 url_images, 

773 opts, 

774 ) 

775 for s in range(1, 457) 

776 if s not in missing_subjects 

777 ] 

778 else: 

779 # only one gross outlier produced, hidden by nilearn API 

780 removed_outliers = [390] 

781 missing_subjects = sorted(missing_subjects + removed_outliers) 

782 file_names_gm = [ 

783 ( 

784 Path( 

785 f"OAS1_{s:04d}_MR1", 

786 f"mwc1OAS1_{s:04d}_MR1_mpr_anon_fslswapdim_bet.nii.gz", 

787 ), 

788 url_images, 

789 opts, 

790 ) 

791 for s in range(1, 457) 

792 if s not in missing_subjects 

793 ][:n_subjects] 

794 file_names_wm = [ 

795 ( 

796 Path( 

797 f"OAS1_{s:04d}_MR1", 

798 f"mwc2OAS1_{s:04d}_MR1_mpr_anon_fslswapdim_bet.nii.gz", 

799 ), 

800 url_images, 

801 opts, 

802 ) 

803 for s in range(1, 457) 

804 if s not in missing_subjects 

805 ] 

806 file_names_extvars = [("oasis_cross-sectional.csv", url_csv, {})] 

807 file_names_dua = [("data_usage_agreement.txt", url_dua, {})] 

808 # restrict to user-specified number of subjects 

809 file_names_gm = file_names_gm[:n_subjects] 

810 file_names_wm = file_names_wm[:n_subjects] 

811 

812 file_names = ( 

813 file_names_gm + file_names_wm + file_names_extvars + file_names_dua 

814 ) 

815 dataset_name = "oasis1" 

816 data_dir = get_dataset_dir( 

817 dataset_name, data_dir=data_dir, verbose=verbose 

818 ) 

819 files = fetch_files(data_dir, file_names, resume=resume, verbose=verbose) 

820 

821 # Build Bunch 

822 gm_maps = files[:n_subjects] 

823 wm_maps = files[n_subjects : (2 * n_subjects)] 

824 ext_vars_file = files[-2] 

825 data_usage_agreement = files[-1] 

826 

827 # Keep CSV information only for selected subjects 

828 csv_data = pd.read_csv(ext_vars_file) 

829 # Comparisons to recfromcsv data must be bytes. 

830 actual_subjects_ids = [ 

831 ("OAS1" + str.split(Path(x).name, "OAS1")[1][:9]) for x in gm_maps 

832 ] 

833 subject_mask = np.asarray( 

834 [subject_id in actual_subjects_ids for subject_id in csv_data["ID"]] 

835 ) 

836 csv_data = csv_data[subject_mask] 

837 csv_data = csv_data.rename( 

838 columns={c: c.lower().replace("/", "") for c in csv_data.columns} 

839 ) 

840 fdescr = get_dataset_descr(dataset_name) 

841 

842 return Bunch( 

843 gray_matter_maps=gm_maps, 

844 white_matter_maps=wm_maps, 

845 ext_vars=csv_data, 

846 data_usage_agreement=data_usage_agreement, 

847 description=fdescr, 

848 ) 

849 

850 

851@fill_doc 

852def fetch_surf_fsaverage(mesh="fsaverage5", data_dir=None): 

853 """Download a Freesurfer fsaverage surface. 

854 

855 File names are subject to change and only attribute names 

856 are guaranteed to be stable across nilearn versions. 

857 See :footcite:t:`Fischl1999`. 

858 

859 See :func:`~nilearn.datasets.load_fsaverage` and 

860 :func:`~nilearn.datasets.load_fsaverage_data` 

861 to access fsaverage data as :obj:`~nilearn.surface.SurfaceImage`. 

862 

863 Parameters 

864 ---------- 

865 mesh : :obj:`str`, default='fsaverage5' 

866 Which :term:`mesh` to fetch. 

867 Should be one of the following values: 

868 %(fsaverage_options)s 

869 

870 %(data_dir)s 

871 

872 Returns 

873 ------- 

874 data : :obj:`sklearn.utils.Bunch` 

875 Dictionary-like object, the interest attributes are : 

876 - 'area_left': Gifti file, left hemisphere area data 

877 - 'area_right': Gifti file, right hemisphere area data 

878 - 'curv_left': Gifti file, left hemisphere curvature data 

879 - 'curv_right': Gifti file, right hemisphere curvature data 

880 - 'flat_left': Gifti file, left hemisphere flat surface :term:`mesh` 

881 - 'flat_right': Gifti file, right hemisphere flat surface :term:`mesh` 

882 - 'pial_left': Gifti file, left hemisphere pial surface :term:`mesh` 

883 - 'pial_right': Gifti file, right hemisphere pial surface :term:`mesh` 

884 - 'infl_left': Gifti file, left hemisphere inflated pial surface 

885 :term:`mesh` 

886 - 'infl_right': Gifti file, right hemisphere inflated pial 

887 surface :term:`mesh` 

888 - 'sphere_left': Gifti file, left hemisphere sphere surface 

889 :term:`mesh` 

890 - 'sphere_right': Gifti file, right hemisphere sphere surface 

891 :term:`mesh` 

892 - 'sulc_left': Gifti file, left hemisphere sulcal depth data 

893 - 'sulc_right': Gifti file, right hemisphere sulcal depth data 

894 - 'thick_left': Gifti file, left hemisphere cortical thickness data 

895 - 'thick_right': Gifti file, right hemisphere cortical thickness data 

896 - 'white_left': Gifti file, left hemisphere 

897 white surface :term:`mesh` 

898 - 'white_right': Gifti file, right hemisphere* 

899 white surface :term:`mesh` 

900 

901 References 

902 ---------- 

903 .. footbibliography:: 

904 

905 """ 

906 check_params(locals()) 

907 

908 available_meshes = ( 

909 "fsaverage3", 

910 "fsaverage4", 

911 "fsaverage5", 

912 "fsaverage6", 

913 "fsaverage7", 

914 "fsaverage", 

915 ) 

916 

917 if mesh not in available_meshes: 

918 raise ValueError( 

919 f"'mesh' should be one of {available_meshes}; " 

920 f"{mesh!r} was provided" 

921 ) 

922 

923 # Call a dataset loader depending on the value of mesh 

924 if mesh in ( 

925 "fsaverage3", 

926 "fsaverage4", 

927 "fsaverage6", 

928 "fsaverage7", 

929 "fsaverage", 

930 ): 

931 # rename mesh to "fsaverage" to download it once 

932 # regardless of whether mesh equals "fsaverage" or "fsaverage7" 

933 if mesh == "fsaverage7": 

934 mesh = "fsaverage" 

935 bunch = _fetch_surf_fsaverage(mesh, data_dir=data_dir) 

936 elif mesh == "fsaverage5": 

937 bunch = _fetch_surf_fsaverage5() 

938 

939 return bunch 

940 

941 

942def _fetch_surf_fsaverage5(): 

943 """Ship fsaverage5 surfaces and sulcal information with Nilearn. 

944 

945 The source of the data is coming from nitrc based on this PR #1016. 

946 Manually downloaded gzipped and shipped with this function. 

947 

948 Shipping is done with Nilearn based on issue #1705. 

949 

950 """ 

951 data_dir = Path(FSAVERAGE5_PATH) 

952 

953 data = { 

954 f"{part}_{hemi}": str(data_dir / f"{part}_{hemi}.gii.gz") 

955 for part in [ 

956 "area", 

957 "curv", 

958 "flat", 

959 "infl", 

960 "pial", 

961 "sphere", 

962 "sulc", 

963 "thick", 

964 "white", 

965 ] 

966 for hemi in ["left", "right"] 

967 } 

968 data["description"] = get_dataset_descr("fsaverage5") 

969 

970 return Bunch(**data) 

971 

972 

973def _fetch_surf_fsaverage(dataset_name, data_dir=None): 

974 """Ship fsaverage{3,4,6,7} meshes. 

975 

976 These meshes can be used for visualization purposes, but also to run 

977 cortical surface-based searchlight decoding. 

978 

979 The source of the data is downloaded from OSF. 

980 """ 

981 dataset_dir = get_dataset_dir(dataset_name, data_dir=data_dir) 

982 opts = {"uncompress": True} 

983 

984 url = { 

985 "fsaverage3": "https://osf.io/azhdf/download", 

986 "fsaverage4": "https://osf.io/28uma/download", 

987 "fsaverage6": "https://osf.io/jzxyr/download", 

988 "fsaverage": "https://osf.io/svf8k/download", # fsaverage7 

989 }[dataset_name] 

990 

991 # List of attributes exposed by the dataset 

992 dataset_attributes = [ 

993 f"{part}_{hemi}" 

994 for part in [ 

995 "area", 

996 "curv", 

997 "flat", 

998 "infl", 

999 "pial", 

1000 "sphere", 

1001 "sulc", 

1002 "thick", 

1003 "white", 

1004 ] 

1005 for hemi in ["left", "right"] 

1006 ] 

1007 

1008 # Note that the file names match the attribute's 

1009 fetch_files( 

1010 dataset_dir, 

1011 [ 

1012 (f"{attribute}.gii.gz", url, opts) 

1013 for attribute in dataset_attributes 

1014 ], 

1015 ) 

1016 

1017 result = { 

1018 attribute: dataset_dir / f"{attribute}.gii.gz" 

1019 for attribute in dataset_attributes 

1020 } 

1021 result["description"] = str(get_dataset_descr(dataset_name)) 

1022 

1023 return Bunch(**result) 

1024 

1025 

1026@fill_doc 

1027def load_fsaverage(mesh="fsaverage5", data_dir=None): 

1028 """Load fsaverage for both hemispheres as PolyMesh objects. 

1029 

1030 .. versionadded:: 0.11.0 

1031 

1032 Parameters 

1033 ---------- 

1034 mesh : :obj:`str`, default='fsaverage5' 

1035 Which :term:`mesh` to fetch. 

1036 Should be one of the following values: 

1037 %(fsaverage_options)s 

1038 

1039 %(data_dir)s 

1040 

1041 Returns 

1042 ------- 

1043 data : :obj:`sklearn.utils.Bunch` 

1044 Dictionary-like object, the interest attributes are : 

1045 - ``'description'``: description of the dataset 

1046 - ``'pial'``: Polymesh for pial surface for left and right hemispheres 

1047 - ``'white_matter'``: Polymesh for white matter surface 

1048 for left and right hemispheres 

1049 - ``'inflated'``: Polymesh for inglated surface 

1050 for left and right hemispheres 

1051 - ``'sphere'``: Polymesh for spherical surface 

1052 for left and right hemispheres 

1053 - ``'flat'``: Polymesh for flattened surface 

1054 for left and right hemispheres 

1055 """ 

1056 check_params(locals()) 

1057 

1058 fsaverage = fetch_surf_fsaverage(mesh, data_dir=data_dir) 

1059 renaming = { 

1060 "pial": "pial", 

1061 "white": "white_matter", 

1062 "infl": "inflated", 

1063 "sphere": "sphere", 

1064 "flat": "flat", 

1065 } 

1066 meshes = {"description": fsaverage.description} 

1067 for key, value in renaming.items(): 

1068 left = FileMesh(fsaverage[f"{key}_left"]) 

1069 right = FileMesh(fsaverage[f"{key}_right"]) 

1070 meshes[value] = PolyMesh(left=left, right=right) 

1071 return Bunch(**meshes) 

1072 

1073 

1074@fill_doc 

1075def load_fsaverage_data( 

1076 mesh="fsaverage5", mesh_type="pial", data_type="sulcal", data_dir=None 

1077): 

1078 """Return freesurfer data on an fsaverage mesh as a SurfaceImage. 

1079 

1080 .. versionadded:: 0.11.0 

1081 

1082 Parameters 

1083 ---------- 

1084 mesh : :obj:`str`, default='fsaverage5' 

1085 Which :term:`mesh` to fetch. 

1086 Should be one of the following values: 

1087 %(fsaverage_options)s 

1088 

1089 mesh_type : :obj:`str`, default='pial' 

1090 Must be one of: 

1091 - ``"pial"`` 

1092 - ``"white_matter"`` 

1093 - ``"inflated"`` 

1094 - ``"sphere"`` 

1095 - ``"flat"`` 

1096 

1097 data_type : :obj:`str`, default='sulcal' 

1098 Must be one of: 

1099 - ``"curvature"``, 

1100 - ``"sulcal"``, 

1101 - ``"thickness"``, 

1102 

1103 %(data_dir)s 

1104 

1105 Returns 

1106 ------- 

1107 img : :obj:`~nilearn.surface.SurfaceImage` 

1108 SurfaceImage with the freesurfer mesh and data. 

1109 """ 

1110 check_params(locals()) 

1111 

1112 if mesh_type not in ALLOWED_MESH_TYPES: 

1113 raise ValueError( 

1114 f"'mesh_type' must be one of {ALLOWED_MESH_TYPES}.\n" 

1115 f"Got: {mesh_type=}." 

1116 ) 

1117 if data_type not in ALLOWED_DATA_TYPES: 

1118 raise ValueError( 

1119 f"'data_type' must be one of {ALLOWED_DATA_TYPES}.\n" 

1120 f"Got: {data_type=}." 

1121 ) 

1122 

1123 fsaverage = load_fsaverage(mesh=mesh, data_dir=data_dir) 

1124 fsaverage_data = fetch_surf_fsaverage(mesh=mesh, data_dir=data_dir) 

1125 renaming = {"curvature": "curv", "sulcal": "sulc", "thickness": "thick"} 

1126 img = SurfaceImage( 

1127 mesh=fsaverage[mesh_type], 

1128 data={ 

1129 "left": fsaverage_data[f"{renaming[data_type]}_left"], 

1130 "right": fsaverage_data[f"{renaming[data_type]}_right"], 

1131 }, 

1132 ) 

1133 

1134 return img