From 1d0407226a3ad8f399aedd05e780394d90c24fc8 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Fri, 7 May 2021 19:22:30 +0200 Subject: [PATCH 01/44] Repalce numpy with pandas --- nilearn/datasets/atlas.py | 32 +++++++++++----------- nilearn/datasets/func.py | 38 ++++++++++++--------------- nilearn/datasets/struct.py | 5 ++-- nilearn/datasets/tests/test_func.py | 24 ++++++++--------- nilearn/datasets/tests/test_struct.py | 4 +-- 5 files changed, 49 insertions(+), 54 deletions(-) diff --git a/nilearn/datasets/atlas.py b/nilearn/datasets/atlas.py index 59aa80e194..7013c68864 100644 --- a/nilearn/datasets/atlas.py +++ b/nilearn/datasets/atlas.py @@ -10,6 +10,7 @@ import nibabel as nb import numpy as np +import pandas as pd from numpy.lib import recfunctions from sklearn.utils import Bunch @@ -109,7 +110,7 @@ def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, resume=True # Download the zip file, first files_ = _fetch_files(data_dir, files, verbose=verbose) - labels = np.recfromcsv(files_[0]) + labels = pd.read_csv(files_[0]).to_records() # README readme_files = [('README.md', 'https://osf.io/4k9bf/download', @@ -257,7 +258,7 @@ def fetch_atlas_destrieux_2009(lateralized=True, data_dir=None, url=None, files_ = _fetch_files(data_dir, files, resume=resume, verbose=verbose) - params = dict(maps=files_[1], labels=np.recfromcsv(files_[0])) + params = dict(maps=files_[1], labels=pd.read_csv(files_[0])) with open(files_[2], 'r') as rst_file: params['description'] = rst_file.read() @@ -486,13 +487,13 @@ def fetch_atlas_msdl(data_dir=None, url=None, resume=True, verbose=1): data_dir = _get_dataset_dir(dataset_name, data_dir=data_dir, verbose=verbose) files = _fetch_files(data_dir, files, resume=resume, verbose=verbose) - csv_data = np.recfromcsv(files[0]) + csv_data = pd.read_csv(files[0]) labels = [name.strip() for name in csv_data['name'].tolist()] - labels = [label.decode("utf-8") for label in labels] + with warnings.catch_warnings(): warnings.filterwarnings('ignore', module='numpy', category=FutureWarning) - region_coords = csv_data[['x', 'y', 'z']].tolist() + region_coords = csv_data[['x', 'y', 'z']].values.tolist() net_names = [net_name.strip() for net_name in csv_data['net_name'].tolist()] fdescr = _get_dataset_descr(dataset_name) @@ -520,7 +521,7 @@ def fetch_coords_power_2011(): fdescr = _get_dataset_descr(dataset_name) package_directory = os.path.dirname(os.path.abspath(__file__)) csv = os.path.join(package_directory, "data", "power_2011.csv") - params = dict(rois=np.recfromcsv(csv), description=fdescr) + params = dict(rois=pd.read_csv(csv).to_records(), description=fdescr) return Bunch(**params) @@ -946,10 +947,10 @@ def fetch_coords_dosenbach_2010(ordered_regions=True): fdescr = _get_dataset_descr(dataset_name) package_directory = os.path.dirname(os.path.abspath(__file__)) csv = os.path.join(package_directory, "data", "dosenbach_2010.csv") - out_csv = np.recfromcsv(csv) + out_csv = pd.read_csv(csv) if ordered_regions: - out_csv = np.sort(out_csv, order=['network', 'name', 'y']) + out_csv = out_csv.sort_values(by=['network', 'name', 'y']) # We add the ROI number to its name, since names are not unique names = out_csv['name'] @@ -1006,10 +1007,8 @@ def fetch_coords_seitzman_2018(ordered_regions=True): anatomical_file = os.path.join(package_directory, "data", "seitzman_2018_ROIs_anatomicalLabels.txt") - rois = np.recfromcsv(roi_file, delimiter=" ") - rois = recfunctions.rename_fields(rois, {"netname": "network", - "radiusmm": "radius"}) - rois.network = rois.network.astype(str) + rois = pd.read_csv(roi_file, delimiter=" ") + rois = rois.rename(columns={"netName": "network", "radius(mm)": "radius"}) # get integer regional labels and convert to text labels with mapping # from header line @@ -1023,16 +1022,15 @@ def fetch_coords_seitzman_2018(ordered_regions=True): anatomical = np.genfromtxt(anatomical_file, skip_header=1) anatomical_names = np.array([region_mapping[a] for a in anatomical]) - rois = recfunctions.merge_arrays((rois, anatomical_names), - asrecarray=True, flatten=True) - rois.dtype.names = rois.dtype.names[:-1] + ("region",) + rois = pd.concat([rois, pd.DataFrame(anatomical_names)], axis=1) + rois.columns = list(rois.columns[:-1]) + ["region"] if ordered_regions: - rois = np.sort(rois, order=['network', 'y']) + rois = rois.sort_values(by=['network', 'y']) params = dict(rois=rois[['x', 'y', 'z']], radius=rois['radius'], - networks=rois['network'].astype(str), + networks=rois['network'], regions=rois['region'], description=fdescr) return Bunch(**params) diff --git a/nilearn/datasets/func.py b/nilearn/datasets/func.py index b4a6c83388..ddfdc59eb5 100644 --- a/nilearn/datasets/func.py +++ b/nilearn/datasets/func.py @@ -980,20 +980,17 @@ def _is_valid_path(path, index, verbose): # Load covariates file from numpy.lib.recfunctions import join_by participants_file = os.path.join(data_dir, participants_file) - csv_data = np.recfromcsv(participants_file, delimiter='\t') + csv_data = pd.read_csv(participants_file, delimiter='\t') behavioural_file = os.path.join(data_dir, behavioural_file) - csv_data2 = np.recfromcsv(behavioural_file, delimiter='\t') - csv_data = join_by( - "participant_id", csv_data, csv_data2, usemask=False, asrecarray=True) + csv_data2 = pd.read_csv(behavioural_file, delimiter='\t') + csv_data = csv_data.merge(csv_data2) subject_names = csv_data["participant_id"].tolist() subjects_indices = [] for name in subject_ids: - name = name.encode("utf8") if name not in subject_names: continue subjects_indices.append(subject_names.index(name)) - csv_data = csv_data[subjects_indices] - + csv_data = csv_data.iloc[subjects_indices] return Bunch(ext_vars=csv_data, description=fdescr, **files) @@ -1238,10 +1235,10 @@ def fetch_abide_pcp(data_dir=None, n_subjects=None, pipeline='cpac', # bytes (encode()) needed for python 2/3 compat with numpy pheno = '\n'.join(pheno).encode() pheno = BytesIO(pheno) - pheno = np.recfromcsv(pheno, comments='$', case_sensitive=True) + pheno = pd.read_csv(pheno, comment='$') # First, filter subjects with no filename - pheno = pheno[pheno['FILE_ID'] != b'no_filename'] + pheno = pheno[pheno['FILE_ID'] != 'no_filename'] # Apply user defined filters user_filter = _filter_columns(pheno, kwargs) pheno = pheno[user_filter] @@ -1252,7 +1249,7 @@ def fetch_abide_pcp(data_dir=None, n_subjects=None, pipeline='cpac', # Get the files results = {} - file_ids = [file_id.decode() for file_id in pheno['FILE_ID']] + file_ids = pheno['FILE_ID'].tolist() if n_subjects is not None: file_ids = file_ids[:n_subjects] pheno = pheno[:n_subjects] @@ -1634,9 +1631,8 @@ def fetch_cobre(n_subjects=10, data_dir=None, url=None, verbose=1): names = ['ID', 'Current Age', 'Gender', 'Handedness', 'Subject Type', 'Diagnosis', 'Frames OK', 'FD', 'FD Scrubbed'] - csv_array_phen = np.recfromcsv(csv_file_phen, names=names, - skip_header=True, delimiter='\t') - + csv_array_phen = pd.read_csv(csv_file_phen, names=names, header=0, + delimiter='\t') # Check number of subjects max_subjects = len(csv_array_phen) if n_subjects is None: @@ -1646,19 +1642,19 @@ def fetch_cobre(n_subjects=10, data_dir=None, url=None, verbose=1): warnings.warn('Warning: there are only %d subjects' % max_subjects) n_subjects = max_subjects - sz_count = list(csv_array_phen['subject_type']).count(b'Patient') - ct_count = list(csv_array_phen['subject_type']).count(b'Control') + sz_count = list(csv_array_phen['Subject Type']).count('Patient') + ct_count = list(csv_array_phen['Subject Type']).count('Control') n_sz = np.round(float(n_subjects) / max_subjects * sz_count).astype(int) n_ct = np.round(float(n_subjects) / max_subjects * ct_count).astype(int) # First, restrict the csv files to the adequate number of subjects - sz_ids = csv_array_phen[csv_array_phen['subject_type'] == - b'Patient']['id'][:n_sz] - ct_ids = csv_array_phen[csv_array_phen['subject_type'] == - b'Control']['id'][:n_ct] + sz_ids = csv_array_phen[csv_array_phen['Subject Type'] == + 'Patient']['ID'][:n_sz] + ct_ids = csv_array_phen[csv_array_phen['Subject Type'] == + 'Control']['ID'][:n_ct] ids = np.hstack([sz_ids, ct_ids]) - csv_array_phen = csv_array_phen[np.in1d(csv_array_phen['id'], ids)] + csv_array_phen = csv_array_phen[np.in1d(csv_array_phen['ID'], ids)] # Call fetch_files once per subject. @@ -2170,7 +2166,7 @@ def _reduce_confounds(regressors, keep_confounds): out_file = in_file.replace('desc-confounds', 'desc-reducedConfounds') if not os.path.isfile(out_file): - confounds = np.recfromcsv(in_file, delimiter='\t') + confounds = pd.read_csv(in_file, delimiter='\t').to_records() selected_confounds = confounds[keep_confounds] header = '\t'.join(selected_confounds.dtype.names) np.savetxt(out_file, np.array(selected_confounds.tolist()), diff --git a/nilearn/datasets/struct.py b/nilearn/datasets/struct.py index c23e2bf26d..cc63579539 100644 --- a/nilearn/datasets/struct.py +++ b/nilearn/datasets/struct.py @@ -6,6 +6,7 @@ from pathlib import Path import numpy as np +import pandas as pd from scipy import ndimage from sklearn.utils import Bunch @@ -429,14 +430,14 @@ def fetch_oasis_vbm(n_subjects=None, dartel_version=True, data_dir=None, data_usage_agreement = files[-1] # Keep CSV information only for selected subjects - csv_data = np.recfromcsv(ext_vars_file) + csv_data = pd.read_csv(ext_vars_file) # Comparisons to recfromcsv data must be bytes. actual_subjects_ids = [("OAS1" + str.split(os.path.basename(x), "OAS1")[1][:9]).encode() for x in gm_maps] subject_mask = np.asarray([subject_id in actual_subjects_ids - for subject_id in csv_data['id']]) + for subject_id in csv_data['ID']]) csv_data = csv_data[subject_mask] fdescr = _get_dataset_descr(dataset_name) diff --git a/nilearn/datasets/tests/test_func.py b/nilearn/datasets/tests/test_func.py index 081194f904..3f633bba16 100644 --- a/nilearn/datasets/tests/test_func.py +++ b/nilearn/datasets/tests/test_func.py @@ -206,9 +206,9 @@ def test_fetch_localizer_contrasts(tmp_path, request_mocker, localizer_mocker): assert not hasattr(dataset, 'tmaps') assert not hasattr(dataset, 'masks') assert isinstance(dataset.cmaps[0], str) - assert isinstance(dataset.ext_vars, np.recarray) + assert isinstance(dataset.ext_vars, pd.DataFrame) assert len(dataset.cmaps) == 2 - assert dataset.ext_vars.size == 2 + assert len(dataset['ext_vars']) == 2 # Multiple contrasts dataset = func.fetch_localizer_contrasts( @@ -216,10 +216,10 @@ def test_fetch_localizer_contrasts(tmp_path, request_mocker, localizer_mocker): n_subjects=2, data_dir=str(tmp_path), verbose=1) - assert isinstance(dataset.ext_vars, np.recarray) + assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.cmaps[0], str) assert len(dataset.cmaps) == 2 * 2 # two contrasts are fetched - assert dataset.ext_vars.size == 2 + assert len(dataset['ext_vars']) == 2 # all get_*=True dataset = func.fetch_localizer_contrasts( @@ -230,12 +230,12 @@ def test_fetch_localizer_contrasts(tmp_path, request_mocker, localizer_mocker): get_masks=True, get_tmaps=True, verbose=1) - assert isinstance(dataset.ext_vars, np.recarray) + assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.anats[0], str) assert isinstance(dataset.cmaps[0], str) assert isinstance(dataset.masks[0], str) assert isinstance(dataset.tmaps[0], str) - assert dataset.ext_vars.size == 1 + assert len(dataset['ext_vars']) == 1 assert len(dataset.anats) == 1 assert len(dataset.cmaps) == 1 assert len(dataset.masks) == 1 @@ -248,10 +248,10 @@ def test_fetch_localizer_contrasts(tmp_path, request_mocker, localizer_mocker): n_subjects=[2, 3, 5], data_dir=str(tmp_path), verbose=1) - assert dataset2.ext_vars.size == 3 + assert len(dataset2['ext_vars']) == 3 assert len(dataset2.cmaps) == 3 - assert ([row[0] for row in dataset2.ext_vars] == - [b'S02', b'S03', b'S05']) + assert (list(dataset2['ext_vars']['participant_id'].values) == + ['S02', 'S03', 'S05']) def test_fetch_localizer_calculation_task(tmp_path, request_mocker, @@ -261,9 +261,9 @@ def test_fetch_localizer_calculation_task(tmp_path, request_mocker, n_subjects=2, data_dir=str(tmp_path), verbose=1) - assert isinstance(dataset.ext_vars, np.recarray) + assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.cmaps[0], str) - assert dataset.ext_vars.size == 2 + assert len(dataset['ext_vars']) == 2 assert len(dataset.cmaps) == 2 assert dataset.description != '' @@ -494,7 +494,7 @@ def test_fetch_cobre(tmp_path, request_mocker): assert isinstance(cobre_data.confounds, list) assert isinstance(cobre_data.func[0], str) # returned phenotypic data will be an array - assert isinstance(cobre_data.phenotypic, np.recarray) + assert isinstance(cobre_data.phenotypic, pd.DataFrame) # Fetch only 30 subjects data_30_subjects = func.fetch_cobre(n_subjects=30, diff --git a/nilearn/datasets/tests/test_struct.py b/nilearn/datasets/tests/test_struct.py index 23c0cfb5af..ca7c2f42a9 100644 --- a/nilearn/datasets/tests/test_struct.py +++ b/nilearn/datasets/tests/test_struct.py @@ -119,7 +119,7 @@ def test_fetch_oasis_vbm(tmp_path, request_mocker): assert len(dataset.white_matter_maps) == 403 assert isinstance(dataset.gray_matter_maps[0], str) assert isinstance(dataset.white_matter_maps[0], str) - assert isinstance(dataset.ext_vars, np.recarray) + assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.data_usage_agreement, str) assert request_mocker.url_count == 1 @@ -129,7 +129,7 @@ def test_fetch_oasis_vbm(tmp_path, request_mocker): assert len(dataset.white_matter_maps) == 415 assert isinstance(dataset.gray_matter_maps[0], str) assert isinstance(dataset.white_matter_maps[0], str) - assert isinstance(dataset.ext_vars, np.recarray) + assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.data_usage_agreement, str) assert request_mocker.url_count == 2 assert dataset.description != '' From 58ff41c18d0c3e8f39bf8233e6494a547fa096bc Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Thu, 16 Dec 2021 16:17:38 +0100 Subject: [PATCH 02/44] [MAINT] Fix new typos found by codespell (#3101) Fixes c87847b7 / #3003. --- nilearn/signal.py | 9 +++++---- nilearn/tests/test_signal.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/nilearn/signal.py b/nilearn/signal.py index 3691d4c610..b5b4b8f6f8 100644 --- a/nilearn/signal.py +++ b/nilearn/signal.py @@ -861,9 +861,10 @@ def _check_signal_parameters(detrend, standardize_confounds): """Raise warning if the combination is illogical""" if not detrend and not standardize_confounds: warnings.warn("When confounds are provided, one must perform detrend " - "and/or standarize confounds. You provided detrend={0}, " - "standardize_confounds={1}. If confounds were not " - "standardized or demeaned before passing to signal.clean" - " signal will not be correctly cleaned. ".format( + "and/or standardize confounds. You provided " + "detrend={0}, standardize_confounds={1}. If confounds " + "were not standardized or demeaned before passing to " + "signal.clean signal will not be correctly " + "cleaned. ".format( detrend, standardize_confounds) ) diff --git a/nilearn/tests/test_signal.py b/nilearn/tests/test_signal.py index 1453c4c383..45577f2c32 100644 --- a/nilearn/tests/test_signal.py +++ b/nilearn/tests/test_signal.py @@ -506,7 +506,7 @@ def test_clean_confounds(): # Test without standardizing that constant parts of confounds are # accounted for # passing standardize_confounds=False, detrend=False should raise warning - warning_message = r"must perform detrend and/or standarize confounds" + warning_message = r"must perform detrend and/or standardize confounds" with pytest.warns(UserWarning, match=warning_message): np.testing.assert_almost_equal( nisignal.clean(np.ones((20, 2)), From 03e1f58c5fc754cddf37d60e479b65e1effc5661 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Thu, 16 Dec 2021 18:04:50 +0100 Subject: [PATCH 03/44] Fix pep8 + destrieux --- nilearn/datasets/atlas.py | 2 +- nilearn/datasets/tests/test_func.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/nilearn/datasets/atlas.py b/nilearn/datasets/atlas.py index 6c37a4c9c1..0ef429dcc5 100644 --- a/nilearn/datasets/atlas.py +++ b/nilearn/datasets/atlas.py @@ -238,7 +238,7 @@ def fetch_atlas_destrieux_2009(lateralized=True, data_dir=None, url=None, files_ = _fetch_files(data_dir, files, resume=resume, verbose=verbose) - params = dict(maps=files_[1], labels=pd.read_csv(files_[0])) + params = dict(maps=files_[1], labels=pd.read_csv(files_[0], index_col=0).to_records()) with open(files_[2], 'r') as rst_file: params['description'] = rst_file.read() diff --git a/nilearn/datasets/tests/test_func.py b/nilearn/datasets/tests/test_func.py index 3973ae2827..bd6b6eac66 100644 --- a/nilearn/datasets/tests/test_func.py +++ b/nilearn/datasets/tests/test_func.py @@ -214,8 +214,9 @@ def test_fetch_localizer_contrasts(tmp_path, request_mocker, localizer_mocker): verbose=1) assert len(dataset2['ext_vars']) == 3 assert len(dataset2.cmaps) == 3 - assert (list(dataset2['ext_vars']['participant_id'].values) == - ['S02', 'S03', 'S05']) + assert (list(dataset2['ext_vars']['participant_id'].values) == ['S02', + 'S03', + 'S05']) def test_fetch_localizer_calculation_task(tmp_path, request_mocker, From 1bac472c9eb73c9228cdde192393d748f1f04ef2 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Thu, 16 Dec 2021 19:22:30 +0100 Subject: [PATCH 04/44] Fix pep8 --- nilearn/datasets/atlas.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nilearn/datasets/atlas.py b/nilearn/datasets/atlas.py index 0ef429dcc5..50ad5bca2d 100644 --- a/nilearn/datasets/atlas.py +++ b/nilearn/datasets/atlas.py @@ -238,7 +238,8 @@ def fetch_atlas_destrieux_2009(lateralized=True, data_dir=None, url=None, files_ = _fetch_files(data_dir, files, resume=resume, verbose=verbose) - params = dict(maps=files_[1], labels=pd.read_csv(files_[0], index_col=0).to_records()) + params = dict(maps=files_[1], + labels=pd.read_csv(files_[0], index_col=0).to_records()) with open(files_[2], 'r') as rst_file: params['description'] = rst_file.read() From aeaf3ef142289a20274b178e36911616a10ba943 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Wed, 12 Jan 2022 11:50:26 +0100 Subject: [PATCH 05/44] Merge docs --- .ipynb_checkpoints/Untitled-checkpoint.ipynb | 6 ---- Untitled.ipynb | 33 -------------------- 2 files changed, 39 deletions(-) delete mode 100644 .ipynb_checkpoints/Untitled-checkpoint.ipynb delete mode 100644 Untitled.ipynb diff --git a/.ipynb_checkpoints/Untitled-checkpoint.ipynb b/.ipynb_checkpoints/Untitled-checkpoint.ipynb deleted file mode 100644 index 363fcab7ed..0000000000 --- a/.ipynb_checkpoints/Untitled-checkpoint.ipynb +++ /dev/null @@ -1,6 +0,0 @@ -{ - "cells": [], - "metadata": {}, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/Untitled.ipynb b/Untitled.ipynb deleted file mode 100644 index 56b7d4986e..0000000000 --- a/Untitled.ipynb +++ /dev/null @@ -1,33 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "f972f98d-8f15-4fb9-b1f9-6f51822d7905", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.2" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 24024b1e12108b6dc12c2c56c1b24efe5a880af0 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Wed, 19 Jan 2022 11:47:18 +0100 Subject: [PATCH 06/44] continue work (unfinished) --- nilearn/_utils/docs.py | 7 ++++++ nilearn/datasets/atlas.py | 46 ++++++++++++++++++++++++++++++--------- nilearn/datasets/func.py | 25 ++++++++++++++++----- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/nilearn/_utils/docs.py b/nilearn/_utils/docs.py index 01a6a11b4c..473db8ad6d 100644 --- a/nilearn/_utils/docs.py +++ b/nilearn/_utils/docs.py @@ -35,6 +35,13 @@ ax : :class:`~matplotlib.axes.Axes` The matplotlib axes in which the plots will be drawn.""" +# Legacy_format +docdict['legacy_format'] = """ +legacy_format : :obj:`bool`, optional + If set to ``True``, the fetcher will return recarrays. Otherwise, + it will return pandas dataframes. + Default=True.""" + # Resume docdict['resume'] = """ resume : :obj:`bool`, optional diff --git a/nilearn/datasets/atlas.py b/nilearn/datasets/atlas.py index 8fb040de76..fd7e2d0082 100644 --- a/nilearn/datasets/atlas.py +++ b/nilearn/datasets/atlas.py @@ -23,7 +23,8 @@ @fill_doc -def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, resume=True, verbose=1): +def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, + resume=True, verbose=1, legacy_format=True): """Fetch DiFuMo brain atlas Dictionaries of Functional Modes, or “DiFuMo”, can serve as atlases to extract @@ -57,6 +58,7 @@ def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, resume=True %(data_dir)s %(resume)s %(verbose)s + %(legacy_format)s Returns ------- @@ -113,7 +115,9 @@ def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, resume=True # Download the zip file, first files_ = _fetch_files(data_dir, files, verbose=verbose) - labels = pd.read_csv(files_[0]).to_records() + labels = pd.read_csv(files_[0]) + if legacy_format: + labels = labels.to_records() # README readme_files = [('README.md', 'https://osf.io/4k9bf/download', @@ -200,7 +204,7 @@ def fetch_atlas_craddock_2012(data_dir=None, url=None, resume=True, verbose=1): @fill_doc def fetch_atlas_destrieux_2009(lateralized=True, data_dir=None, url=None, - resume=True, verbose=1): + resume=True, verbose=1, legacy_format=True): """Download and load the Destrieux cortical atlas (dated 2009). See :footcite:`Fischl2004Automatically`, @@ -221,6 +225,7 @@ def fetch_atlas_destrieux_2009(lateralized=True, data_dir=None, url=None, %(url)s %(resume)s %(verbose)s + %(legacy_format)s Returns ------- @@ -261,7 +266,10 @@ def fetch_atlas_destrieux_2009(lateralized=True, data_dir=None, url=None, verbose=verbose) params = dict(maps=files_[1], - labels=pd.read_csv(files_[0], index_col=0).to_records()) + labels=pd.read_csv(files_[0], index_col=0)) + + if legacy_format: + params['labels'] = params['labels'].to_records() with open(files_[2], 'r') as rst_file: params['description'] = rst_file.read() @@ -721,18 +729,23 @@ def fetch_atlas_msdl(data_dir=None, url=None, resume=True, verbose=1): warnings.filterwarnings('ignore', module='numpy', category=FutureWarning) region_coords = csv_data[['x', 'y', 'z']].values.tolist() - net_names = [net_name.strip() for net_name in csv_data['net_name'].tolist()] + net_names = [net_name.strip() for net_name in csv_data['net name'].tolist()] fdescr = _get_dataset_descr(dataset_name) return Bunch(maps=files[1], labels=labels, region_coords=region_coords, networks=net_names, description=fdescr) -def fetch_coords_power_2011(): +@fill_doc +def fetch_coords_power_2011(legacy_format=True): """Download and load the Power et al. brain atlas composed of 264 ROIs. See :footcite:`Power2011Functional`. + Parameters + ---------- + %(legacy_format)s + Returns ------- data : :func:`sklearn.utils.Bunch` @@ -740,6 +753,8 @@ def fetch_coords_power_2011(): - 'rois': :class:`numpy.recarray`, rec array containing the coordinates of 264 ROIs in :term:`MNI` space. + If ``legacy_format`` is set to ``False``, this is a + :class:`pandas.DataFrame`. - 'description': :obj:`str`, description of the atlas. @@ -752,8 +767,9 @@ def fetch_coords_power_2011(): fdescr = _get_dataset_descr(dataset_name) package_directory = os.path.dirname(os.path.abspath(__file__)) csv = os.path.join(package_directory, "data", "power_2011.csv") - params = dict(rois=pd.read_csv(csv).to_records(), description=fdescr) - + params = dict(rois=pd.read_csv(csv), description=fdescr) + if legacy_format: + params['rois'] = params['rois'].to_records() return Bunch(**params) @@ -1168,7 +1184,8 @@ def fetch_atlas_basc_multiscale_2015(version='sym', data_dir=None, url=None, return Bunch(**params) -def fetch_coords_dosenbach_2010(ordered_regions=True): +@fill_doc +def fetch_coords_dosenbach_2010(ordered_regions=True, legacy_format=True): """Load the Dosenbach et al. 160 ROIs. These ROIs cover much of the cerebral cortex and cerebellum and are assigned to 6 networks. @@ -1181,6 +1198,7 @@ def fetch_coords_dosenbach_2010(ordered_regions=True): ROIs from same networks are grouped together and ordered with respect to their names and their locations (anterior to posterior). Default=True. + %(legacy_format)s Returns ------- @@ -1218,10 +1236,14 @@ def fetch_coords_dosenbach_2010(ordered_regions=True): labels=labels, networks=out_csv['network'], description=fdescr) + if legacy_format: + params['rois'] = params['rois'].to_records() + return Bunch(**params) -def fetch_coords_seitzman_2018(ordered_regions=True): +@fill_doc +def fetch_coords_seitzman_2018(ordered_regions=True, legacy_format=True): """Load the Seitzman et al. 300 ROIs. These ROIs cover cortical, subcortical and cerebellar regions and are @@ -1240,6 +1262,7 @@ def fetch_coords_seitzman_2018(ordered_regions=True): ordered_regions : :obj:`bool`, optional ROIs from same networks are grouped together and ordered with respect to their locations (anterior to posterior). Default=True. + %(legacy_format)s Returns ------- @@ -1290,6 +1313,9 @@ def fetch_coords_seitzman_2018(ordered_regions=True): if ordered_regions: rois = rois.sort_values(by=['network', 'y']) + if legacy_format: + rois = rois.to_records() + params = dict(rois=rois[['x', 'y', 'z']], radius=rois['radius'], networks=rois['network'], diff --git a/nilearn/datasets/func.py b/nilearn/datasets/func.py index 7e2400c56c..517d438314 100644 --- a/nilearn/datasets/func.py +++ b/nilearn/datasets/func.py @@ -412,7 +412,8 @@ def fetch_miyawaki2008(data_dir=None, url=None, resume=True, verbose=1): @fill_doc def fetch_localizer_contrasts(contrasts, n_subjects=None, get_tmaps=False, get_masks=False, get_anats=False, - data_dir=None, url=None, resume=True, verbose=1): + data_dir=None, url=None, resume=True, verbose=1, + legacy_format=True): """Download and load Brainomics/Localizer dataset (94 subjects). "The Functional Localizer is a simple and fast acquisition @@ -525,6 +526,7 @@ def fetch_localizer_contrasts(contrasts, n_subjects=None, get_tmaps=False, %(url)s %(resume)s %(verbose)s + %(legacy_format)s Returns ------- @@ -751,12 +753,14 @@ def _is_valid_path(path, index, verbose): continue subjects_indices.append(subject_names.index(name)) csv_data = csv_data.iloc[subjects_indices] + if legacy_format: + csv_data = csv_data.to_records() return Bunch(ext_vars=csv_data, description=fdescr, **files) @fill_doc def fetch_localizer_calculation_task(n_subjects=1, data_dir=None, url=None, - verbose=1): + verbose=1, legacy_format=True): """Fetch calculation task contrast maps from the localizer. Parameters @@ -767,6 +771,7 @@ def fetch_localizer_calculation_task(n_subjects=1, data_dir=None, url=None, %(data_dir)s %(url)s %(verbose)s + %(legacy_format)s Returns ------- @@ -790,13 +795,14 @@ def fetch_localizer_calculation_task(n_subjects=1, data_dir=None, url=None, n_subjects=n_subjects, get_tmaps=False, get_masks=False, get_anats=False, data_dir=data_dir, - url=url, resume=True, verbose=verbose) + url=url, resume=True, verbose=verbose, + legacy_format=legacy_format) return data @fill_doc def fetch_localizer_button_task(data_dir=None, url=None, - verbose=1): + verbose=1, legacy_format=True): """Fetch left vs right button press contrast maps from the localizer. Parameters @@ -804,6 +810,7 @@ def fetch_localizer_button_task(data_dir=None, url=None, %(data_dir)s %(url)s %(verbose)s + %(legacy_format)s Returns ------- @@ -830,7 +837,8 @@ def fetch_localizer_button_task(data_dir=None, url=None, n_subjects=[2], get_tmaps=True, get_masks=False, get_anats=True, data_dir=data_dir, - url=url, resume=True, verbose=verbose) + url=url, resume=True, verbose=verbose, + legacy_format=legacy_format) # Additional keys for backward compatibility data['tmap'] = data['tmaps'][0] data['anat'] = data['anats'][0] @@ -841,7 +849,8 @@ def fetch_localizer_button_task(data_dir=None, url=None, def fetch_abide_pcp(data_dir=None, n_subjects=None, pipeline='cpac', band_pass_filtering=False, global_signal_regression=False, derivatives=['func_preproc'], - quality_checked=True, url=None, verbose=1, **kwargs): + quality_checked=True, url=None, verbose=1, + legacy_format=True, **kwargs): """Fetch ABIDE dataset. Fetch the Autism Brain Imaging Data Exchange (ABIDE) dataset wrt criteria @@ -883,6 +892,7 @@ def fetch_abide_pcp(data_dir=None, n_subjects=None, pipeline='cpac', passed quality assessment for all raters. Default=True. %(url)s %(verbose)s + %(legacy_format)s kwargs : parameter list, optional Any extra keyword argument will be used to filter downloaded subjects according to the CSV phenotypic file. Some examples of filters are @@ -998,6 +1008,9 @@ def fetch_abide_pcp(data_dir=None, n_subjects=None, pipeline='cpac', file_ids = file_ids[:n_subjects] pheno = pheno[:n_subjects] + if legacy_format: + pheno = pheno.to_records() + results['description'] = _get_dataset_descr(dataset_name) results['phenotypic'] = pheno for derivative in derivatives: From 539ab522929c470ba677e290438cec95468d94b8 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Wed, 19 Jan 2022 12:35:41 +0100 Subject: [PATCH 07/44] Iter --- nilearn/datasets/struct.py | 8 ++++-- nilearn/datasets/tests/test_func.py | 40 +++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/nilearn/datasets/struct.py b/nilearn/datasets/struct.py index 3e589375cb..5808ff3f9b 100644 --- a/nilearn/datasets/struct.py +++ b/nilearn/datasets/struct.py @@ -552,7 +552,7 @@ def fetch_icbm152_brain_gm_mask(data_dir=None, threshold=0.2, resume=True, @fill_doc def fetch_oasis_vbm(n_subjects=None, dartel_version=True, data_dir=None, - url=None, resume=True, verbose=1): + url=None, resume=True, verbose=1, legacy_format=True): """Download and load Oasis "cross-sectional MRI" dataset (416 subjects). For more information, see :footcite:`OASISbrain`, @@ -571,6 +571,7 @@ def fetch_oasis_vbm(n_subjects=None, dartel_version=True, data_dir=None, %(url)s %(resume)s %(verbose)s + %(legacy_format)s Returns ------- @@ -740,7 +741,7 @@ def fetch_oasis_vbm(n_subjects=None, dartel_version=True, data_dir=None, # Comparisons to recfromcsv data must be bytes. actual_subjects_ids = [("OAS1" + str.split(os.path.basename(x), - "OAS1")[1][:9]).encode() + "OAS1")[1][:9]) for x in gm_maps] subject_mask = np.asarray([subject_id in actual_subjects_ids for subject_id in csv_data['ID']]) @@ -748,6 +749,9 @@ def fetch_oasis_vbm(n_subjects=None, dartel_version=True, data_dir=None, fdescr = _get_dataset_descr(dataset_name) + if legacy_format: + csv_data = csv_data.to_records() + return Bunch( gray_matter_maps=gm_maps, white_matter_maps=wm_maps, diff --git a/nilearn/datasets/tests/test_func.py b/nilearn/datasets/tests/test_func.py index bd6b6eac66..c46b807d0b 100644 --- a/nilearn/datasets/tests/test_func.py +++ b/nilearn/datasets/tests/test_func.py @@ -165,7 +165,22 @@ def test_fetch_localizer_contrasts(tmp_path, request_mocker, localizer_mocker): ['checkerboard'], n_subjects=2, data_dir=tmp_path, - verbose=1) + verbose=1, + legacy_format=True) + assert not hasattr(dataset, 'anats') + assert not hasattr(dataset, 'tmaps') + assert not hasattr(dataset, 'masks') + assert isinstance(dataset.cmaps[0], str) + assert isinstance(dataset.ext_vars, np.recarray) + assert len(dataset.cmaps) == 2 + assert dataset.ext_vars.size == 2 + + dataset = func.fetch_localizer_contrasts( + ['checkerboard'], + n_subjects=2, + data_dir=tmp_path, + verbose=1, + legacy_format=False) assert not hasattr(dataset, 'anats') assert not hasattr(dataset, 'tmaps') assert not hasattr(dataset, 'masks') @@ -179,7 +194,8 @@ def test_fetch_localizer_contrasts(tmp_path, request_mocker, localizer_mocker): ['checkerboard', 'horizontal checkerboard'], n_subjects=2, data_dir=tmp_path, - verbose=1) + verbose=1, + legacy_format=False) assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.cmaps[0], str) assert len(dataset.cmaps) == 2 * 2 # two contrasts are fetched @@ -193,7 +209,8 @@ def test_fetch_localizer_contrasts(tmp_path, request_mocker, localizer_mocker): get_anats=True, get_masks=True, get_tmaps=True, - verbose=1) + verbose=1, + legacy_format=False) assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.anats[0], str) assert isinstance(dataset.cmaps[0], str) @@ -211,7 +228,8 @@ def test_fetch_localizer_contrasts(tmp_path, request_mocker, localizer_mocker): ['checkerboard'], n_subjects=[2, 3, 5], data_dir=tmp_path, - verbose=1) + verbose=1, + legacy_format=False) assert len(dataset2['ext_vars']) == 3 assert len(dataset2.cmaps) == 3 assert (list(dataset2['ext_vars']['participant_id'].values) == ['S02', @@ -225,13 +243,25 @@ def test_fetch_localizer_calculation_task(tmp_path, request_mocker, dataset = func.fetch_localizer_calculation_task( n_subjects=2, data_dir=tmp_path, - verbose=1) + verbose=1, + legacy_format=False) assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.cmaps[0], str) assert len(dataset['ext_vars']) == 2 assert len(dataset.cmaps) == 2 assert dataset.description != '' + dataset = func.fetch_localizer_calculation_task( + n_subjects=2, + data_dir=tmp_path, + verbose=1, + legacy_format=True) + assert isinstance(dataset.ext_vars, np.recarray) + assert isinstance(dataset.cmaps[0], str) + assert dataset.ext_vars.size == 2 + assert len(dataset.cmaps) == 2 + assert dataset.description != '' + def test_fetch_localizer_button_task(tmp_path, request_mocker, localizer_mocker): From c74c35662a85bc120dc624675c69ede768e7a7c7 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Wed, 19 Jan 2022 13:55:10 +0100 Subject: [PATCH 08/44] Fix test --- nilearn/datasets/tests/test_struct.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/nilearn/datasets/tests/test_struct.py b/nilearn/datasets/tests/test_struct.py index 798e47f806..10147a2742 100644 --- a/nilearn/datasets/tests/test_struct.py +++ b/nilearn/datasets/tests/test_struct.py @@ -110,27 +110,37 @@ def _make_oasis_data(dartel=True): return dict_to_archive(data) -def test_fetch_oasis_vbm(tmp_path, request_mocker): +@pytest.mark.parametrize('legacy_format', [True, False]) +def test_fetch_oasis_vbm(tmp_path, request_mocker, legacy_format): request_mocker.url_mapping["*archive_dartel.tgz*"] = _make_oasis_data() request_mocker.url_mapping["*archive.tgz*"] = _make_oasis_data(False) dataset = struct.fetch_oasis_vbm( - data_dir=str(tmp_path), verbose=0) + data_dir=str(tmp_path), verbose=0, legacy_format=legacy_format + ) assert len(dataset.gray_matter_maps) == 403 assert len(dataset.white_matter_maps) == 403 assert isinstance(dataset.gray_matter_maps[0], str) assert isinstance(dataset.white_matter_maps[0], str) - assert isinstance(dataset.ext_vars, pd.DataFrame) + if legacy_format: + assert isinstance(dataset.ext_vars, np.recarray) + else: + assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.data_usage_agreement, str) assert request_mocker.url_count == 1 - dataset = struct.fetch_oasis_vbm(data_dir=str(tmp_path), - dartel_version=False, verbose=0) + dataset = struct.fetch_oasis_vbm( + data_dir=str(tmp_path), dartel_version=False, verbose=0, + legacy_format=legacy_format + ) assert len(dataset.gray_matter_maps) == 415 assert len(dataset.white_matter_maps) == 415 assert isinstance(dataset.gray_matter_maps[0], str) assert isinstance(dataset.white_matter_maps[0], str) - assert isinstance(dataset.ext_vars, pd.DataFrame) + if legacy_format: + assert isinstance(dataset.ext_vars, np.recarray) + else: + assert isinstance(dataset.ext_vars, pd.DataFrame) assert isinstance(dataset.data_usage_agreement, str) assert request_mocker.url_count == 2 assert dataset.description != '' From 0a0b98bb7242f4b2b4aac15031d4eabd65c2fdd9 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Wed, 19 Jan 2022 14:18:47 +0100 Subject: [PATCH 09/44] Fix other test --- nilearn/datasets/tests/test_atlas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nilearn/datasets/tests/test_atlas.py b/nilearn/datasets/tests/test_atlas.py index ed4ee35f53..2d509233e8 100644 --- a/nilearn/datasets/tests/test_atlas.py +++ b/nilearn/datasets/tests/test_atlas.py @@ -359,7 +359,7 @@ def test_fetch_atlas_destrieux_2009(tmp_path, request_mocker, lateralized): def test_fetch_atlas_msdl(tmp_path, request_mocker): labels = pd.DataFrame( {"x": [1.5, 1.2], "y": [1.5, 1.3], - "z": [1.5, 1.4], "name": ["Aud", "DMN"], "net_name": ["Aud", "DMN"]}) + "z": [1.5, 1.4], "name": ["Aud", "DMN"], "net name": ["Aud", "DMN"]}) root = Path("MSDL_rois") archive = {root / "msdl_rois_labels.csv": labels.to_csv(index=False), root / "msdl_rois.nii": "", From 8ec02f91366e888f367cfb7be006855f1c245303 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Wed, 19 Jan 2022 14:59:22 +0100 Subject: [PATCH 10/44] Iter --- nilearn/datasets/atlas.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/nilearn/datasets/atlas.py b/nilearn/datasets/atlas.py index fd7e2d0082..90132c3620 100644 --- a/nilearn/datasets/atlas.py +++ b/nilearn/datasets/atlas.py @@ -73,6 +73,8 @@ def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, the regions. The length of the label array corresponds to the number of dimensions requested. ``data.labels[i]`` is the label corresponding to volume ``i`` in the 'maps' image. + If ``legacy_format`` is set to ``False``, this is a + :class:`pandas.DataFrame`. - 'description': :obj:`str`, general description of the dataset. References @@ -239,6 +241,8 @@ def fetch_atlas_destrieux_2009(lateralized=True, data_dir=None, url=None, indices in the list of labels. - 'labels': :class:`numpy.recarray`, rec array containing the names of the ROIs. + If ``legacy_format`` is set to ``False``, this is a + :class:`pandas.DataFrame`. - 'description': :obj:`str`, description of the atlas. References @@ -729,7 +733,9 @@ def fetch_atlas_msdl(data_dir=None, url=None, resume=True, verbose=1): warnings.filterwarnings('ignore', module='numpy', category=FutureWarning) region_coords = csv_data[['x', 'y', 'z']].values.tolist() - net_names = [net_name.strip() for net_name in csv_data['net name'].tolist()] + net_names = [ + net_name.strip() for net_name in csv_data['net name'].tolist() + ] fdescr = _get_dataset_descr(dataset_name) return Bunch(maps=files[1], labels=labels, region_coords=region_coords, @@ -1207,6 +1213,8 @@ def fetch_coords_dosenbach_2010(ordered_regions=True, legacy_format=True): - 'rois': :class:`numpy.recarray`, rec array with the coordinates of the 160 ROIs in :term:`MNI` space. + If ``legacy_format`` is set to ``False``, this is a + :class:`pandas.DataFrame`. - 'labels': :class:`numpy.ndarray` of :obj:`str`, list of label names for the 160 ROIs. - 'networks': :class:`numpy.ndarray` of :obj:`str`, list of network @@ -1271,6 +1279,8 @@ def fetch_coords_seitzman_2018(ordered_regions=True, legacy_format=True): - 'rois': :class:`numpy.recarray`, rec array with the coordinates of the 300 ROIs in :term:`MNI` space. + If ``legacy_format`` is set to ``False``, this is a + :class:`pandas.DataFrame`. - 'radius': :class:`numpy.ndarray` of :obj:`int`, radius of each ROI in mm. - 'networks': :class:`numpy.ndarray` of :obj:`str`, names of the @@ -1317,9 +1327,10 @@ def fetch_coords_seitzman_2018(ordered_regions=True, legacy_format=True): rois = rois.to_records() params = dict(rois=rois[['x', 'y', 'z']], - radius=rois['radius'], - networks=rois['network'], - regions=rois['region'], description=fdescr) + radius=np.array(rois['radius']), + networks=np.array(rois['network']), + regions=np.array(rois['region']), + description=fdescr) return Bunch(**params) From 93f36dd2004aac441eabc92c8b30575b708d119d Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Thu, 20 Jan 2022 13:17:40 +0100 Subject: [PATCH 11/44] Add warnings --- nilearn/datasets/atlas.py | 11 +++++++++++ nilearn/datasets/func.py | 9 +++++++++ nilearn/datasets/struct.py | 6 ++++++ 3 files changed, 26 insertions(+) diff --git a/nilearn/datasets/atlas.py b/nilearn/datasets/atlas.py index 90132c3620..8176b4a80d 100644 --- a/nilearn/datasets/atlas.py +++ b/nilearn/datasets/atlas.py @@ -21,6 +21,12 @@ _TALAIRACH_LEVELS = ['hemisphere', 'lobe', 'gyrus', 'tissue', 'ba'] +LEGACY_FORMAT_MSG = ( + "`legacy_format` will default to `False` in release 0.11. " + "Dataset fetchers will then return pandas dataframes instead " + "of recarrays." +) + @fill_doc def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, @@ -119,6 +125,7 @@ def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, files_ = _fetch_files(data_dir, files, verbose=verbose) labels = pd.read_csv(files_[0]) if legacy_format: + warnings.warn(LEGACY_FORMAT_MSG) labels = labels.to_records() # README @@ -273,6 +280,7 @@ def fetch_atlas_destrieux_2009(lateralized=True, data_dir=None, url=None, labels=pd.read_csv(files_[0], index_col=0)) if legacy_format: + warnings.warn(LEGACY_FORMAT_MSG) params['labels'] = params['labels'].to_records() with open(files_[2], 'r') as rst_file: @@ -775,6 +783,7 @@ def fetch_coords_power_2011(legacy_format=True): csv = os.path.join(package_directory, "data", "power_2011.csv") params = dict(rois=pd.read_csv(csv), description=fdescr) if legacy_format: + warnings.warn(LEGACY_FORMAT_MSG) params['rois'] = params['rois'].to_records() return Bunch(**params) @@ -1245,6 +1254,7 @@ def fetch_coords_dosenbach_2010(ordered_regions=True, legacy_format=True): networks=out_csv['network'], description=fdescr) if legacy_format: + warnings.warn(LEGACY_FORMAT_MSG) params['rois'] = params['rois'].to_records() return Bunch(**params) @@ -1324,6 +1334,7 @@ def fetch_coords_seitzman_2018(ordered_regions=True, legacy_format=True): rois = rois.sort_values(by=['network', 'y']) if legacy_format: + warnings.warn(LEGACY_FORMAT_MSG) rois = rois.to_records() params = dict(rois=rois[['x', 'y', 'z']], diff --git a/nilearn/datasets/func.py b/nilearn/datasets/func.py index 517d438314..1f1260286a 100644 --- a/nilearn/datasets/func.py +++ b/nilearn/datasets/func.py @@ -30,6 +30,13 @@ from nilearn.image import get_data +LEGACY_FORMAT_MSG = ( + "`legacy_format` will default to `False` in release 0.11. " + "Dataset fetchers will then return pandas dataframes instead " + "of recarrays." + ) + + @fill_doc def fetch_haxby(data_dir=None, subjects=(2,), fetch_stimuli=False, url=None, resume=True, verbose=1): @@ -754,6 +761,7 @@ def _is_valid_path(path, index, verbose): subjects_indices.append(subject_names.index(name)) csv_data = csv_data.iloc[subjects_indices] if legacy_format: + warnings.warn(LEGACY_FORMAT_MSG) csv_data = csv_data.to_records() return Bunch(ext_vars=csv_data, description=fdescr, **files) @@ -1009,6 +1017,7 @@ def fetch_abide_pcp(data_dir=None, n_subjects=None, pipeline='cpac', pheno = pheno[:n_subjects] if legacy_format: + warnings.warn(LEGACY_FORMAT_MSG) pheno = pheno.to_records() results['description'] = _get_dataset_descr(dataset_name) diff --git a/nilearn/datasets/struct.py b/nilearn/datasets/struct.py index 5808ff3f9b..a2b4d8f401 100644 --- a/nilearn/datasets/struct.py +++ b/nilearn/datasets/struct.py @@ -31,6 +31,11 @@ "mni_icbm152_wm_tal_nlin_sym_09a_converted.nii.gz") FSAVERAGE5_PATH = os.path.join(_package_directory, "data", "fsaverage5") +LEGACY_FORMAT_MSG = ( + "`legacy_format` will default to `False` in release 0.11. " + "Dataset fetchers will then return pandas dataframes instead " + "of recarrays." +) # workaround for # https://github.com/nilearn/nilearn/pull/2738#issuecomment-869018842 @@ -750,6 +755,7 @@ def fetch_oasis_vbm(n_subjects=None, dartel_version=True, data_dir=None, fdescr = _get_dataset_descr(dataset_name) if legacy_format: + warnings.warn(LEGACY_FORMAT_MSG) csv_data = csv_data.to_records() return Bunch( From 1d0eaba8517b5a871c71660003ae680c948644b8 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Thu, 20 Jan 2022 13:34:22 +0100 Subject: [PATCH 12/44] Fix PEP8 --- nilearn/datasets/func.py | 8 ++++---- nilearn/datasets/struct.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nilearn/datasets/func.py b/nilearn/datasets/func.py index 1f1260286a..f57e637701 100644 --- a/nilearn/datasets/func.py +++ b/nilearn/datasets/func.py @@ -31,10 +31,10 @@ LEGACY_FORMAT_MSG = ( - "`legacy_format` will default to `False` in release 0.11. " - "Dataset fetchers will then return pandas dataframes instead " - "of recarrays." - ) + "`legacy_format` will default to `False` in release 0.11. " + "Dataset fetchers will then return pandas dataframes instead " + "of recarrays." +) @fill_doc diff --git a/nilearn/datasets/struct.py b/nilearn/datasets/struct.py index a2b4d8f401..4d34e62e70 100644 --- a/nilearn/datasets/struct.py +++ b/nilearn/datasets/struct.py @@ -32,9 +32,9 @@ FSAVERAGE5_PATH = os.path.join(_package_directory, "data", "fsaverage5") LEGACY_FORMAT_MSG = ( - "`legacy_format` will default to `False` in release 0.11. " - "Dataset fetchers will then return pandas dataframes instead " - "of recarrays." + "`legacy_format` will default to `False` in release 0.11. " + "Dataset fetchers will then return pandas dataframes instead " + "of recarrays." ) # workaround for From 4264ab23aac3543b23c7ea7090cac536b54419d5 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Mon, 24 Jan 2022 12:02:54 +0100 Subject: [PATCH 13/44] Address Jerome's reviews --- nilearn/datasets/atlas.py | 22 +++++++++++----------- nilearn/datasets/func.py | 14 +++++++------- nilearn/datasets/struct.py | 13 +++++++------ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/nilearn/datasets/atlas.py b/nilearn/datasets/atlas.py index 8176b4a80d..c8d1a8a3a3 100644 --- a/nilearn/datasets/atlas.py +++ b/nilearn/datasets/atlas.py @@ -21,10 +21,10 @@ _TALAIRACH_LEVELS = ['hemisphere', 'lobe', 'gyrus', 'tissue', 'ba'] -LEGACY_FORMAT_MSG = ( +_LEGACY_FORMAT_MSG = ( "`legacy_format` will default to `False` in release 0.11. " - "Dataset fetchers will then return pandas dataframes instead " - "of recarrays." + "Dataset fetchers will then return pandas dataframes by default " + "instead of recarrays." ) @@ -125,8 +125,8 @@ def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, files_ = _fetch_files(data_dir, files, verbose=verbose) labels = pd.read_csv(files_[0]) if legacy_format: - warnings.warn(LEGACY_FORMAT_MSG) - labels = labels.to_records() + warnings.warn(_LEGACY_FORMAT_MSG) + labels = labels.to_records(index=False) # README readme_files = [('README.md', 'https://osf.io/4k9bf/download', @@ -280,7 +280,7 @@ def fetch_atlas_destrieux_2009(lateralized=True, data_dir=None, url=None, labels=pd.read_csv(files_[0], index_col=0)) if legacy_format: - warnings.warn(LEGACY_FORMAT_MSG) + warnings.warn(_LEGACY_FORMAT_MSG) params['labels'] = params['labels'].to_records() with open(files_[2], 'r') as rst_file: @@ -783,8 +783,8 @@ def fetch_coords_power_2011(legacy_format=True): csv = os.path.join(package_directory, "data", "power_2011.csv") params = dict(rois=pd.read_csv(csv), description=fdescr) if legacy_format: - warnings.warn(LEGACY_FORMAT_MSG) - params['rois'] = params['rois'].to_records() + warnings.warn(_LEGACY_FORMAT_MSG) + params['rois'] = params['rois'].to_records(index=False) return Bunch(**params) @@ -1254,8 +1254,8 @@ def fetch_coords_dosenbach_2010(ordered_regions=True, legacy_format=True): networks=out_csv['network'], description=fdescr) if legacy_format: - warnings.warn(LEGACY_FORMAT_MSG) - params['rois'] = params['rois'].to_records() + warnings.warn(_LEGACY_FORMAT_MSG) + params['rois'] = params['rois'].to_records(index=False) return Bunch(**params) @@ -1334,7 +1334,7 @@ def fetch_coords_seitzman_2018(ordered_regions=True, legacy_format=True): rois = rois.sort_values(by=['network', 'y']) if legacy_format: - warnings.warn(LEGACY_FORMAT_MSG) + warnings.warn(_LEGACY_FORMAT_MSG) rois = rois.to_records() params = dict(rois=rois[['x', 'y', 'z']], diff --git a/nilearn/datasets/func.py b/nilearn/datasets/func.py index f57e637701..f67abcd700 100644 --- a/nilearn/datasets/func.py +++ b/nilearn/datasets/func.py @@ -30,10 +30,10 @@ from nilearn.image import get_data -LEGACY_FORMAT_MSG = ( +_LEGACY_FORMAT_MSG = ( "`legacy_format` will default to `False` in release 0.11. " - "Dataset fetchers will then return pandas dataframes instead " - "of recarrays." + "Dataset fetchers will then return pandas dataframes by default " + "instead of recarrays." ) @@ -761,8 +761,8 @@ def _is_valid_path(path, index, verbose): subjects_indices.append(subject_names.index(name)) csv_data = csv_data.iloc[subjects_indices] if legacy_format: - warnings.warn(LEGACY_FORMAT_MSG) - csv_data = csv_data.to_records() + warnings.warn(_LEGACY_FORMAT_MSG) + csv_data = csv_data.to_records(index=False) return Bunch(ext_vars=csv_data, description=fdescr, **files) @@ -1017,8 +1017,8 @@ def fetch_abide_pcp(data_dir=None, n_subjects=None, pipeline='cpac', pheno = pheno[:n_subjects] if legacy_format: - warnings.warn(LEGACY_FORMAT_MSG) - pheno = pheno.to_records() + warnings.warn(_LEGACY_FORMAT_MSG) + pheno = pheno.to_records(index=False) results['description'] = _get_dataset_descr(dataset_name) results['phenotypic'] = pheno diff --git a/nilearn/datasets/struct.py b/nilearn/datasets/struct.py index 4d34e62e70..44bcd46f31 100644 --- a/nilearn/datasets/struct.py +++ b/nilearn/datasets/struct.py @@ -31,10 +31,10 @@ "mni_icbm152_wm_tal_nlin_sym_09a_converted.nii.gz") FSAVERAGE5_PATH = os.path.join(_package_directory, "data", "fsaverage5") -LEGACY_FORMAT_MSG = ( +_LEGACY_FORMAT_MSG = ( "`legacy_format` will default to `False` in release 0.11. " - "Dataset fetchers will then return pandas dataframes instead " - "of recarrays." + "Dataset fetchers will then return pandas dataframes by default " + "instead of recarrays." ) # workaround for @@ -751,12 +751,13 @@ def fetch_oasis_vbm(n_subjects=None, dartel_version=True, data_dir=None, subject_mask = np.asarray([subject_id in actual_subjects_ids for subject_id in csv_data['ID']]) csv_data = csv_data[subject_mask] - + csv_data = csv_data.rename(columns={c: c.lower() for c in csv_data.columns}) + csv_data = csv_data.rename(columns={c: c.replace("/", "") for c in csv_data.columns}) fdescr = _get_dataset_descr(dataset_name) if legacy_format: - warnings.warn(LEGACY_FORMAT_MSG) - csv_data = csv_data.to_records() + warnings.warn(_LEGACY_FORMAT_MSG) + csv_data = csv_data.to_records(index=False) return Bunch( gray_matter_maps=gm_maps, From 3be012341ee2911011383cd58f53edad2af82a24 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Mon, 24 Jan 2022 12:24:51 +0100 Subject: [PATCH 14/44] Fix PEP8 --- nilearn/datasets/struct.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nilearn/datasets/struct.py b/nilearn/datasets/struct.py index 44bcd46f31..19dbd112fc 100644 --- a/nilearn/datasets/struct.py +++ b/nilearn/datasets/struct.py @@ -751,8 +751,12 @@ def fetch_oasis_vbm(n_subjects=None, dartel_version=True, data_dir=None, subject_mask = np.asarray([subject_id in actual_subjects_ids for subject_id in csv_data['ID']]) csv_data = csv_data[subject_mask] - csv_data = csv_data.rename(columns={c: c.lower() for c in csv_data.columns}) - csv_data = csv_data.rename(columns={c: c.replace("/", "") for c in csv_data.columns}) + csv_data = csv_data.rename( + columns={c: c.lower() for c in csv_data.columns} + ) + csv_data = csv_data.rename( + columns={c: c.replace("/", "") for c in csv_data.columns} + ) fdescr = _get_dataset_descr(dataset_name) if legacy_format: From 8455f929c4c0245fbc0adb0522123fe3879fa617 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Mon, 24 Jan 2022 14:45:44 +0100 Subject: [PATCH 15/44] convert to lower case in fetch_atlas_difumo --- nilearn/datasets/atlas.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nilearn/datasets/atlas.py b/nilearn/datasets/atlas.py index c8d1a8a3a3..b5f308fb33 100644 --- a/nilearn/datasets/atlas.py +++ b/nilearn/datasets/atlas.py @@ -124,6 +124,7 @@ def fetch_atlas_difumo(dimension=64, resolution_mm=2, data_dir=None, # Download the zip file, first files_ = _fetch_files(data_dir, files, verbose=verbose) labels = pd.read_csv(files_[0]) + labels = labels.rename(columns={c: c.lower() for c in labels.columns}) if legacy_format: warnings.warn(_LEGACY_FORMAT_MSG) labels = labels.to_records(index=False) From e558a2531499593a8089471a3c8e319499320419 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Tue, 25 Jan 2022 17:00:14 +0100 Subject: [PATCH 16/44] [circle full] Add whatsnew. --- doc/whats_new.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/whats_new.rst b/doc/whats_new.rst index f2f24bf67a..e5dd6f01c3 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -157,6 +157,12 @@ Changes - Descriptions of datasets retrieved with fetchers from :mod:`nilearn.datasets` are now python strings rather than `bytes`. Therefore, decoding the descriptions is no longer necessary. +- Dataset fetchers returning a :class:`numpy.recarray` can now return a + :class:`pandas.DataFrame` instead. These fetchers now have a ``legacy_format`` optional + argument defaulting to ``True`` for backward compatibility. Users will be warned that + this parameter will default to ``False`` in release 0.11.0, making + :class:`pandas.DataFrame` the default return type instead or :class:`numpy.recarray`. + (See PR `#2829 `_). .. _v0.8.1: From ba553c262e864eb554279d7cb5f040b5f0fcdda3 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Tue, 25 Jan 2022 18:50:13 +0100 Subject: [PATCH 17/44] Fix --- nilearn/datasets/atlas.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nilearn/datasets/atlas.py b/nilearn/datasets/atlas.py index b5f308fb33..b4dee2c7b9 100644 --- a/nilearn/datasets/atlas.py +++ b/nilearn/datasets/atlas.py @@ -783,6 +783,9 @@ def fetch_coords_power_2011(legacy_format=True): package_directory = os.path.dirname(os.path.abspath(__file__)) csv = os.path.join(package_directory, "data", "power_2011.csv") params = dict(rois=pd.read_csv(csv), description=fdescr) + params['rois'] = params['rois'].rename( + columns={c: c.lower() for c in params['rois'].columns} + ) if legacy_format: warnings.warn(_LEGACY_FORMAT_MSG) params['rois'] = params['rois'].to_records(index=False) From 0c7ff85b7e5695de770012ae25957ba281f2148b Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Tue, 25 Jan 2022 18:51:08 +0100 Subject: [PATCH 18/44] [circle full] remove deprecation warning from example --- examples/03_connectivity/plot_sphere_based_connectome.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/03_connectivity/plot_sphere_based_connectome.py b/examples/03_connectivity/plot_sphere_based_connectome.py index 5bbb053bec..f184ad053a 100644 --- a/examples/03_connectivity/plot_sphere_based_connectome.py +++ b/examples/03_connectivity/plot_sphere_based_connectome.py @@ -158,7 +158,7 @@ # # First we fetch the coordinates of the Power atlas -power = datasets.fetch_coords_power_2011() +power = datasets.fetch_coords_power_2011(legacy_format=False) print('Power atlas comes with {0}.'.format(power.keys())) @@ -306,7 +306,7 @@ # ------------------------------------------- # # We repeat the same steps for Dosenbach's atlas. -dosenbach = datasets.fetch_coords_dosenbach_2010() +dosenbach = datasets.fetch_coords_dosenbach_2010(legacy_format=False) coords = np.vstack(( dosenbach.rois['x'], From b1a86a3a31e57cf57af3dfa8ee13ad75178e1e5c Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Tue, 25 Jan 2022 20:50:42 +0100 Subject: [PATCH 19/44] Fix examples --- .../01_plotting/plot_3d_map_to_surface_projection.py | 2 +- examples/01_plotting/plot_dim_plotting.py | 3 ++- examples/01_plotting/plot_prob_atlas.py | 5 +++-- examples/02_decoding/plot_oasis_vbm.py | 6 ++++-- examples/02_decoding/plot_oasis_vbm_space_net.py | 4 +++- examples/03_connectivity/plot_atlas_comparison.py | 5 +++-- examples/05_glm_second_level/plot_oasis.py | 6 ++++-- .../plot_proportion_activated_voxels.py | 7 ++++--- .../plot_second_level_association_test.py | 10 +++++++--- .../plot_second_level_one_sample_test.py | 6 ++++-- .../plot_second_level_two_sample_test.py | 8 ++++++-- examples/05_glm_second_level/plot_thresholding.py | 3 ++- .../plot_localizer_mass_univariate_methods.py | 10 +++++++--- examples/07_advanced/plot_localizer_simple_analysis.py | 3 ++- 14 files changed, 52 insertions(+), 26 deletions(-) diff --git a/examples/01_plotting/plot_3d_map_to_surface_projection.py b/examples/01_plotting/plot_3d_map_to_surface_projection.py index 76cca8faea..6cb001e6d2 100644 --- a/examples/01_plotting/plot_3d_map_to_surface_projection.py +++ b/examples/01_plotting/plot_3d_map_to_surface_projection.py @@ -209,7 +209,7 @@ # averaging the labels between neighboring regions. Using nearest-neighbor # interpolation with zero radius will achieve this. -destrieux = datasets.fetch_atlas_destrieux_2009() +destrieux = datasets.fetch_atlas_destrieux_2009(legacy_format=False) view = plotting.view_img_on_surf( destrieux.maps, diff --git a/examples/01_plotting/plot_dim_plotting.py b/examples/01_plotting/plot_dim_plotting.py index 7f11b04031..fff80e5e3a 100644 --- a/examples/01_plotting/plot_dim_plotting.py +++ b/examples/01_plotting/plot_dim_plotting.py @@ -19,11 +19,12 @@ from nilearn import datasets -localizer_dataset = datasets.fetch_localizer_button_task() +localizer_dataset = datasets.fetch_localizer_button_task(legacy_format=False) # Contrast map of motor task localizer_tmap_filename = localizer_dataset.tmap # Subject specific anatomical image localizer_anat_filename = localizer_dataset.anat + ########################################################################### # Plotting with enhancement of background image with dim=-.5 # -------------------------------------------------------------------------- diff --git a/examples/01_plotting/plot_prob_atlas.py b/examples/01_plotting/plot_prob_atlas.py index ab38c45388..0d90599304 100644 --- a/examples/01_plotting/plot_prob_atlas.py +++ b/examples/01_plotting/plot_prob_atlas.py @@ -46,8 +46,9 @@ # Dictionaries of Functional Modes (“DiFuMo”) atlas dim = 64 res = 2 -difumo = datasets.fetch_atlas_difumo(dimension=dim, - resolution_mm=res) +difumo = datasets.fetch_atlas_difumo( + dimension=dim, resolution_mm=res, legacy_format=False +) # Visualization from nilearn import plotting diff --git a/examples/02_decoding/plot_oasis_vbm.py b/examples/02_decoding/plot_oasis_vbm.py index e438554b07..2dabca6f96 100644 --- a/examples/02_decoding/plot_oasis_vbm.py +++ b/examples/02_decoding/plot_oasis_vbm.py @@ -56,9 +56,11 @@ ############################################################################ # Load Oasis dataset # ------------------- -oasis_dataset = datasets.fetch_oasis_vbm(n_subjects=n_subjects) +oasis_dataset = datasets.fetch_oasis_vbm( + n_subjects=n_subjects, legacy_format=False +) gray_matter_map_filenames = oasis_dataset.gray_matter_maps -age = oasis_dataset.ext_vars['age'].astype(float) +age = oasis_dataset.ext_vars['age'].values # Split data into training set and test set from sklearn.model_selection import train_test_split diff --git a/examples/02_decoding/plot_oasis_vbm_space_net.py b/examples/02_decoding/plot_oasis_vbm_space_net.py index 4b6749edc6..5b6019fc10 100644 --- a/examples/02_decoding/plot_oasis_vbm_space_net.py +++ b/examples/02_decoding/plot_oasis_vbm_space_net.py @@ -16,7 +16,9 @@ import numpy as np from nilearn import datasets n_subjects = 200 # increase this number if you have more RAM on your box -dataset_files = datasets.fetch_oasis_vbm(n_subjects=n_subjects) +dataset_files = datasets.fetch_oasis_vbm( + n_subjects=n_subjects, legacy_format=False +) age = dataset_files.ext_vars['age'].astype(float) age = np.array(age) gm_imgs = np.array(dataset_files.gray_matter_maps) diff --git a/examples/03_connectivity/plot_atlas_comparison.py b/examples/03_connectivity/plot_atlas_comparison.py index 374531b2da..1c2bd68867 100644 --- a/examples/03_connectivity/plot_atlas_comparison.py +++ b/examples/03_connectivity/plot_atlas_comparison.py @@ -118,8 +118,9 @@ def lag_correlation(time_series, lag): # ----------------------------------------------------------------- dim = 64 -difumo = datasets.fetch_atlas_difumo(dimension=dim, - resolution_mm=2) +difumo = datasets.fetch_atlas_difumo( + dimension=dim, resolution_mm=2, legacy_format=False +) ########################################################################## # Iterate over fetched atlases to extract coordinates - probabilistic diff --git a/examples/05_glm_second_level/plot_oasis.py b/examples/05_glm_second_level/plot_oasis.py index c79dfd28d1..1e5dda05d8 100644 --- a/examples/05_glm_second_level/plot_oasis.py +++ b/examples/05_glm_second_level/plot_oasis.py @@ -33,13 +33,15 @@ # ------------------ from nilearn import datasets -oasis_dataset = datasets.fetch_oasis_vbm(n_subjects=n_subjects) +oasis_dataset = datasets.fetch_oasis_vbm( + n_subjects=n_subjects, legacy_format=False +) gray_matter_map_filenames = oasis_dataset.gray_matter_maps age = oasis_dataset.ext_vars['age'].astype(float) ############################################################################### # Sex is encoded as 'M' or 'F'. Hence, we make it a binary variable. -sex = oasis_dataset.ext_vars['mf'] == b'F' +sex = oasis_dataset.ext_vars['mf'] == 'F' ############################################################################### # Print basic information on the dataset. diff --git a/examples/05_glm_second_level/plot_proportion_activated_voxels.py b/examples/05_glm_second_level/plot_proportion_activated_voxels.py index 431ee3060d..6a17955303 100644 --- a/examples/05_glm_second_level/plot_proportion_activated_voxels.py +++ b/examples/05_glm_second_level/plot_proportion_activated_voxels.py @@ -21,9 +21,10 @@ # BOLD activity estimate divided by the uncertainty about this estimate. from nilearn.datasets import fetch_localizer_contrasts n_subjects = 16 -data = fetch_localizer_contrasts(["left vs right button press"], n_subjects, - get_tmaps=True) - +data = fetch_localizer_contrasts( + ["left vs right button press"], n_subjects, + get_tmaps=True, legacy_format=False +) from nilearn import plotting ############################################################################ diff --git a/examples/05_glm_second_level/plot_second_level_association_test.py b/examples/05_glm_second_level/plot_second_level_association_test.py index 989ae7603c..5dffedd56e 100644 --- a/examples/05_glm_second_level/plot_second_level_association_test.py +++ b/examples/05_glm_second_level/plot_second_level_association_test.py @@ -19,7 +19,9 @@ from nilearn import datasets n_samples = 94 localizer_dataset = datasets.fetch_localizer_contrasts( - ['left button press (auditory cue)'], n_subjects=n_samples) + ['left button press (auditory cue)'], + n_subjects=n_samples, legacy_format=False +) ############################################################################## # Let's print basic information on the dataset. @@ -34,11 +36,13 @@ ############################################################################## # It is worth to do a auality check and remove subjects with missing values. import numpy as np -mask_quality_check = np.where(tested_var != b'n/a')[0] +mask_quality_check = np.where( + np.logical_not(np.isnan(tested_var)) +)[0] n_samples = mask_quality_check.size contrast_map_filenames = [localizer_dataset.cmaps[i] for i in mask_quality_check] -tested_var = tested_var[mask_quality_check].astype(float).reshape((-1, 1)) +tested_var = tested_var[mask_quality_check].values.reshape((-1, 1)) print("Actual number of subjects after quality check: %d" % n_samples) ############################################################################ diff --git a/examples/05_glm_second_level/plot_second_level_one_sample_test.py b/examples/05_glm_second_level/plot_second_level_one_sample_test.py index a053b51e9e..acea9504e4 100644 --- a/examples/05_glm_second_level/plot_second_level_one_sample_test.py +++ b/examples/05_glm_second_level/plot_second_level_one_sample_test.py @@ -27,8 +27,10 @@ # estimate. from nilearn.datasets import fetch_localizer_contrasts n_subjects = 16 -data = fetch_localizer_contrasts(["left vs right button press"], n_subjects, - get_tmaps=True) +data = fetch_localizer_contrasts( + ["left vs right button press"], n_subjects, + get_tmaps=True, legacy_format=False +) ########################################################################### # Display subject t_maps diff --git a/examples/05_glm_second_level/plot_second_level_two_sample_test.py b/examples/05_glm_second_level/plot_second_level_two_sample_test.py index ad045c576d..4f9264b8b5 100644 --- a/examples/05_glm_second_level/plot_second_level_two_sample_test.py +++ b/examples/05_glm_second_level/plot_second_level_two_sample_test.py @@ -35,9 +35,13 @@ # localizer dataset. n_subjects = 16 sample_vertical = fetch_localizer_contrasts( - ["vertical checkerboard"], n_subjects, get_tmaps=True) + ["vertical checkerboard"], n_subjects, + get_tmaps=True, legacy_format=False +) sample_horizontal = fetch_localizer_contrasts( - ["horizontal checkerboard"], n_subjects, get_tmaps=True) + ["horizontal checkerboard"], n_subjects, + get_tmaps=True, legacy_format=False +) # Implicitly, there is a one-to-one correspondence between the two samples: # the first image of both samples comes from subject S1, the second from subject S2 etc. diff --git a/examples/05_glm_second_level/plot_thresholding.py b/examples/05_glm_second_level/plot_thresholding.py index 3e0edcc532..2e60ebfca8 100644 --- a/examples/05_glm_second_level/plot_thresholding.py +++ b/examples/05_glm_second_level/plot_thresholding.py @@ -18,7 +18,8 @@ from nilearn import datasets n_samples = 20 localizer_dataset = datasets.fetch_localizer_calculation_task( - n_subjects=n_samples) + n_subjects=n_samples, legacy_format=False +) ######################################################################### # Get the set of individual statstical maps (contrast estimates) diff --git a/examples/07_advanced/plot_localizer_mass_univariate_methods.py b/examples/07_advanced/plot_localizer_mass_univariate_methods.py index 75128fe650..02956fc0e9 100644 --- a/examples/07_advanced/plot_localizer_mass_univariate_methods.py +++ b/examples/07_advanced/plot_localizer_mass_univariate_methods.py @@ -29,7 +29,9 @@ # Load Localizer contrast n_samples = 94 localizer_dataset = datasets.fetch_localizer_contrasts( - ['left button press (auditory cue)'], n_subjects=n_samples) + ['left button press (auditory cue)'], + n_subjects=n_samples, legacy_format=False +) # print basic information on the dataset print('First contrast nifti image (3D) is located at: %s' % @@ -37,11 +39,13 @@ tested_var = localizer_dataset.ext_vars['pseudo'] # Quality check / Remove subjects with bad tested variate -mask_quality_check = np.where(tested_var != b'n/a')[0] +mask_quality_check = np.where( + np.logical_not(np.isnan(tested_var)) +)[0] n_samples = mask_quality_check.size contrast_map_filenames = [localizer_dataset.cmaps[i] for i in mask_quality_check] -tested_var = tested_var[mask_quality_check].astype(float).reshape((-1, 1)) +tested_var = tested_var[mask_quality_check].values.reshape((-1, 1)) print("Actual number of subjects after quality check: %d" % n_samples) diff --git a/examples/07_advanced/plot_localizer_simple_analysis.py b/examples/07_advanced/plot_localizer_simple_analysis.py index a1cd1aeb5a..2c91a4d53f 100644 --- a/examples/07_advanced/plot_localizer_simple_analysis.py +++ b/examples/07_advanced/plot_localizer_simple_analysis.py @@ -25,7 +25,8 @@ # Load Localizer contrast n_samples = 20 localizer_dataset = datasets.fetch_localizer_calculation_task( - n_subjects=n_samples) + n_subjects=n_samples, legacy_format=False +) tested_var = np.ones((n_samples, 1)) From 41c8e7bf60abc42186db4ead79e15fc247176aa8 Mon Sep 17 00:00:00 2001 From: Gensollen Date: Mon, 17 Jan 2022 16:03:56 +0100 Subject: [PATCH 20/44] [ENH] Add `cbar_tick_format` to plotting functions (#2859) * enable cbar_tick_format in BaseSlicer * show in examples * Add whatsnew entry * [circle full] test full build * Fix doctrings and kwarg for colorbar and cbar_tick_format * pep8 * Re-add tests and fix rebase issues * Fix PEP8 * [circle full] request full build * plot_roi cbar tick format defaults to integers * escape % * [circle full] request full build --- doc/whats_new.rst | 6 ++ examples/01_plotting/plot_visualization.py | 2 +- examples/plot_single_subject_single_run.py | 4 +- nilearn/plotting/displays/_slicers.py | 14 ++++- nilearn/plotting/img_plotting.py | 63 ++++++++++++++++--- .../test_img_plotting/test_img_plotting.py | 12 ++++ .../tests/test_img_plotting/test_plot_anat.py | 14 +++++ 7 files changed, 100 insertions(+), 15 deletions(-) diff --git a/doc/whats_new.rst b/doc/whats_new.rst index f2f24bf67a..3e47cbb755 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -119,6 +119,12 @@ Enhancements - Importing :mod:`nilearn.plotting` will now raise a warning if the matplotlib backend has been changed from its original value, instead of silently modifying it. +- Function :func:`~nilearn.plotting.plot_img` and deriving functions like + :func:`~nilearn.plotting.plot_anat`, :func:`~nilearn.plotting.plot_stat_map`, or + :func:`~nilearn.plotting.plot_epi` now accept an optional argument + ``cbar_tick_format`` to specify how numbers should be displayed on the colorbar. + This is consistent with the API of surface plotting functions (see release 0.7.1). + The default format is scientific notation. Changes ------- diff --git a/examples/01_plotting/plot_visualization.py b/examples/01_plotting/plot_visualization.py index a52744f313..70b3a47868 100644 --- a/examples/01_plotting/plot_visualization.py +++ b/examples/01_plotting/plot_visualization.py @@ -29,7 +29,7 @@ mean_haxby = mean_img(func_filename) from nilearn.plotting import plot_epi, show -plot_epi(mean_haxby) +plot_epi(mean_haxby, colorbar=True, cbar_tick_format="%i") ############################################################################## # Extracting a brain mask diff --git a/examples/plot_single_subject_single_run.py b/examples/plot_single_subject_single_run.py index 31ecd92244..773fdc93b7 100644 --- a/examples/plot_single_subject_single_run.py +++ b/examples/plot_single_subject_single_run.py @@ -55,8 +55,8 @@ ############################################################################### # We can display the first functional image and the subject's anatomy: from nilearn.plotting import plot_stat_map, plot_anat, plot_img -plot_img(subject_data.func[0]) -plot_anat(subject_data.anat) +plot_img(subject_data.func[0], colorbar=True, cbar_tick_format="%i") +plot_anat(subject_data.anat, colorbar=True, cbar_tick_format="%i") ############################################################################### # Next, we concatenate all the 3D :term:`EPI` image into a single 4D image, diff --git a/nilearn/plotting/displays/_slicers.py b/nilearn/plotting/displays/_slicers.py index de537b7fbf..2ad82152c2 100644 --- a/nilearn/plotting/displays/_slicers.py +++ b/nilearn/plotting/displays/_slicers.py @@ -65,6 +65,7 @@ def __init__(self, cut_coords, axes=None, black_bg=False, self._brain_color = brain_color self._colorbar = False self._colorbar_width = 0.05 * bb.width + self._cbar_tick_format = "%.2g" self._colorbar_margin = dict(left=0.25 * bb.width, right=0.02 * bb.width, top=0.05 * bb.height, @@ -217,8 +218,9 @@ def title(self, text, x=0.01, y=0.99, size=15, color=None, bgcolor=None, ax.set_zorder(1000) @fill_doc - def add_overlay(self, img, threshold=1e-6, colorbar=False, **kwargs): - """Plot a 3D map in all the views. + def add_overlay(self, img, threshold=1e-6, colorbar=False, + cbar_tick_format="%.2g", **kwargs): + """ Plot a 3D map in all the views. Parameters ---------- @@ -235,6 +237,11 @@ def add_overlay(self, img, threshold=1e-6, colorbar=False, **kwargs): Default=1e-6. + cbar_tick_format: str, optional + Controls how to format the tick labels of the colorbar. + Ex: use "%%i" to display as integers. + Default is '%%.2g' for scientific notation. + colorbar : :obj:`bool`, optional If ``True``, display a colorbar on the right of the plots. Default=False. @@ -248,6 +255,7 @@ def add_overlay(self, img, threshold=1e-6, colorbar=False, **kwargs): "colorbar.") else: self._colorbar = colorbar + self._cbar_tick_format = cbar_tick_format img = check_niimg_3d(img) @@ -458,7 +466,7 @@ def _show_colorbar(self, cmap, norm, threshold=None): self._cbar = ColorbarBase( self._colorbar_ax, ticks=ticks, norm=norm, orientation='vertical', cmap=our_cmap, boundaries=bounds, - spacing='proportional', format='%.2g') + spacing='proportional', format=self._cbar_tick_format) self._cbar.ax.set_facecolor(self._brain_color) self._colorbar_ax.yaxis.tick_left() diff --git a/nilearn/plotting/img_plotting.py b/nilearn/plotting/img_plotting.py index 18200b6e0b..532ca5b0a6 100644 --- a/nilearn/plotting/img_plotting.py +++ b/nilearn/plotting/img_plotting.py @@ -124,6 +124,7 @@ def _plot_img_with_bg(img, bg_img=None, cut_coords=None, bg_vmin=None, bg_vmax=None, interpolation="nearest", display_factory=get_slicer, cbar_vmin=None, cbar_vmax=None, + cbar_tick_format="%.2g", brain_color=(0.5, 0.5, 0.5), decimals=False, **kwargs): @@ -201,6 +202,7 @@ def _plot_img_with_bg(img, bg_img=None, cut_coords=None, display.add_overlay(new_img_like(img, data, affine), threshold=threshold, interpolation=interpolation, colorbar=colorbar, vmin=vmin, vmax=vmax, + cbar_tick_format=cbar_tick_format, **kwargs) if annotate: @@ -268,6 +270,7 @@ def _crop_colorbar(cbar, cbar_vmin, cbar_vmax): def plot_img(img, cut_coords=None, output_file=None, display_mode='ortho', figure=None, axes=None, title=None, threshold=None, annotate=True, draw_cross=True, black_bg=False, colorbar=False, + cbar_tick_format="%.2g", resampling_interpolation='continuous', bg_img=None, vmin=None, vmax=None, **kwargs): """ Plot cuts of a given image (by default Frontal, Axial, and Lateral) @@ -291,6 +294,10 @@ def plot_img(img, cut_coords=None, output_file=None, display_mode='ortho', Default=False. %(colorbar)s Default=False. + cbar_tick_format: str, optional + Controls how to format the tick labels of the colorbar. + Ex: use "%%i" to display as integers. + Default is '%%.2g' for scientific notation. %(resampling_interpolation)s Default='continuous'. %(bg_img)s @@ -310,6 +317,7 @@ def plot_img(img, cut_coords=None, output_file=None, display_mode='ortho', draw_cross=draw_cross, resampling_interpolation=resampling_interpolation, black_bg=black_bg, colorbar=colorbar, + cbar_tick_format=cbar_tick_format, bg_img=bg_img, vmin=vmin, vmax=vmax, **kwargs) return display @@ -456,7 +464,8 @@ def plot_anat(anat_img=MNI152TEMPLATE, cut_coords=None, output_file=None, display_mode='ortho', figure=None, axes=None, title=None, annotate=True, threshold=None, draw_cross=True, black_bg='auto', dim='auto', cmap=plt.cm.gray, - vmin=None, vmax=None, **kwargs): + colorbar=False, cbar_tick_format="%.2g", vmin=None, + vmax=None, **kwargs): """Plot cuts of an anatomical image (by default 3 cuts: Frontal, Axial, and Lateral) @@ -482,6 +491,13 @@ def plot_anat(anat_img=MNI152TEMPLATE, cut_coords=None, Default='auto'. %(cmap)s Default=`plt.cm.gray`. + colorbar : boolean, optional + If True, display a colorbar on the right of the plots. + Default=False. + cbar_tick_format: str, optional + Controls how to format the tick labels of the colorbar. + Ex: use "%%i" to display as integers. + Default is '%%.2g' for scientific notation. %(vmin)s %(vmax)s @@ -507,6 +523,7 @@ def plot_anat(anat_img=MNI152TEMPLATE, cut_coords=None, figure=figure, axes=axes, title=title, threshold=threshold, annotate=annotate, draw_cross=draw_cross, black_bg=black_bg, + colorbar=colorbar, cbar_tick_format=cbar_tick_format, vmin=vmin, vmax=vmax, cmap=cmap, **kwargs) return display @@ -515,6 +532,7 @@ def plot_anat(anat_img=MNI152TEMPLATE, cut_coords=None, def plot_epi(epi_img=None, cut_coords=None, output_file=None, display_mode='ortho', figure=None, axes=None, title=None, annotate=True, draw_cross=True, black_bg=True, + colorbar=False, cbar_tick_format="%.2g", cmap=plt.cm.nipy_spectral, vmin=None, vmax=None, **kwargs): """Plot cuts of an EPI image (by default 3 cuts: Frontal, Axial, and Lateral) @@ -533,6 +551,13 @@ def plot_epi(epi_img=None, cut_coords=None, output_file=None, %(draw_cross)s %(black_bg)s Default=True. + colorbar : boolean, optional + If True, display a colorbar on the right of the plots. + Default=False. + cbar_tick_format: str, optional + Controls how to format the tick labels of the colorbar. + Ex: use "%%i" to display as integers. + Default is '%%.2g' for scientific notation. %(cmap)s Default=`plt.cm.nipy_spectral`. %(vmin)s @@ -548,6 +573,7 @@ def plot_epi(epi_img=None, cut_coords=None, output_file=None, figure=figure, axes=axes, title=title, threshold=None, annotate=annotate, draw_cross=draw_cross, black_bg=black_bg, + colorbar=colorbar, cbar_tick_format=cbar_tick_format, cmap=cmap, vmin=vmin, vmax=vmax, **kwargs) return display @@ -604,8 +630,9 @@ def plot_roi(roi_img, bg_img=MNI152TEMPLATE, cut_coords=None, output_file=None, display_mode='ortho', figure=None, axes=None, title=None, annotate=True, draw_cross=True, black_bg='auto', threshold=0.5, alpha=0.7, cmap=plt.cm.gist_ncar, dim='auto', - vmin=None, vmax=None, resampling_interpolation='nearest', - view_type='continuous', linewidths=2.5, **kwargs): + colorbar=False, cbar_tick_format="%i", vmin=None, vmax=None, + resampling_interpolation='nearest', view_type='continuous', + linewidths=2.5, **kwargs): """Plot cuts of an ROI/mask image (by default 3 cuts: Frontal, Axial, and Lateral) @@ -638,6 +665,13 @@ def plot_roi(roi_img, bg_img=MNI152TEMPLATE, cut_coords=None, Default=`plt.cm.gist_ncar`. %(dim)s Default='auto'. + colorbar : boolean, optional + If True, display a colorbar on the right of the plots. + Default=False. + cbar_tick_format: str, optional + Controls how to format the tick labels of the colorbar. + Ex: use "%%.2g" to use scientific notation. + Default is '%%i' to display as integers. %(vmin)s %(vmax)s %(resampling_interpolation)s @@ -684,6 +718,7 @@ def plot_roi(roi_img, bg_img=MNI152TEMPLATE, cut_coords=None, draw_cross=draw_cross, black_bg=black_bg, threshold=threshold, bg_vmin=bg_vmin, bg_vmax=bg_vmax, resampling_interpolation=resampling_interpolation, + colorbar=colorbar, cbar_tick_format=cbar_tick_format, alpha=alpha, cmap=cmap, vmin=vmin, vmax=vmax, **kwargs) if view_type == 'contours': @@ -875,9 +910,9 @@ def plot_prob_atlas(maps_img, bg_img=MNI152TEMPLATE, view_type='auto', @fill_doc def plot_stat_map(stat_map_img, bg_img=MNI152TEMPLATE, cut_coords=None, output_file=None, display_mode='ortho', colorbar=True, - figure=None, axes=None, title=None, threshold=1e-6, - annotate=True, draw_cross=True, black_bg='auto', - cmap=cm.cold_hot, symmetric_cbar="auto", + cbar_tick_format="%.2g", figure=None, axes=None, + title=None, threshold=1e-6, annotate=True, draw_cross=True, + black_bg='auto', cmap=cm.cold_hot, symmetric_cbar="auto", dim='auto', vmax=None, resampling_interpolation='continuous', **kwargs): """Plot cuts of an ROI/mask image (by default 3 cuts: Frontal, Axial, and @@ -897,6 +932,10 @@ def plot_stat_map(stat_map_img, bg_img=MNI152TEMPLATE, cut_coords=None, %(display_mode)s %(colorbar)s Default=True. + cbar_tick_format: str, optional + Controls how to format the tick labels of the colorbar. + Ex: use "%%i" to display as integers. + Default is '%%.2g' for scientific notation. %(figure)s %(axes)s %(title)s @@ -952,7 +991,8 @@ def plot_stat_map(stat_map_img, bg_img=MNI152TEMPLATE, cut_coords=None, figure=figure, axes=axes, title=title, annotate=annotate, draw_cross=draw_cross, black_bg=black_bg, threshold=threshold, bg_vmin=bg_vmin, bg_vmax=bg_vmax, cmap=cmap, vmin=vmin, vmax=vmax, - colorbar=colorbar, cbar_vmin=cbar_vmin, cbar_vmax=cbar_vmax, + colorbar=colorbar, cbar_tick_format=cbar_tick_format, + cbar_vmin=cbar_vmin, cbar_vmax=cbar_vmax, resampling_interpolation=resampling_interpolation, **kwargs) return display @@ -961,6 +1001,7 @@ def plot_stat_map(stat_map_img, bg_img=MNI152TEMPLATE, cut_coords=None, @fill_doc def plot_glass_brain(stat_map_img, output_file=None, display_mode='ortho', colorbar=False, + cbar_tick_format="%.2g", figure=None, axes=None, title=None, threshold='auto', annotate=True, black_bg=False, @@ -996,6 +1037,10 @@ def plot_glass_brain(stat_map_img, 'lzry', 'lyrz'. Default='ortho'. %(colorbar)s Default=False. + cbar_tick_format: str, optional + Controls how to format the tick labels of the colorbar. + Ex: use "%%i" to display as integers. + Default is '%%.2g' for scientific notation. %(figure)s %(axes)s %(title)s @@ -1056,8 +1101,8 @@ def display_factory(display_mode): img=stat_map_img, output_file=output_file, display_mode=display_mode, figure=figure, axes=axes, title=title, annotate=annotate, black_bg=black_bg, threshold=threshold, cmap=cmap, colorbar=colorbar, - display_factory=display_factory, vmin=vmin, vmax=vmax, - cbar_vmin=cbar_vmin, cbar_vmax=cbar_vmax, + cbar_tick_format=cbar_tick_format, display_factory=display_factory, + vmin=vmin, vmax=vmax, cbar_vmin=cbar_vmin, cbar_vmax=cbar_vmax, resampling_interpolation=resampling_interpolation, **kwargs) if stat_map_img is None and 'l' in display.axes: diff --git a/nilearn/plotting/tests/test_img_plotting/test_img_plotting.py b/nilearn/plotting/tests/test_img_plotting/test_img_plotting.py index 7de0324571..3e2a4a0254 100644 --- a/nilearn/plotting/tests/test_img_plotting/test_img_plotting.py +++ b/nilearn/plotting/tests/test_img_plotting/test_img_plotting.py @@ -50,6 +50,18 @@ def test_plot_functions_3d_default_params(plot_func, testdata_3d, tmpdir): # no plt.close() +@pytest.mark.parametrize("plot_func", PLOTTING_FUNCS_3D) +@pytest.mark.parametrize("cbar_tick_format", ["%f", "%i"]) +def test_cbar_tick_format(plot_func, testdata_3d, cbar_tick_format, tmpdir): # noqa + """Test different colorbar tick format with 3D plotting functions.""" + filename = str(tmpdir.join('temp.png')) + plot_func( + testdata_3d['img'], output_file=filename, colorbar=True, + cbar_tick_format=cbar_tick_format + ) + plt.close() + + @pytest.mark.parametrize("plot_func", PLOTTING_FUNCS_4D) def test_plot_functions_4d_default_params(plot_func, testdata_3d, testdata_4d, tmpdir): # noqa """Smoke-test for 4D plotting functions with default arguments.""" diff --git a/nilearn/plotting/tests/test_img_plotting/test_plot_anat.py b/nilearn/plotting/tests/test_img_plotting/test_plot_anat.py index c115b1910e..76067a80d2 100644 --- a/nilearn/plotting/tests/test_img_plotting/test_plot_anat.py +++ b/nilearn/plotting/tests/test_img_plotting/test_plot_anat.py @@ -17,6 +17,20 @@ def test_plot_anat_MNI(anat_img, display_mode, tmpdir): plt.close() +@pytest.mark.parametrize("anat_img", [False, MNI152TEMPLATE]) +@pytest.mark.parametrize("display_mode", ['z', 'ortho']) +@pytest.mark.parametrize("cbar_tick_format", ["%.2g", "%i"]) +def test_plot_anat_colorbar(anat_img, display_mode, cbar_tick_format, tmpdir): + """Tests for plot_anat with MNI template and colorbar.""" + slicer = plot_anat( + anat_img=anat_img, display_mode=display_mode, colorbar=True, + cbar_tick_format=cbar_tick_format + ) + filename = str(tmpdir.join('test.png')) + slicer.savefig(filename) + plt.close() + + def test_plot_anat_3d_img(testdata_3d, tmpdir): # noqa:F811 """Smoke test for plot_anat.""" filename = str(tmpdir.join('test.png')) From 10e179502ff709771fa57d7483246de468746d38 Mon Sep 17 00:00:00 2001 From: Gensollen Date: Tue, 18 Jan 2022 15:55:46 +0100 Subject: [PATCH 21/44] Rename private functions of `permuted_least_squares` to start with '_' (#3131) * rename functions * update test * Fix PEP8 --- .../mass_univariate/permuted_least_squares.py | 35 ++++++++++--------- .../tests/test_permuted_least_squares.py | 4 +-- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/nilearn/mass_univariate/permuted_least_squares.py b/nilearn/mass_univariate/permuted_least_squares.py index 5902349cec..ca2e784912 100644 --- a/nilearn/mass_univariate/permuted_least_squares.py +++ b/nilearn/mass_univariate/permuted_least_squares.py @@ -12,7 +12,8 @@ from scipy import linalg from sklearn.utils import check_random_state -def normalize_matrix_on_axis(m, axis=0): + +def _normalize_matrix_on_axis(m, axis=0): """ Normalize a 2D matrix on an axis. Parameters @@ -33,12 +34,12 @@ def normalize_matrix_on_axis(m, axis=0): -------- >>> import numpy as np >>> from nilearn.mass_univariate.permuted_least_squares import ( - ... normalize_matrix_on_axis) + ... _normalize_matrix_on_axis) >>> X = np.array([[0, 4], [1, 0]]) - >>> normalize_matrix_on_axis(X) + >>> _normalize_matrix_on_axis(X) array([[0., 1.], [1., 0.]]) - >>> normalize_matrix_on_axis(X, axis=1) + >>> _normalize_matrix_on_axis(X, axis=1) array([[0., 1.], [1., 0.]]) @@ -51,13 +52,13 @@ def normalize_matrix_on_axis(m, axis=0): # array transposition preserves the contiguity flag of that array ret = (m.T / np.sqrt(np.sum(m ** 2, axis=0))[:, np.newaxis]).T elif axis == 1: - ret = normalize_matrix_on_axis(m.T).T + ret = _normalize_matrix_on_axis(m.T).T else: raise ValueError('axis(=%d) out of bounds' % axis) return ret -def orthonormalize_matrix(m, tol=1.e-12): +def _orthonormalize_matrix(m, tol=1.e-12): """ Orthonormalize a matrix. Uses a Singular Value Decomposition. @@ -80,14 +81,14 @@ def orthonormalize_matrix(m, tol=1.e-12): -------- >>> import numpy as np >>> from nilearn.mass_univariate.permuted_least_squares import ( - ... orthonormalize_matrix) + ... _orthonormalize_matrix) >>> X = np.array([[1, 2], [0, 1], [1, 1]]) - >>> orthonormalize_matrix(X) + >>> _orthonormalize_matrix(X) array([[-0.81049889, -0.0987837 ], [-0.31970025, -0.75130448], [-0.49079864, 0.65252078]]) >>> X = np.array([[0, 1], [4, 0]]) - >>> orthonormalize_matrix(X) + >>> _orthonormalize_matrix(X) array([[ 0., -1.], [-1., 0.]]) @@ -414,13 +415,13 @@ def permuted_ols(tested_vars, target_vars, confounding_vars=None, ### OLS regression on original data if confounding_vars is not None: # step 1: extract effect of covars from target vars - covars_orthonormalized = orthonormalize_matrix(confounding_vars) + covars_orthonormalized = _orthonormalize_matrix(confounding_vars) if not covars_orthonormalized.flags['C_CONTIGUOUS']: # useful to developer warnings.warn('Confounding variates not C_CONTIGUOUS.') covars_orthonormalized = np.ascontiguousarray( covars_orthonormalized) - targetvars_normalized = normalize_matrix_on_axis( + targetvars_normalized = _normalize_matrix_on_axis( target_vars).T # faster with F-ordered target_vars_chunk if not targetvars_normalized.flags['C_CONTIGUOUS']: # useful to developer @@ -430,19 +431,21 @@ def permuted_ols(tested_vars, target_vars, confounding_vars=None, covars_orthonormalized) targetvars_resid_covars = targetvars_normalized - np.dot( beta_targetvars_covars, covars_orthonormalized.T) - targetvars_resid_covars = normalize_matrix_on_axis( + targetvars_resid_covars = _normalize_matrix_on_axis( targetvars_resid_covars, axis=1) # step 2: extract effect of covars from tested vars - testedvars_normalized = normalize_matrix_on_axis(tested_vars.T, axis=1) + testedvars_normalized = _normalize_matrix_on_axis( + tested_vars.T, axis=1 + ) beta_testedvars_covars = np.dot(testedvars_normalized, covars_orthonormalized) testedvars_resid_covars = testedvars_normalized - np.dot( beta_testedvars_covars, covars_orthonormalized.T) - testedvars_resid_covars = normalize_matrix_on_axis( + testedvars_resid_covars = _normalize_matrix_on_axis( testedvars_resid_covars, axis=1).T.copy() else: - targetvars_resid_covars = normalize_matrix_on_axis(target_vars).T - testedvars_resid_covars = normalize_matrix_on_axis(tested_vars).copy() + targetvars_resid_covars = _normalize_matrix_on_axis(target_vars).T + testedvars_resid_covars = _normalize_matrix_on_axis(tested_vars).copy() covars_orthonormalized = None # check arrays contiguousity (for the sake of code efficiency) if not targetvars_resid_covars.flags['C_CONTIGUOUS']: diff --git a/nilearn/mass_univariate/tests/test_permuted_least_squares.py b/nilearn/mass_univariate/tests/test_permuted_least_squares.py index 866567d8d1..a99275b957 100644 --- a/nilearn/mass_univariate/tests/test_permuted_least_squares.py +++ b/nilearn/mass_univariate/tests/test_permuted_least_squares.py @@ -13,7 +13,7 @@ from nilearn.mass_univariate import permuted_ols from nilearn.mass_univariate.permuted_least_squares import ( - _t_score_with_covars_and_normalized_design, orthonormalize_matrix) + _t_score_with_covars_and_normalized_design, _orthonormalize_matrix) def get_tvalue_with_alternative_library(tested_vars, target_vars, covars=None): @@ -128,7 +128,7 @@ def test_t_score_with_covars_and_normalized_design_withcovar(random_state=0): var2 = var2 / np.sqrt(np.sum(var2 ** 2, 0)) # normalize covars = np.eye(n_samples, 3) # covars is orthogonal covars[3] = -1 # covars is orthogonal to var1 - covars = orthonormalize_matrix(covars) + covars = _orthonormalize_matrix(covars) # nilearn t-score own_score = _t_score_with_covars_and_normalized_design(var1, var2, covars) From b229c9f78cf930f06aed50e4d2af43667cc76ecb Mon Sep 17 00:00:00 2001 From: Gensollen Date: Wed, 19 Jan 2022 10:00:04 +0100 Subject: [PATCH 22/44] [MAINT] Update git protocol in CircleCI fetch step (#3124) * update protocol * try force cleaning * try clearing cache --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index df827b91cf..93de59eeea 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -215,17 +215,17 @@ jobs: steps: - restore_cache: keys: - - source-cache + - source-cache-v2 - checkout - run: name: Complete checkout command: | if ! git remote -v | grep upstream; then - git remote add upstream git://github.com/nilearn/nilearn.git + git remote add upstream git@github.com:nilearn/nilearn.git fi git fetch upstream - save_cache: - key: source-cache + key: source-cache-v2 paths: - ".git" - run: From ca6746de0dca88d4dd2a5f79fe63ebf22e40a1a0 Mon Sep 17 00:00:00 2001 From: Hao-Ting Wang Date: Wed, 19 Jan 2022 06:46:20 -0500 Subject: [PATCH 23/44] [MAINT] Scipy deprecation warning in RegionExtractor (#3130) atol='legacy' option in `scipy.sparse.linalg.cg` to avoid deprecation warning --- nilearn/_utils/segmentation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nilearn/_utils/segmentation.py b/nilearn/_utils/segmentation.py index 71021fde62..eb6ff14e22 100644 --- a/nilearn/_utils/segmentation.py +++ b/nilearn/_utils/segmentation.py @@ -340,7 +340,7 @@ def _solve_cg(lap_sparse, B, tol): lap_sparse = lap_sparse.tocsc() X = [] for i in range(len(B)): - x0 = cg(lap_sparse, -B[i].todense(), tol=tol)[0] + x0 = cg(lap_sparse, -B[i].todense(), tol=tol, atol='legacy')[0] X.append(x0) X = np.array(X) From 0f5f07db3f2768b459f75e8f6e16989f93a0ce45 Mon Sep 17 00:00:00 2001 From: Gensollen Date: Thu, 20 Jan 2022 14:05:00 +0100 Subject: [PATCH 24/44] [MAINT] Remove deprecated `sessions` and `sample_mask` attributes of `NiftiMasker` (#3133) * remove deprecated sessions and sample_mask * Update tests * Update doctest * [circle full] add whatsnew entry * [circle full] fix --- doc/manipulating_images/masker_objects.rst | 4 +- doc/whats_new.rst | 5 ++ examples/02_decoding/plot_haxby_multiclass.py | 2 +- .../02_decoding/plot_haxby_searchlight.py | 2 +- .../plot_advanced_decoding_scikit.py | 2 +- nilearn/maskers/nifti_masker.py | 46 +------------------ nilearn/maskers/tests/test_nifti_masker.py | 26 +++-------- 7 files changed, 17 insertions(+), 70 deletions(-) diff --git a/doc/manipulating_images/masker_objects.rst b/doc/manipulating_images/masker_objects.rst index 44cde2ec90..9c7cbc029f 100644 --- a/doc/manipulating_images/masker_objects.rst +++ b/doc/manipulating_images/masker_objects.rst @@ -198,8 +198,8 @@ preparation:: high_variance_confounds=False, low_pass=None, mask_args=None, mask_img=None, mask_strategy='background', memory=Memory(location=None), memory_level=1, reports=True, - runs=None, sample_mask=None, smoothing_fwhm=None, - standardize=False, standardize_confounds=True, t_r=None, + runs=None, smoothing_fwhm=None, standardize=False, + standardize_confounds=True, t_r=None, target_affine=None, target_shape=None, verbose=0) The meaning of each parameter is described in the documentation of diff --git a/doc/whats_new.rst b/doc/whats_new.rst index 3e47cbb755..81959b7ccb 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -140,6 +140,11 @@ Changes - Deprecated parameter ``sessions`` of function :func:`~nilearn.signal.clean` has been removed. Use ``runs`` instead. (See PR `#3093 `_). +- Deprecated parameters ``sessions`` and ``sample_mask`` of + :class:`~nilearn.maskers.NiftiMasker` have been removed. Please use ``runs`` instead of + ``sessions``, and provide a ``sample_mask`` through + :meth:`~nilearn.maskers.NiftiMasker.transform`. + (See PR `#3133 `_). - :func:`nilearn.glm.first_level.compute_regressor` will now raise an exception if parameter `cond_id` is not a string which could be used to name a python variable. For instance, number strings (ex: "1") will no longer be accepted as valid condition names. diff --git a/examples/02_decoding/plot_haxby_multiclass.py b/examples/02_decoding/plot_haxby_multiclass.py index e38572799a..842cd12ebc 100644 --- a/examples/02_decoding/plot_haxby_multiclass.py +++ b/examples/02_decoding/plot_haxby_multiclass.py @@ -43,7 +43,7 @@ from nilearn.maskers import NiftiMasker # For decoding, standardizing is often very important nifti_masker = NiftiMasker(mask_img=mask_filename, standardize=True, - sessions=session, smoothing_fwhm=4, + runs=session, smoothing_fwhm=4, memory="nilearn_cache", memory_level=1) X = nifti_masker.fit_transform(func_filename) diff --git a/examples/02_decoding/plot_haxby_searchlight.py b/examples/02_decoding/plot_haxby_searchlight.py index b867735888..d8a01d9c66 100644 --- a/examples/02_decoding/plot_haxby_searchlight.py +++ b/examples/02_decoding/plot_haxby_searchlight.py @@ -87,7 +87,7 @@ from nilearn.maskers import NiftiMasker # For decoding, standardizing is often very important -nifti_masker = NiftiMasker(mask_img=mask_img, sessions=session, +nifti_masker = NiftiMasker(mask_img=mask_img, runs=session, standardize=True, memory='nilearn_cache', memory_level=1) fmri_masked = nifti_masker.fit_transform(fmri_img) diff --git a/examples/07_advanced/plot_advanced_decoding_scikit.py b/examples/07_advanced/plot_advanced_decoding_scikit.py index c00d803c27..f2f6adc1d8 100644 --- a/examples/07_advanced/plot_advanced_decoding_scikit.py +++ b/examples/07_advanced/plot_advanced_decoding_scikit.py @@ -73,7 +73,7 @@ # voxels inside the mask of interest, and transform 4D input fMRI data to # 2D arrays(`shape=(n_timepoints, n_voxels)`) that estimators can work on. from nilearn.maskers import NiftiMasker -masker = NiftiMasker(mask_img=mask_filename, sessions=session_label, +masker = NiftiMasker(mask_img=mask_filename, runs=session_label, smoothing_fwhm=4, standardize=True, memory="nilearn_cache", memory_level=1) fmri_masked = masker.fit_transform(fmri_niimgs) diff --git a/nilearn/maskers/nifti_masker.py b/nilearn/maskers/nifti_masker.py index c3b298234f..5d3459b5ed 100644 --- a/nilearn/maskers/nifti_masker.py +++ b/nilearn/maskers/nifti_masker.py @@ -136,8 +136,6 @@ class NiftiMasker(BaseMasker, CacheMixin): runs : numpy array, optional Add a run level to the preprocessing. Each run will be detrended independently. Must be a 1D array of n_samples elements. - 'runs' replaces 'sessions' after release 0.9.0. - Using 'session' will result in an error after release 0.9.0. %(smoothing_fwhm)s standardize : {False, True, 'zscore', 'psc'}, optional Strategy to standardize the signal. @@ -200,17 +198,6 @@ class NiftiMasker(BaseMasker, CacheMixin): to fine-tune mask computation. Please see the related documentation for details. - sample_mask : Any type compatible with numpy-array indexing, optional - Masks the niimgs along time/fourth dimension. This complements - 3D masking by the mask_img argument. This masking step is applied - before data preprocessing at the beginning of NiftiMasker.transform. - This is useful to perform data subselection as part of a scikit-learn - pipeline. - - .. deprecated:: 0.8.0 - `sample_mask` is deprecated in 0.8.0 and will be removed in - 0.9.0. - dtype : {dtype, "auto"}, optional Data type toward which the data should be converted. If "auto", the data will be converted to int32 if dtype is discrete and float32 if it @@ -251,16 +238,11 @@ class NiftiMasker(BaseMasker, CacheMixin): nilearn.signal.clean """ - @remove_parameters(['sample_mask'], - ('Deprecated in 0.8.0. Supply `sample_masker` through ' - '`transform` or `fit_transform` methods instead. '), - '0.9.0') - @rename_parameters({'sessions': 'runs'}, '0.9.0') def __init__(self, mask_img=None, runs=None, smoothing_fwhm=None, standardize=False, standardize_confounds=True, detrend=False, high_variance_confounds=False, low_pass=None, high_pass=None, t_r=None, target_affine=None, target_shape=None, - mask_strategy='background', mask_args=None, sample_mask=None, + mask_strategy='background', mask_args=None, dtype=None, memory_level=1, memory=Memory(location=None), verbose=0, reports=True, ): @@ -279,7 +261,6 @@ def __init__(self, mask_img=None, runs=None, smoothing_fwhm=None, self.target_shape = target_shape self.mask_strategy = mask_strategy self.mask_args = mask_args - self._sample_mask = sample_mask self.dtype = dtype self.memory = memory @@ -297,21 +278,6 @@ def __init__(self, mask_img=None, runs=None, smoothing_fwhm=None, 'resampling, hover over the displayed image.') self._shelving = False - @property - def sessions(self): - warnings.warn(DeprecationWarning("`sessions` attribute is deprecated " - "and will be removed in 0.9.0, use " - "`runs` instead.")) - return self.runs - - @property - def sample_mask(self): - warnings.warn(DeprecationWarning( - "Deprecated. `sample_mask` will be removed in 0.9.0 in favor of " - "supplying `sample_mask` through method `transform` or " - "`fit_transform`.")) - return self._sample_mask - def generate_report(self): from nilearn.reporting.html_report import generate_report return generate_report(self) @@ -506,16 +472,6 @@ def transform_single_imgs(self, imgs, confounds=None, sample_mask=None, ignore=['mask_img', 'mask_args', 'mask_strategy', '_sample_mask', 'sample_mask']) - if hasattr(self, '_sample_mask') and self._sample_mask is not None: - if sample_mask is not None: - warnings.warn( - UserWarning("Overwriting deprecated attribute " - "`NiftiMasker.sample_mask` with parameter " - "`sample_mask` in method `transform`.") - ) - else: - sample_mask = self._sample_mask - data = self._cache(_filter_and_mask, ignore=['verbose', 'memory', 'memory_level', 'copy'], diff --git a/nilearn/maskers/tests/test_nifti_masker.py b/nilearn/maskers/tests/test_nifti_masker.py index c8b9cac8cc..7cbddcc951 100644 --- a/nilearn/maskers/tests/test_nifti_masker.py +++ b/nilearn/maskers/tests/test_nifti_masker.py @@ -174,26 +174,17 @@ def test_mask_4d(): data_trans2 = masker.transform(data_img_4d, sample_mask=sample_mask) assert_array_equal(data_trans2, data_trans_direct) - # check deprecation warning, and the old API should still work - with pytest.warns(DeprecationWarning) as record: - masker = NiftiMasker(mask_img=mask_img, sample_mask=sample_mask) - masker.fit() - data_trans_depr = masker.transform(data_img_4d) - assert "sample_mask will be removed" in record[0].message.args[0] - assert_array_equal(data_trans_depr, data_trans_direct) - - # show warning when supplying both, use the sample_mask from transform diff_sample_mask = np.array([2, 4]) data_trans_img_diff = index_img(data_img_4d, diff_sample_mask) data_trans_direct_diff = get_data(data_trans_img_diff)[mask_bool, :] data_trans_direct_diff = np.swapaxes(data_trans_direct_diff, 0, 1) - masker = NiftiMasker(mask_img=mask_img, sample_mask=sample_mask) + masker = NiftiMasker(mask_img=mask_img) masker.fit() - with pytest.warns(UserWarning, match=r'^Overwriting') as record: - data_trans3 = masker.transform(data_img_4d, - sample_mask=diff_sample_mask) + data_trans3 = masker.transform( + data_img_4d, sample_mask=diff_sample_mask + ) assert_array_equal(data_trans3, data_trans_direct_diff) - assert "Overwriting deprecated attribute " in record[0].message.args[0] + def test_4d_single_scan(): mask = np.zeros((10, 10, 10)) @@ -251,14 +242,9 @@ def test_sessions(): data[..., 0] = 0 data[20, 20, 20] = 1 data_img = Nifti1Image(data, np.eye(4)) - masker = NiftiMasker(sessions=np.ones(3, dtype=np.int)) + masker = NiftiMasker(runs=np.ones(3, dtype=np.int)) pytest.raises(ValueError, masker.fit_transform, data_img) - # check deprecation warning of attribute sessions - with pytest.warns(DeprecationWarning) as record: - masker.sessions - assert "`sessions` attribute is deprecated" in record[0].message.args[0] - def test_joblib_cache(): from joblib import hash, Memory From 1745e44faafaebd73288bd4270773c54ece7163e Mon Sep 17 00:00:00 2001 From: Gensollen Date: Thu, 20 Jan 2022 15:52:53 +0100 Subject: [PATCH 25/44] [MAINT] Remove old workaround (#3092) --- nilearn/__init__.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/nilearn/__init__.py b/nilearn/__init__.py index f17b96bb75..ccf6e63ae4 100644 --- a/nilearn/__init__.py +++ b/nilearn/__init__.py @@ -69,19 +69,6 @@ def _python_deprecation_warnings(): _python_deprecation_warnings() -# Temporary work around to address formatting issues in doc tests -# with NumPy 1.14. NumPy had made more consistent str/repr formatting -# of numpy arrays. Hence we print the options to old versions. -import numpy as np -if _compare_version(np.__version__, '>=', "1.14"): - # See issue #1600 in nilearn for reason to add try and except - try: - from ._utils.testing import are_tests_running - if are_tests_running(): - np.set_printoptions(legacy='1.13') - except ImportError: - pass - # Monkey-patch gzip to have faster reads on large gzip files if hasattr(gzip.GzipFile, 'max_read_chunk'): gzip.GzipFile.max_read_chunk = 100 * 1024 * 1024 # 100Mb From 4668e3ea478ba635cdab0d2adde0919c1197c924 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Fri, 21 Jan 2022 06:06:03 -0500 Subject: [PATCH 26/44] [ENH] Move FSL- and BIDS-related functions to interfaces module (#3126) * Move BIDS and FSL-related functions to the interfaces module. * Update associated imports across the library. * Add migrated functions to the reference page. * Add entries to whatsnew page. Will need to update with PR link. * Move tests for new functions into appropriate files. * Update the pull request number. --- doc/modules/reference.rst | 35 ++++ doc/whats_new.rst | 15 ++ .../04_glm_first_level/plot_bids_features.py | 2 +- nilearn/_utils/glm.py | 163 ------------------ nilearn/glm/first_level/first_level.py | 4 +- nilearn/glm/tests/test_first_level.py | 2 +- nilearn/glm/tests/test_utils.py | 90 +--------- nilearn/interfaces/__init__.py | 4 +- nilearn/interfaces/bids.py | 160 +++++++++++++++++ nilearn/interfaces/fsl.py | 39 +++++ nilearn/interfaces/tests/test_bids.py | 72 ++++++++ nilearn/interfaces/tests/test_fsl.py | 20 +++ .../_glm_reporter_visual_inspection_suite_.py | 2 +- 13 files changed, 352 insertions(+), 256 deletions(-) create mode 100644 nilearn/interfaces/bids.py create mode 100644 nilearn/interfaces/fsl.py create mode 100644 nilearn/interfaces/tests/test_bids.py create mode 100644 nilearn/interfaces/tests/test_fsl.py diff --git a/doc/modules/reference.rst b/doc/modules/reference.rst index 81072a5577..6901ea8279 100644 --- a/doc/modules/reference.rst +++ b/doc/modules/reference.rst @@ -210,6 +210,24 @@ the :ref:`user guide ` for more information and usage examples. :no-members: :no-inherited-members: +:mod:`nilearn.interfaces.bids` +---------------------------------- + +.. automodule:: nilearn.interfaces.bids + :no-members: + :no-inherited-members: + +**Functions**: + +.. currentmodule:: nilearn.interfaces.bids + +.. autosummary:: + :toctree: generated/ + :template: function.rst + + get_bids_files + parse_bids_filename + :mod:`nilearn.interfaces.fmriprep` ---------------------------------- @@ -228,6 +246,23 @@ the :ref:`user guide ` for more information and usage examples. load_confounds load_confounds_strategy +:mod:`nilearn.interfaces.fsl` +---------------------------------- + +.. automodule:: nilearn.interfaces.fsl + :no-members: + :no-inherited-members: + +**Functions**: + +.. currentmodule:: nilearn.interfaces.fsl + +.. autosummary:: + :toctree: generated/ + :template: function.rst + + get_design_from_fslmat + .. _maskers_ref: :mod:`nilearn.maskers`: Extracting Signals from Brain Images diff --git a/doc/whats_new.rst b/doc/whats_new.rst index 81959b7ccb..290ab1a2e8 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -24,6 +24,21 @@ NEW confound variables from :term:`fMRIPrep` outputs using four preset strategies: ``simple``, ``scrubbing``, ``compcor``, and ``ica_aroma``. (See PR `#3016 `_). +- New submodule :mod:`nilearn.interfaces.bids` to implement loading utilities + for :term:`BIDS` datasets. + (See PR `#3061 `_). +- New function :func:`nilearn.interfaces.bids.get_bids_files` to select files + easily from :term:`BIDS` datasets. + (See PR `#3016 `_). +- New function :func:`nilearn.interfaces.bids.parse_bids_filename` to identify + subparts of :term:`BIDS` filenames. + (See PR `#3016 `_). +- New submodule :mod:`nilearn.interfaces.fsl` to implement loading utilities + for :term:`FSL` outputs. + (See PR `#3061 `_). +- New function :func:`nilearn.interfaces.fsl.get_design_from_fslmat` to load + design matrices from :term:`FSL` files. + (See PR `#3061 `_). - Surface plotting functions like :func:`nilearn.plotting.plot_surf_stat_map` now have an `engine` parameter, defaulting to "matplotlib", but which can be set to "plotly". If plotly and kaleido are installed, this will generate an diff --git a/examples/04_glm_first_level/plot_bids_features.py b/examples/04_glm_first_level/plot_bids_features.py index f995d85837..f66e0e8f9c 100644 --- a/examples/04_glm_first_level/plot_bids_features.py +++ b/examples/04_glm_first_level/plot_bids_features.py @@ -79,7 +79,7 @@ subject = 'sub-' + model.subject_label import os -from nilearn._utils.glm import get_design_from_fslmat +from nilearn.interfaces.fsl import get_design_from_fslmat fsl_design_matrix_path = os.path.join( data_dir, 'derivatives', 'task', subject, 'stopsignal.feat', 'design.mat') design_matrix = get_design_from_fslmat( diff --git a/nilearn/_utils/glm.py b/nilearn/_utils/glm.py index 06b59c0b22..7d99859a5b 100644 --- a/nilearn/_utils/glm.py +++ b/nilearn/_utils/glm.py @@ -3,8 +3,6 @@ Authors: Bertrand Thirion, Matthew Brett, Ana Luisa Pinho, 2020 """ import csv -import glob -import os from warnings import warn @@ -332,164 +330,3 @@ def positive_reciprocal(X): """ X = np.asarray(X) return np.where(X <= 0, 0, 1. / X) - - -# UTILITIES FOR THE BIDS STANDARD -def get_bids_files(main_path, file_tag='*', file_type='*', sub_label='*', - modality_folder='*', filters=None, sub_folder=True): - """Search for files in a :term:`BIDS` dataset following given constraints. - - This utility function allows to filter files in the :term:`BIDS` dataset by - any of the fields contained in the file names. Moreover it allows to search - for specific types of files or particular tags. - - The provided filters have to correspond to a file name field, so - any file not containing the field will be ignored. For example the filter - ('sub', '01') would return all files corresponding to the first - subject that specifically contain in the file name "sub-01". If more - filters are given then we constraint the possible files names accordingly. - - Notice that to search in the derivatives folder, it has to be given as - part of the main_path. This is useful since the current convention gives - exactly the same inner structure to derivatives than to the main :term:`BIDS` - dataset folder, so we can search it in the same way. - - Parameters - ---------- - main_path : str - Directory of the :term:`BIDS` dataset. - - file_tag : str accepted by glob, optional - The final tag of the desired files. For example 'bold' if one is - interested in the files related to the neuroimages. - Default='*'. - - file_type : str accepted by glob, optional - The type of the desired files. For example to be able to request only - 'nii' or 'json' files for the 'bold' tag. - Default='*'. - - sub_label : str accepted by glob, optional - Such a common filter is given as a direct option since it applies also - at the level of directories. the label is what follows the 'sub' field - in the :term:`BIDS` convention as 'sub-label'. - Default='*'. - - modality_folder : str accepted by glob, optional - Inside the subject and optional session folders a final level of - folders is expected in the :term:`BIDS` convention that groups files according - to different neuroimaging modalities and any other additions of the - dataset provider. For example the 'func' and 'anat' standard folders. - If given as the empty string '', files will be searched inside the - sub-label/ses-label directories. - Default='*'. - - filters : list of tuples (str, str), optional - Filters are of the form (field, label). Only one filter per field - allowed. A file that does not match a filter will be discarded. - Filter examples would be ('ses', '01'), ('dir', 'ap') and - ('task', 'localizer'). - - sub_folder : boolean, optional - Determines if the files searched are at the level of - subject/session folders or just below the dataset main folder. - Setting this option to False with other default values would return - all the files below the main directory, ignoring files in subject - or derivatives folders. - Default=True. - - Returns - ------- - files : list of str - List of file paths found. - - """ - filters = filters if filters else [] - if sub_folder: - files = os.path.join(main_path, 'sub-*', 'ses-*') - if glob.glob(files): - files = os.path.join(main_path, 'sub-%s' % sub_label, 'ses-*', - modality_folder, 'sub-%s*_%s.%s' % - (sub_label, file_tag, file_type)) - else: - files = os.path.join(main_path, 'sub-%s' % sub_label, - modality_folder, 'sub-%s*_%s.%s' % - (sub_label, file_tag, file_type)) - else: - files = os.path.join(main_path, '*%s.%s' % (file_tag, file_type)) - - files = glob.glob(files) - files.sort() - if filters: - files = [parse_bids_filename(file_) for file_ in files] - for key, value in filters: - files = [file_ for file_ in files - if (key in file_ and file_[key] == value) - ] - return [ref_file['file_path'] for ref_file in files] - - return files - - -def parse_bids_filename(img_path): - r"""Return dictionary with parsed information from file path. - - Parameters - ---------- - img_path : str - - Returns - ------- - reference : dict - Returns a dictionary with all key-value pairs in the file name - parsed and other useful fields like 'file_path', 'file_basename', - 'file_tag', 'file_type' and 'file_fields'. - - The 'file_tag' field refers to the last part of the file under the - :term:`BIDS` convention that is of the form \*_tag.type. - Contrary to the rest of the file name it is not a key-value pair. - This notion should be revised in the case we are handling derivatives - since so far the convention will keep the tag prepended to any fields - added in the case of preprocessed files that also end with another tag. - This parser will consider any tag in the middle of the file name as a - key with no value and will be included in the 'file_fields' key. - - """ - reference = {} - reference['file_path'] = img_path - reference['file_basename'] = os.path.basename(img_path) - parts = reference['file_basename'].split('_') - tag, type_ = parts[-1].split('.', 1) - reference['file_tag'] = tag - reference['file_type'] = type_ - reference['file_fields'] = [] - for part in parts[:-1]: - field = part.split('-')[0] - reference['file_fields'].append(field) - # In derivatives is not clear if the source file name will - # be parsed as a field with no value. - if len(part.split('-')) > 1: - value = part.split('-')[1] - reference[field] = value - else: - reference[field] = None - return reference - - -def get_design_from_fslmat(fsl_design_matrix_path, column_names=None): - """ Extract design matrix dataframe from FSL mat file. - """ - design_matrix_file = open(fsl_design_matrix_path, 'r') - # Based on the openneuro example this seems to be the right - # marker to start extracting the matrix until the end of the file - # Conventions of FSL mat files should be verified in more detail for - # a general case - for line in design_matrix_file: - if '/Matrix' in line: - break - design_matrix = np.array( - [[float(val) for val in line.replace('\t\n', '').split('\t')] for - line in design_matrix_file]) - design_matrix = pd.DataFrame(design_matrix, columns=column_names) - - return design_matrix diff --git a/nilearn/glm/first_level/first_level.py b/nilearn/glm/first_level/first_level.py index 25346c633e..b36fe743ba 100644 --- a/nilearn/glm/first_level/first_level.py +++ b/nilearn/glm/first_level/first_level.py @@ -22,10 +22,10 @@ from sklearn.base import clone from sklearn.cluster import KMeans +from nilearn.interfaces.bids import get_bids_files, parse_bids_filename from nilearn._utils import fill_doc from nilearn._utils.glm import (_check_events_file_uses_tab_separators, - _check_run_tables, get_bids_files, - parse_bids_filename) + _check_run_tables) from nilearn._utils.niimg_conversions import check_niimg from nilearn.glm.contrasts import (_compute_fixed_effect_contrast, expression_to_contrast_vector) diff --git a/nilearn/glm/tests/test_first_level.py b/nilearn/glm/tests/test_first_level.py index dc0dd7ae20..aac69394e7 100644 --- a/nilearn/glm/tests/test_first_level.py +++ b/nilearn/glm/tests/test_first_level.py @@ -15,7 +15,6 @@ from nilearn._utils.data_gen import (create_fake_bids_dataset, generate_fake_fmri_data_and_design, write_fake_fmri_data_and_design) -from nilearn._utils.glm import get_bids_files from nilearn.glm.contrasts import compute_fixed_effects from nilearn.glm.first_level import (FirstLevelModel, first_level_from_bids, mean_scaling, run_glm) @@ -23,6 +22,7 @@ check_design_matrix, make_first_level_design_matrix) from nilearn.glm.first_level.first_level import _yule_walker from nilearn.image import get_data +from nilearn.interfaces.bids import get_bids_files from nilearn.glm.regression import ARModel, OLSModel from nilearn.maskers import NiftiMasker diff --git a/nilearn/glm/tests/test_utils.py b/nilearn/glm/tests/test_utils.py index 339f9a6195..0d4a306028 100644 --- a/nilearn/glm/tests/test_utils.py +++ b/nilearn/glm/tests/test_utils.py @@ -1,23 +1,19 @@ #!/usr/bin/env python -import os - import numpy as np import pandas as pd import pytest import scipy.stats as sps import scipy.linalg as spl -from nibabel.tmpdirs import InTemporaryDirectory from numpy.testing import assert_almost_equal, assert_array_almost_equal from scipy.stats import norm -from nilearn._utils.data_gen import (create_fake_bids_dataset, - generate_fake_fmri) +from nilearn._utils.data_gen import generate_fake_fmri from nilearn._utils.glm import (_check_and_load_tables, _check_list_length_match, _check_run_tables, - full_rank, get_bids_files, - get_design_from_fslmat, multiple_fast_inverse, - multiple_mahalanobis, parse_bids_filename, + full_rank, + multiple_fast_inverse, + multiple_mahalanobis, positive_reciprocal, z_score) from nilearn.maskers import NiftiMasker from nilearn.glm.first_level import (FirstLevelModel, @@ -234,81 +230,3 @@ def test_img_table_checks(): _check_run_tables([''] * 2, [[0], pd.DataFrame()], "") with pytest.raises(ValueError): _check_run_tables([''] * 2, ['.csv', pd.DataFrame()], "") - - -def test_get_bids_files(): - with InTemporaryDirectory(): - bids_path = create_fake_bids_dataset(n_sub=10, n_ses=2, - tasks=['localizer', 'main'], - n_runs=[1, 3]) - # For each possible option of file selection we check that we - # recover the appropriate amount of files, as included in the - # fake bids dataset. - - # 250 files in total related to subject images. Top level files like - # README not included - selection = get_bids_files(bids_path) - assert len(selection) == 250 - # 160 bold files expected. .nii and .json files - selection = get_bids_files(bids_path, file_tag='bold') - assert len(selection) == 160 - # Only 90 files are nii.gz. Bold and T1w files. - selection = get_bids_files(bids_path, file_type='nii.gz') - assert len(selection) == 90 - # Only 25 files correspond to subject 01 - selection = get_bids_files(bids_path, sub_label='01') - assert len(selection) == 25 - # There are only 10 files in anat folders. One T1w per subject. - selection = get_bids_files(bids_path, modality_folder='anat') - assert len(selection) == 10 - # 20 files corresponding to run 1 of session 2 of main task. - # 10 bold.nii.gz and 10 bold.json files. (10 subjects) - filters = [('task', 'main'), ('run', '01'), ('ses', '02')] - selection = get_bids_files(bids_path, file_tag='bold', filters=filters) - assert len(selection) == 20 - # Get Top level folder files. Only 1 in this case, the README file. - selection = get_bids_files(bids_path, sub_folder=False) - assert len(selection) == 1 - # 80 counfonds (4 runs per ses & sub), testing `fmriprep` >= 20.2 path - selection = get_bids_files(os.path.join(bids_path, 'derivatives'), - file_tag='desc-confounds_timeseries') - assert len(selection) == 80 - - with InTemporaryDirectory(): - bids_path = create_fake_bids_dataset(n_sub=10, n_ses=2, - tasks=['localizer', 'main'], - n_runs=[1, 3], - confounds_tag="desc-confounds_" - "regressors") - # 80 counfonds (4 runs per ses & sub), testing `fmriprep` >= 20.2 path - selection = get_bids_files(os.path.join(bids_path, 'derivatives'), - file_tag='desc-confounds_regressors') - assert len(selection) == 80 - - -def test_parse_bids_filename(): - fields = ['sub', 'ses', 'task', 'lolo'] - labels = ['01', '01', 'langloc', 'lala'] - file_name = 'sub-01_ses-01_task-langloc_lolo-lala_bold.nii.gz' - file_path = os.path.join('dataset', 'sub-01', 'ses-01', 'func', file_name) - file_dict = parse_bids_filename(file_path) - for fidx, field in enumerate(fields): - assert file_dict[field] == labels[fidx] - assert file_dict['file_type'] == 'nii.gz' - assert file_dict['file_tag'] == 'bold' - assert file_dict['file_path'] == file_path - assert file_dict['file_basename'] == file_name - assert file_dict['file_fields'] == fields - - -def test_get_design_from_fslmat(tmp_path): - fsl_mat_path = os.path.join(str(tmp_path), 'fsl_mat.txt') - matrix = np.ones((5, 5)) - with open(fsl_mat_path, 'w') as fsl_mat: - fsl_mat.write('/Matrix\n') - for row in matrix: - for val in row: - fsl_mat.write(str(val) + '\t') - fsl_mat.write('\n') - design_matrix = get_design_from_fslmat(fsl_mat_path) - assert design_matrix.shape == matrix.shape diff --git a/nilearn/interfaces/__init__.py b/nilearn/interfaces/__init__.py index 343cff31d7..2c851f1746 100644 --- a/nilearn/interfaces/__init__.py +++ b/nilearn/interfaces/__init__.py @@ -2,6 +2,6 @@ Interfaces for Nilearn. """ -from nilearn.interfaces import fmriprep +from nilearn.interfaces import bids, fmriprep, fsl -__all__ = ['fmriprep'] +__all__ = ['bids', 'fmriprep', 'fsl'] diff --git a/nilearn/interfaces/bids.py b/nilearn/interfaces/bids.py new file mode 100644 index 0000000000..fa63943b3f --- /dev/null +++ b/nilearn/interfaces/bids.py @@ -0,0 +1,160 @@ +"""Functions for working with BIDS datasets.""" +import glob +import os + + +def get_bids_files( + main_path, + file_tag='*', + file_type='*', + sub_label='*', + modality_folder='*', + filters=None, + sub_folder=True, +): + """Search for files in a :term:`BIDS` dataset following given constraints. + + This utility function allows to filter files in the :term:`BIDS` dataset by + any of the fields contained in the file names. Moreover it allows to search + for specific types of files or particular tags. + + The provided filters have to correspond to a file name field, so + any file not containing the field will be ignored. For example the filter + ('sub', '01') would return all files corresponding to the first + subject that specifically contain in the file name 'sub-01'. If more + filters are given then we constraint the possible files names accordingly. + + Notice that to search in the derivatives folder, it has to be given as + part of the main_path. This is useful since the current convention gives + exactly the same inner structure to derivatives than to the main + :term:`BIDS` dataset folder, so we can search it in the same way. + + Parameters + ---------- + main_path : :obj:`str` + Directory of the :term:`BIDS` dataset. + + file_tag : :obj:`str` accepted by glob, optional + The final tag of the desired files. For example 'bold' if one is + interested in the files related to the neuroimages. + Default='*'. + + file_type : :obj:`str` accepted by glob, optional + The type of the desired files. For example to be able to request only + 'nii' or 'json' files for the 'bold' tag. + Default='*'. + + sub_label : :obj:`str` accepted by glob, optional + Such a common filter is given as a direct option since it applies also + at the level of directories. the label is what follows the 'sub' field + in the :term:`BIDS` convention as 'sub-label'. + Default='*'. + + modality_folder : :obj:`str` accepted by glob, optional + Inside the subject and optional session folders a final level of + folders is expected in the :term:`BIDS` convention that groups files + according to different neuroimaging modalities and any other additions + of the dataset provider. For example the 'func' and 'anat' standard + folders. If given as the empty string '', files will be searched + inside the sub-label/ses-label directories. + Default='*'. + + filters : :obj:`list` of :obj:`tuple` (:obj:`str`, :obj:`str`), optional + Filters are of the form (field, label). Only one filter per field + allowed. A file that does not match a filter will be discarded. + Filter examples would be ('ses', '01'), ('dir', 'ap') and + ('task', 'localizer'). + + sub_folder : :obj:`bool`, optional + Determines if the files searched are at the level of + subject/session folders or just below the dataset main folder. + Setting this option to False with other default values would return + all the files below the main directory, ignoring files in subject + or derivatives folders. + Default=True. + + Returns + ------- + files : :obj:`list` of :obj:`str` + List of file paths found. + + """ + filters = filters if filters else [] + if sub_folder: + files = os.path.join(main_path, 'sub-*', 'ses-*') + if glob.glob(files): + files = os.path.join( + main_path, + 'sub-%s' % sub_label, + 'ses-*', + modality_folder, + 'sub-%s*_%s.%s' % (sub_label, file_tag, file_type), + ) + else: + files = os.path.join( + main_path, + 'sub-%s' % sub_label, + modality_folder, + 'sub-%s*_%s.%s' % (sub_label, file_tag, file_type), + ) + else: + files = os.path.join(main_path, '*%s.%s' % (file_tag, file_type)) + + files = glob.glob(files) + files.sort() + if filters: + files = [parse_bids_filename(file_) for file_ in files] + for key, value in filters: + files = [ + file_ for file_ in files if + (key in file_ and file_[key] == value) + ] + return [ref_file['file_path'] for ref_file in files] + + return files + + +def parse_bids_filename(img_path): + r"""Return dictionary with parsed information from file path. + + Parameters + ---------- + img_path : :obj:`str` + Path to file from which to parse information. + + Returns + ------- + reference : :obj:`dict` + Returns a dictionary with all key-value pairs in the file name + parsed and other useful fields like 'file_path', 'file_basename', + 'file_tag', 'file_type' and 'file_fields'. + + The 'file_tag' field refers to the last part of the file under the + :term:`BIDS` convention that is of the form \*_tag.type. + Contrary to the rest of the file name it is not a key-value pair. + This notion should be revised in the case we are handling derivatives + since so far the convention will keep the tag prepended to any fields + added in the case of preprocessed files that also end with another tag. + This parser will consider any tag in the middle of the file name as a + key with no value and will be included in the 'file_fields' key. + + """ + reference = {} + reference['file_path'] = img_path + reference['file_basename'] = os.path.basename(img_path) + parts = reference['file_basename'].split('_') + tag, type_ = parts[-1].split('.', 1) + reference['file_tag'] = tag + reference['file_type'] = type_ + reference['file_fields'] = [] + for part in parts[:-1]: + field = part.split('-')[0] + reference['file_fields'].append(field) + # In derivatives is not clear if the source file name will + # be parsed as a field with no value. + if len(part.split('-')) > 1: + value = part.split('-')[1] + reference[field] = value + else: + reference[field] = None + return reference diff --git a/nilearn/interfaces/fsl.py b/nilearn/interfaces/fsl.py new file mode 100644 index 0000000000..e67d15bed8 --- /dev/null +++ b/nilearn/interfaces/fsl.py @@ -0,0 +1,39 @@ +"""Functions for working with the FSL library.""" +import numpy as np +import pandas as pd + + +def get_design_from_fslmat(fsl_design_matrix_path, column_names=None): + """Extract design matrix dataframe from FSL mat file. + + Parameters + ---------- + fsl_design_matrix_path : :obj:`str` + Path to the FSL design matrix file. + column_names : None or :obj:`list` of :obj:`str`, optional + The names of the columns in the design matrix. + Default=None. + + Returns + ------- + design_matrix : :obj:`pandas.DataFrame` + A DataFrame containing the design matrix. + """ + with open(fsl_design_matrix_path, 'r') as design_matrix_file: + # Based on the openneuro example this seems to be the right + # marker to start extracting the matrix until the end of the file + # Conventions of FSL mat files should be verified in more detail for + # a general case + for line in design_matrix_file: + if '/Matrix' in line: + break + + design_matrix = np.array( + [ + [float(val) for val in line.replace('\t\n', '').split('\t')] + for line in design_matrix_file + ] + ) + design_matrix = pd.DataFrame(design_matrix, columns=column_names) + + return design_matrix diff --git a/nilearn/interfaces/tests/test_bids.py b/nilearn/interfaces/tests/test_bids.py new file mode 100644 index 0000000000..387fa3903a --- /dev/null +++ b/nilearn/interfaces/tests/test_bids.py @@ -0,0 +1,72 @@ +"""Tests for the nilearn.interfaces.bids submodule.""" +import os + +from nibabel.tmpdirs import InTemporaryDirectory + +from nilearn._utils.data_gen import create_fake_bids_dataset +from nilearn.interfaces.bids import get_bids_files, parse_bids_filename + + +def test_get_bids_files(): + with InTemporaryDirectory(): + bids_path = create_fake_bids_dataset(n_sub=10, n_ses=2, + tasks=['localizer', 'main'], + n_runs=[1, 3]) + # For each possible option of file selection we check that we + # recover the appropriate amount of files, as included in the + # fake bids dataset. + + # 250 files in total related to subject images. Top level files like + # README not included + selection = get_bids_files(bids_path) + assert len(selection) == 250 + # 160 bold files expected. .nii and .json files + selection = get_bids_files(bids_path, file_tag='bold') + assert len(selection) == 160 + # Only 90 files are nii.gz. Bold and T1w files. + selection = get_bids_files(bids_path, file_type='nii.gz') + assert len(selection) == 90 + # Only 25 files correspond to subject 01 + selection = get_bids_files(bids_path, sub_label='01') + assert len(selection) == 25 + # There are only 10 files in anat folders. One T1w per subject. + selection = get_bids_files(bids_path, modality_folder='anat') + assert len(selection) == 10 + # 20 files corresponding to run 1 of session 2 of main task. + # 10 bold.nii.gz and 10 bold.json files. (10 subjects) + filters = [('task', 'main'), ('run', '01'), ('ses', '02')] + selection = get_bids_files(bids_path, file_tag='bold', filters=filters) + assert len(selection) == 20 + # Get Top level folder files. Only 1 in this case, the README file. + selection = get_bids_files(bids_path, sub_folder=False) + assert len(selection) == 1 + # 80 counfonds (4 runs per ses & sub), testing `fmriprep` >= 20.2 path + selection = get_bids_files(os.path.join(bids_path, 'derivatives'), + file_tag='desc-confounds_timeseries') + assert len(selection) == 80 + + with InTemporaryDirectory(): + bids_path = create_fake_bids_dataset(n_sub=10, n_ses=2, + tasks=['localizer', 'main'], + n_runs=[1, 3], + confounds_tag="desc-confounds_" + "regressors") + # 80 counfonds (4 runs per ses & sub), testing `fmriprep` >= 20.2 path + selection = get_bids_files(os.path.join(bids_path, 'derivatives'), + file_tag='desc-confounds_regressors') + assert len(selection) == 80 + + +def test_parse_bids_filename(): + fields = ['sub', 'ses', 'task', 'lolo'] + labels = ['01', '01', 'langloc', 'lala'] + file_name = 'sub-01_ses-01_task-langloc_lolo-lala_bold.nii.gz' + file_path = os.path.join('dataset', 'sub-01', 'ses-01', 'func', file_name) + file_dict = parse_bids_filename(file_path) + for fidx, field in enumerate(fields): + assert file_dict[field] == labels[fidx] + assert file_dict['file_type'] == 'nii.gz' + assert file_dict['file_tag'] == 'bold' + assert file_dict['file_path'] == file_path + assert file_dict['file_basename'] == file_name + assert file_dict['file_fields'] == fields diff --git a/nilearn/interfaces/tests/test_fsl.py b/nilearn/interfaces/tests/test_fsl.py new file mode 100644 index 0000000000..87e04d96c0 --- /dev/null +++ b/nilearn/interfaces/tests/test_fsl.py @@ -0,0 +1,20 @@ +"""Tests for the nilearn.interfaces.fsl submodule.""" +import os + +import numpy as np + +from nilearn.interfaces.fsl import get_design_from_fslmat + + +def test_get_design_from_fslmat(tmp_path): + fsl_mat_path = os.path.join(str(tmp_path), 'fsl_mat.txt') + matrix = np.ones((5, 5)) + with open(fsl_mat_path, 'w') as fsl_mat: + fsl_mat.write('/Matrix\n') + for row in matrix: + for val in row: + fsl_mat.write(str(val) + '\t') + fsl_mat.write('\n') + + design_matrix = get_design_from_fslmat(fsl_mat_path) + assert design_matrix.shape == matrix.shape diff --git a/nilearn/reporting/_visual_testing/_glm_reporter_visual_inspection_suite_.py b/nilearn/reporting/_visual_testing/_glm_reporter_visual_inspection_suite_.py index 516789f269..797eff7286 100644 --- a/nilearn/reporting/_visual_testing/_glm_reporter_visual_inspection_suite_.py +++ b/nilearn/reporting/_visual_testing/_glm_reporter_visual_inspection_suite_.py @@ -13,12 +13,12 @@ import pandas as pd import nilearn -from nilearn._utils.glm import get_design_from_fslmat from nilearn.glm.first_level import FirstLevelModel, first_level_from_bids from nilearn.glm.first_level.design_matrix import \ make_first_level_design_matrix from nilearn.glm.second_level import SecondLevelModel from nilearn.image import resample_to_img +from nilearn.interfaces.fsl import get_design_from_fslmat from nilearn.maskers import NiftiSpheresMasker from nilearn.reporting import make_glm_report From d0d10934666a562e208575cb94a457e2f7b780f1 Mon Sep 17 00:00:00 2001 From: Gensollen Date: Fri, 21 Jan 2022 17:40:59 +0100 Subject: [PATCH 27/44] [FIX] Fix links in whats_new (#3139) * [circle full] fix links * [circle full] fix wrong glossary entry --- doc/whats_new.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/whats_new.rst b/doc/whats_new.rst index 290ab1a2e8..3c2b81dcf7 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -26,19 +26,19 @@ NEW (See PR `#3016 `_). - New submodule :mod:`nilearn.interfaces.bids` to implement loading utilities for :term:`BIDS` datasets. - (See PR `#3061 `_). + (See PR `#3126 `_). - New function :func:`nilearn.interfaces.bids.get_bids_files` to select files easily from :term:`BIDS` datasets. - (See PR `#3016 `_). + (See PR `#3126 `_). - New function :func:`nilearn.interfaces.bids.parse_bids_filename` to identify subparts of :term:`BIDS` filenames. - (See PR `#3016 `_). + (See PR `#3126 `_). - New submodule :mod:`nilearn.interfaces.fsl` to implement loading utilities - for :term:`FSL` outputs. - (See PR `#3061 `_). + for FSL outputs. + (See PR `#3126 `_). - New function :func:`nilearn.interfaces.fsl.get_design_from_fslmat` to load - design matrices from :term:`FSL` files. - (See PR `#3061 `_). + design matrices from FSL files. + (See PR `#3126 `_). - Surface plotting functions like :func:`nilearn.plotting.plot_surf_stat_map` now have an `engine` parameter, defaulting to "matplotlib", but which can be set to "plotly". If plotly and kaleido are installed, this will generate an From b42b4c0c4c7c000a9d13b4b73c20d1b285396108 Mon Sep 17 00:00:00 2001 From: bthirion Date: Mon, 24 Jan 2022 10:32:38 +0100 Subject: [PATCH 28/44] [FIX] fixed code + added test (#3137) * fixed code + added test * pep8 * Added to whatsnew * string fix --- doc/whats_new.rst | 2 ++ nilearn/glm/tests/test_thresholding.py | 5 +++++ nilearn/glm/thresholding.py | 3 +-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/whats_new.rst b/doc/whats_new.rst index 3c2b81dcf7..ec0fdca4a9 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -83,6 +83,8 @@ Fixes index (See PR `#3078 `_). - Convert reference in `nilearn/regions/region_extractor.py` to use footcite / footbibliography. (See issue `#2787 `_ and PR `#3111 `_). +- Computation of Benjamini-Hocheberg threshold fixed in `nilearn/glm/thresholding.py` function (see issue `#2879 `_ and PR `#3137 `_) + Enhancements ------------ diff --git a/nilearn/glm/tests/test_thresholding.py b/nilearn/glm/tests/test_thresholding.py index 94418b4ac8..340676c90e 100644 --- a/nilearn/glm/tests/test_thresholding.py +++ b/nilearn/glm/tests/test_thresholding.py @@ -24,6 +24,11 @@ def test_fdr(): fdr_threshold(x, -.1) with pytest.raises(ValueError): fdr_threshold(x, 1.5) + # addresses #2879 + n = 10 + pvals = np.linspace(1 / n, 1, n) + pvals[0] = 0.007 + assert np.isfinite(fdr_threshold(norm.isf(pvals), .1)) def test_threshold_stats_img(): diff --git a/nilearn/glm/thresholding.py b/nilearn/glm/thresholding.py index c5b67be4c0..ca0dd124be 100644 --- a/nilearn/glm/thresholding.py +++ b/nilearn/glm/thresholding.py @@ -98,8 +98,7 @@ def fdr_threshold(z_vals, alpha): z_vals_ = - np.sort(- z_vals) p_vals = norm.sf(z_vals_) n_samples = len(p_vals) - pos = p_vals < alpha * np.linspace( - .5 / n_samples, 1 - .5 / n_samples, n_samples) + pos = p_vals < alpha * np.linspace(1 / n_samples, 1, n_samples) if pos.any(): return (z_vals_[pos][-1] - 1.e-12) From 7b4a476c667973908971138442f32552be25846c Mon Sep 17 00:00:00 2001 From: Gensollen Date: Mon, 24 Jan 2022 12:08:47 +0100 Subject: [PATCH 29/44] [ENH] Refactor `plot_matrix` (#3001) * Refactor plot_matrix * Improve docstrings * Fix PEP8 * [circle full] request full build * Add tests for plot_matrix and refactor * Fix PEP8 * Add missing test * [circle full] request full build * [circle full] Fix method reference * [circle full] Avoid hardcoded parameters. * Update nilearn/plotting/matrix_plotting.py Co-authored-by: bthirion Co-authored-by: bthirion --- nilearn/plotting/matrix_plotting.py | 343 +++++++++++------- .../plotting/tests/test_matrix_plotting.py | 188 +++++++--- 2 files changed, 357 insertions(+), 174 deletions(-) diff --git a/nilearn/plotting/matrix_plotting.py b/nilearn/plotting/matrix_plotting.py index 6d444f6f3e..4e050a9169 100644 --- a/nilearn/plotting/matrix_plotting.py +++ b/nilearn/plotting/matrix_plotting.py @@ -15,8 +15,11 @@ from nilearn.glm.first_level import check_design_matrix -def fit_axes(ax): - """ Redimension the given axes to have labels fitting. +def _fit_axes(ax): + """Helper function for plot_matrix. + + This function redimensions the given axes to have + labels fitting. """ fig = ax.get_figure() renderer = get_renderer(fig) @@ -37,6 +40,152 @@ def fit_axes(ax): ax.set_position(new_position) +def _sanitize_inputs_plot_matrix(mat_shape, tri, labels, reorder, figure, axes): # noqa + """Helper function for plot_matrix. + + This function makes sure the inputs to plot_matrix are valid. + """ + _sanitize_tri(tri) + labels = _sanitize_labels(mat_shape, labels) + reorder = _sanitize_reorder(reorder) + fig, axes, own_fig = _sanitize_figure_and_axes(figure, axes) + return labels, reorder, fig, axes, own_fig + + +def _sanitize_figure_and_axes(figure, axes): + """Helper function for plot_matrix.""" + if axes is not None and figure is not None: + raise ValueError( + "Parameters figure and axes cannot be specified " + "together. You gave 'figure=%s, axes=%s'" % (figure, axes) + ) + if figure is not None: + if isinstance(figure, plt.Figure): + fig = figure + else: + fig = plt.figure(figsize=figure) + axes = plt.gca() + own_fig = True + else: + if axes is None: + fig, axes = plt.subplots(1, 1, figsize=(7, 5)) + own_fig = True + else: + fig = axes.figure + own_fig = False + return fig, axes, own_fig + + +def _sanitize_labels(mat_shape, labels): + """Helper function for plot_matrix.""" + # we need a list so an empty one will be cast to False + if isinstance(labels, np.ndarray): + labels = labels.tolist() + if labels and len(labels) != mat_shape[0]: + raise ValueError("Length of labels unequal to length of matrix.") + return labels + + +def _sanitize_tri(tri): + """Helper function for plot_matrix.""" + VALID_TRI_VALUES = set(["full", "lower", "diag"]) + if tri not in VALID_TRI_VALUES: + raise ValueError("Parameter tri needs to be " + "one of {}.".format(VALID_TRI_VALUES)) + + +def _sanitize_reorder(reorder): + """Helper function for plot_matrix.""" + VALID_REORDER_ARGS = set([True, False, 'single', 'complete', 'average']) + if reorder not in VALID_REORDER_ARGS: + raise ValueError("Parameter reorder needs to be " + "one of {}.".format(VALID_REORDER_ARGS)) + reorder = 'average' if reorder is True else reorder + return reorder + + +def _reorder_matrix(mat, labels, reorder): + """Helper function for plot_matrix. + + This function reorders the provided matrix. + """ + if not labels: + raise ValueError("Labels are needed to show the reordering.") + try: + from scipy.cluster.hierarchy import (linkage, + optimal_leaf_ordering, + leaves_list) + except ImportError: + raise ImportError("A scipy version of at least 1.0 is needed for " + "ordering the matrix with optimal_leaf_ordering.") + linkage_matrix = linkage(mat, method=reorder) + ordered_linkage = optimal_leaf_ordering(linkage_matrix, mat) + index = leaves_list(ordered_linkage) + # make sure labels is an ndarray and copy it + labels = np.array(labels).copy() + mat = mat.copy() + # and reorder labels and matrix + labels = labels[index].tolist() + mat = mat[index, :][:, index] + return mat, labels + + +def _mask_matrix(mat, tri): + """Helper function for plot_matrix. + + This function masks the matrix depending on the provided + value of ``tri``. + """ + if tri == 'lower': + mask = np.tri(mat.shape[0], k=-1, dtype=bool) ^ True + else: + mask = np.tri(mat.shape[0], dtype=bool) ^ True + return np.ma.masked_array(mat, mask) + + +def _configure_axis(axes, labels, label_size, + x_label_rotation, y_label_rotation): + """Helper function for plot_matrix.""" + if not labels: + axes.xaxis.set_major_formatter(plt.NullFormatter()) + axes.yaxis.set_major_formatter(plt.NullFormatter()) + else: + axes.set_xticks(np.arange(len(labels))) + axes.set_xticklabels(labels, size=label_size) + for label in axes.get_xticklabels(): + label.set_ha('right') + label.set_rotation(x_label_rotation) + axes.set_yticks(np.arange(len(labels))) + axes.set_yticklabels(labels, size=label_size) + for label in axes.get_yticklabels(): + label.set_ha('right') + label.set_va('top') + label.set_rotation(y_label_rotation) + + +def _configure_grid(axes, grid, tri, size): + """Helper function for plot_matrix.""" + # Different grids for different layouts + if tri == 'lower': + for i in range(size): + # Correct for weird mis-sizing + i = 1.001 * i + axes.plot([i + 0.5, i + 0.5], [size - 0.5, i + 0.5], color='grey') + axes.plot([i + 0.5, -0.5], [i + 0.5, i + 0.5], color='grey') + elif tri == 'diag': + for i in range(size): + # Correct for weird mis-sizing + i = 1.001 * i + axes.plot([i + 0.5, i + 0.5], [size - 0.5, i - 0.5], color='grey') + axes.plot([i + 0.5, -0.5], [i - 0.5, i - 0.5], color='grey') + else: + for i in range(size): + # Correct for weird mis-sizing + i = 1.001 * i + axes.plot([i + 0.5, i + 0.5], [size - 0.5, -0.5], color='grey') + axes.plot([size - 0.5, -0.5], [i + 0.5, i + 0.5], color='grey') + + @fill_doc def plot_matrix(mat, title=None, labels=None, figure=None, axes=None, colorbar=True, cmap=plt.cm.RdBu_r, tri='full', @@ -45,34 +194,46 @@ def plot_matrix(mat, title=None, labels=None, figure=None, axes=None, Parameters ---------- - mat : 2-D numpy array + mat : 2-D :class:`numpy.ndarray` Matrix to be plotted. %(title)s - labels : list, ndarray of strings, empty list, False, or None, optional + labels : :obj:`list`, or :class:`numpy.ndarray` of :obj:`str`,\ + or False, or None, optional The label of each row and column. Needs to be the same length as rows/columns of mat. If False, None, or an empty list, no labels are plotted. - figure : figure instance, figsize tuple, or None, optional + figure : :class:`matplotlib.figure.Figure`, figsize :obj:`tuple`,\ + or None, optional Sets the figure used. This argument can be either an existing figure, or a pair (width, height) that gives the size of a newly-created figure. - Specifying both axes and figure is not allowed. - axes : None or Axes, optional + .. note:: + + Specifying both axes and figure is not allowed. + + axes : None or :class:`matplotlib.axes.Axes`, optional Axes instance to be plotted on. Creates a new one if None. - Specifying both axes and figure is not allowed. + + .. note:: + + Specifying both axes and figure is not allowed. + %(colorbar)s Default=True. %(cmap)s Default=`plt.cm.RdBu_r`. tri : {'full', 'lower', 'diag'}, optional Which triangular part of the matrix to plot: - 'lower' is the lower part, 'diag' is the lower including - diagonal, and 'full' is the full matrix. + + - 'lower': Plot the lower part + - 'diag': Plot the lower part with the diagonal + - 'full': Plot the full matrix + Default='full'. - auto_fit : boolean, optional + auto_fit : :obj:`bool`, optional If auto_fit is True, the axes are dimensioned to give room for the labels. This assumes that the labels are resting against the bottom and left edges of the figure. @@ -82,7 +243,7 @@ def plot_matrix(mat, title=None, labels=None, figure=None, axes=None, If not False, a grid is plotted to separate rows and columns using the given color. Default=False. - reorder : boolean or {'single', 'complete', 'average'}, optional + reorder : :obj:`bool` or {'single', 'complete', 'average'}, optional If not False, reorders the matrix into blocks of clusters. Accepted linkage options for the clustering are 'single', 'complete', and 'average'. True defaults to average linkage. @@ -98,127 +259,39 @@ def plot_matrix(mat, title=None, labels=None, figure=None, axes=None, Returns ------- - display : instance of matplotlib + display : :class:`matplotlib.axes.Axes` Axes image. """ - # we need a list so an empty one will be cast to False - if isinstance(labels, np.ndarray): - labels = labels.tolist() - if labels and len(labels) != mat.shape[0]: - raise ValueError("Length of labels unequal to length of matrix.") - + labels, reorder, fig, axes, own_fig = _sanitize_inputs_plot_matrix( + mat.shape, tri, labels, reorder, figure, axes + ) if reorder: - if not labels: - raise ValueError("Labels are needed to show the reordering.") - try: - from scipy.cluster.hierarchy import (linkage, optimal_leaf_ordering, - leaves_list) - except ImportError: - raise ImportError("A scipy version of at least 1.0 is needed " - "for ordering the matrix with " - "optimal_leaf_ordering.") - valid_reorder_args = [True, 'single', 'complete', 'average'] - if reorder not in valid_reorder_args: - raise ValueError("Parameter reorder needs to be " - "one of {}.".format(valid_reorder_args)) - if reorder is True: - reorder = 'average' - linkage_matrix = linkage(mat, method=reorder) - ordered_linkage = optimal_leaf_ordering(linkage_matrix, mat) - index = leaves_list(ordered_linkage) - # make sure labels is an ndarray and copy it - labels = np.array(labels).copy() - mat = mat.copy() - # and reorder labels and matrix - labels = labels[index].tolist() - mat = mat[index, :][:, index] - - if tri == 'lower': - mask = np.tri(mat.shape[0], k=-1, dtype=bool) ^ True - mat = np.ma.masked_array(mat, mask) - elif tri == 'diag': - mask = np.tri(mat.shape[0], dtype=bool) ^ True - mat = np.ma.masked_array(mat, mask) - if axes is not None and figure is not None: - raise ValueError("Parameters figure and axes cannot be specified " - "together. You gave 'figure=%s, axes=%s'" - % (figure, axes)) - if figure is not None: - if isinstance(figure, plt.Figure): - fig = figure - else: - fig = plt.figure(figsize=figure) - axes = plt.gca() - own_fig = True - else: - if axes is None: - fig, axes = plt.subplots(1, 1, figsize=(7, 5)) - own_fig = True - else: - fig = axes.figure - own_fig = False + mat, labels = _reorder_matrix(mat, labels, reorder) + if tri != "full": + mat = _mask_matrix(mat, tri) display = axes.imshow(mat, aspect='equal', interpolation='nearest', cmap=cmap, **kwargs) axes.set_autoscale_on(False) ymin, ymax = axes.get_ylim() - if not labels: - axes.xaxis.set_major_formatter(plt.NullFormatter()) - axes.yaxis.set_major_formatter(plt.NullFormatter()) - else: - axes.set_xticks(np.arange(len(labels))) - axes.set_xticklabels(labels, size='x-small') - for label in axes.get_xticklabels(): - label.set_ha('right') - label.set_rotation(50) - axes.set_yticks(np.arange(len(labels))) - axes.set_yticklabels(labels, size='x-small') - for label in axes.get_yticklabels(): - label.set_ha('right') - label.set_va('top') - label.set_rotation(10) - + _configure_axis(axes, labels, label_size="x-small", + x_label_rotation=50, y_label_rotation=10) if grid is not False: - size = len(mat) - # Different grids for different layouts - if tri == 'lower': - for i in range(size): - # Correct for weird mis-sizing - i = 1.001 * i - axes.plot([i + 0.5, i + 0.5], [size - 0.5, i + 0.5], - color='grey') - axes.plot([i + 0.5, -0.5], [i + 0.5, i + 0.5], - color='grey') - elif tri == 'diag': - for i in range(size): - # Correct for weird mis-sizing - i = 1.001 * i - axes.plot([i + 0.5, i + 0.5], [size - 0.5, i - 0.5], - color='grey') - axes.plot([i + 0.5, -0.5], [i - 0.5, i - 0.5], color='grey') - else: - for i in range(size): - # Correct for weird mis-sizing - i = 1.001 * i - axes.plot([i + 0.5, i + 0.5], [size - 0.5, -0.5], color='grey') - axes.plot([size - 0.5, -0.5], [i + 0.5, i + 0.5], color='grey') - + _configure_grid(axes, grid, tri, len(mat)) axes.set_ylim(ymin, ymax) - if auto_fit: if labels: - fit_axes(axes) + _fit_axes(axes) elif own_fig: plt.tight_layout(pad=.1, rect=((0, 0, .95, 1) if colorbar else (0, 0, 1, 1))) - if colorbar: cax, kw = make_axes(axes, location='right', fraction=0.05, shrink=0.8, pad=.0) fig.colorbar(mappable=display, cax=cax) # make some room - fig.subplots_adjust(right=0.8) + fig.subplots_adjust(right=0.78) # change current axis back to matrix plt.sca(axes) @@ -231,7 +304,6 @@ def plot_matrix(mat, title=None, labels=None, figure=None, axes=None, verticalalignment='top', transform=axes.transAxes, size=size) - return display @@ -242,29 +314,30 @@ def plot_contrast_matrix(contrast_def, design_matrix, colorbar=False, ax=None, Parameters ---------- - contrast_def : str or array of shape (n_col) or list of (string or - array of shape (n_col)) + contrast_def : :obj:`str` or :class:`numpy.ndarray` of shape (n_col),\ + or :obj:`list` of :obj:`str`, or :class:`numpy.ndarray` of shape (n_col) where ``n_col`` is the number of columns of the design matrix, (one array per run). If only one array is provided when there are several runs, it will be assumed that the same contrast is desired for all runs. The string can be a formula compatible with - `pandas.DataFrame.eval`. Basically one can use the name of the + :meth:`pandas.DataFrame.eval`. Basically one can use the name of the conditions as they appear in the design matrix of the fitted model combined with operators +- and combined with numbers with operators +-`*`/. - design_matrix : pandas DataFrame + design_matrix : :class:`pandas.DataFrame` Design matrix to use. %(colorbar)s Default=False. - ax : matplotlib Axes object, optional + ax : :class:`matplotlib.axes.Axes`, optional Axis on which to plot the figure. If None, a new figure will be created. %(output_file)s Returns ------- - Plot Axes object + ax : :class:`matplotlib.axes.Axes` + Figure object. """ design_column_names = design_matrix.columns.tolist() @@ -306,25 +379,25 @@ def plot_contrast_matrix(contrast_def, design_matrix, colorbar=False, ax=None, @fill_doc def plot_design_matrix(design_matrix, rescale=True, ax=None, output_file=None): - """Plot a design matrix provided as a DataFrame + """Plot a design matrix provided as a :class:`pandas.DataFrame`. Parameters ---------- - design matrix : pandas DataFrame, + design matrix : :class:`pandas.DataFrame` Describes a design matrix. - rescale : bool, optional + rescale : :obj:`bool`, optional Rescale columns magnitude for visualization or not. Default=True. - ax : axis handle, optional - Handle to axis onto which we will draw design matrix. + ax : :class:`matplotlib.axes.Axes`, optional + Handle to axes onto which we will draw the design matrix. %(output_file)s Returns ------- - ax: axis handle - The axis used for plotting. + ax : :class:`matplotlib.axes.Axes` + The axes used for plotting. """ # normalize the values per column for better visualization @@ -366,19 +439,25 @@ def plot_event(model_event, cmap=None, output_file=None, **fig_kwargs): Parameters ---------- - model_event : pandas DataFrame or list of pandas DataFrame - The `pandas.DataFrame` must have three columns + model_event : :class:`pandas.DataFrame` or :obj:`list`\ + of :class:`pandas.DataFrame` + The :class:`pandas.DataFrame` must have three columns: ``event_type`` with event name, ``onset`` and ``duration``. - The `pandas.DataFrame` can also be obtained from - :func:`nilearn.glm.first_level.first_level_from_bids`. + + .. note:: + + The :class:`pandas.DataFrame` can also be obtained + from :func:`nilearn.glm.first_level.first_level_from_bids`. + %(cmap)s %(output_file)s **fig_kwargs : extra keyword arguments, optional - Extra arguments passed to matplotlib.pyplot.subplots. + Extra arguments passed to :func:`matplotlib.pyplot.subplots`. Returns ------- - Plot Figure object + figure : :class:`matplotlib.figure.Figure` + Plot Figure object. """ if isinstance(model_event, pd.DataFrame): diff --git a/nilearn/plotting/tests/test_matrix_plotting.py b/nilearn/plotting/tests/test_matrix_plotting.py index 459b7551ab..69f6eaadbb 100644 --- a/nilearn/plotting/tests/test_matrix_plotting.py +++ b/nilearn/plotting/tests/test_matrix_plotting.py @@ -5,6 +5,7 @@ import numpy as np import pandas as pd from nibabel.tmpdirs import InTemporaryDirectory +import matplotlib as mpl import matplotlib.pyplot as plt from nilearn.glm.first_level.design_matrix import ( @@ -17,55 +18,158 @@ ############################################################################## # Some smoke testing for graphics-related code +@pytest.mark.parametrize("fig,axes", + [("foo", "bar"), + (1, 2), + plt.subplots(1, 1, figsize=(7, 5))]) +def test_sanitize_figure_and_axes_error(fig, axes): + from ..matrix_plotting import _sanitize_figure_and_axes + with pytest.raises(ValueError, + match=("Parameters figure and axes cannot " + "be specified together.")): + _sanitize_figure_and_axes(fig, axes) -def test_matrix_plotting(): - from numpy import zeros, array - from nilearn.version import _compare_version - mat = zeros((10, 10)) - labels = [str(i) for i in range(10)] - ax = plot_matrix(mat, labels=labels, title='foo') - plt.close() - # test if plotting lower triangle works - ax = plot_matrix(mat, labels=labels, tri='lower') - # test if it returns an AxesImage + +@pytest.mark.parametrize("fig,axes,expected", + [((6, 4), None, True), + (plt.figure(figsize=(3, 2)), None, True), + (None, None, True), + (None, plt.subplots(1, 1)[1], False)]) +def test_sanitize_figure_and_axes(fig, axes, expected): + from ..matrix_plotting import _sanitize_figure_and_axes + fig2, axes2, own_fig = _sanitize_figure_and_axes(fig, axes) + assert isinstance(fig2, plt.Figure) + assert isinstance(axes2, plt.Axes) + assert own_fig == expected + + +def test_sanitize_labels(): + from ..matrix_plotting import _sanitize_labels + labs = ["foo", "bar"] + with pytest.raises(ValueError, + match="Length of labels unequal to length of matrix."): + _sanitize_labels((6, 6), labs) + for lab in [labs, np.array(labs)]: + assert _sanitize_labels((2, 2), lab) == labs + + +VALID_TRI_VALUES = set(["full", "lower", "diag"]) + + +@pytest.mark.parametrize("tri", VALID_TRI_VALUES) +def test_sanitize_tri(tri): + from ..matrix_plotting import _sanitize_tri + _sanitize_tri(tri) + + +@pytest.mark.parametrize("tri", [None, "foo", 2]) +def test_sanitize_tri_error(tri): + from ..matrix_plotting import _sanitize_tri + with pytest.raises(ValueError, + match=("Parameter tri needs to be " + f"one of {VALID_TRI_VALUES}")): + _sanitize_tri(tri) + + +VALID_REORDER_VALUES = set([True, False, 'single', 'complete', 'average']) + + +@pytest.mark.parametrize("reorder", VALID_REORDER_VALUES) +def test_sanitize_reorder(reorder): + from ..matrix_plotting import _sanitize_reorder + if reorder != True: # noqa + assert _sanitize_reorder(reorder) == reorder + else: + assert _sanitize_reorder(reorder) == 'average' + + +@pytest.mark.parametrize("reorder", [None, "foo", 2]) +def test_sanitize_reorder_error(reorder): + from ..matrix_plotting import _sanitize_reorder + with pytest.raises(ValueError, + match=("Parameter reorder needs to be " + f"one of {VALID_REORDER_VALUES}")): + _sanitize_reorder(reorder) + + +@pytest.fixture +def mat(): + return np.zeros((10, 10)) + + +@pytest.fixture +def labels(): + return [str(i) for i in range(10)] + + +@pytest.mark.parametrize("matrix,lab,reorder", + [(np.zeros((10, 10)), [0, 1, 2], False), + (np.zeros((10, 10)), None, True), + (np.zeros((10, 10)), + [str(i) for i in range(10)], ' ')]) +def test_matrix_plotting_errors(matrix, lab, reorder): + with pytest.raises(ValueError): + plot_matrix(matrix, labels=lab, reorder=reorder) + plt.close() + + +@pytest.mark.parametrize("tri", VALID_TRI_VALUES) +def test_matrix_plotting_with_labels_and_different_tri(mat, labels, tri): + ax = plot_matrix(mat, labels=labels, tri=tri) + assert isinstance(ax, mpl.image.AxesImage) ax.axes.set_title('Title') + assert ax._axes.get_title() == 'Title' + for axis in [ax._axes.xaxis, ax._axes.yaxis]: + assert len(axis.majorTicks) == len(labels) + for tick, label in zip(axis.majorTicks, labels): + assert tick.label1.get_text() == label plt.close() - ax = plot_matrix(mat, labels=labels, tri='diag') - ax.axes.set_title('Title') + + +@pytest.mark.parametrize("lab", + [[], + np.array([str(i) for i in range(10)]), + None]) +def test_matrix_plotting_labels(mat, lab): + plot_matrix(mat, labels=lab) plt.close() - # test if an empty list works as an argument for labels - ax = plot_matrix(mat, labels=[]) + + +@pytest.mark.parametrize("title", ["foo", "foo bar", " ", None]) +def test_matrix_plotting_set_title(mat, labels, title): + ax = plot_matrix(mat, labels=labels, title=title) + nb_txt = 0 if title is None else 1 + assert len(ax._axes.texts) == nb_txt + if title is not None: + assert ax._axes.texts[0].get_text() == title plt.close() - # test if an array gets correctly cast to a list - ax = plot_matrix(mat, labels=array(labels)) + + +@pytest.mark.parametrize("tri", VALID_TRI_VALUES) +def test_matrix_plotting_grid(mat, labels, tri): + plot_matrix(mat, labels=labels, grid=True, tri=tri) + + +def test_matrix_plotting_reorder(mat, labels): + from itertools import permutations + # test if reordering with default linkage works + idx = [2, 3, 5] + # make symmetric matrix of similarities so we can get a block + for perm in permutations(idx, 2): + mat[perm] = 1 + ax = plot_matrix(mat, labels=labels, reorder=True) + assert len(labels) == len(ax.axes.get_xticklabels()) + reordered_labels = [int(lbl.get_text()) + for lbl in ax.axes.get_xticklabels()] + # block order does not matter + assert( # noqa + (reordered_labels[:3] == idx or reordered_labels[-3:] == idx), + 'Clustering does not find block structure.' + ) plt.close() - # test if labels can be None - ax = plot_matrix(mat, labels=None) + # test if reordering with specific linkage works + ax = plot_matrix(mat, labels=labels, reorder='complete') plt.close() - pytest.raises(ValueError, plot_matrix, mat, labels=[0, 1, 2]) - - import scipy - if _compare_version(scipy.__version__, '>=', '1.0.0'): - # test if a ValueError is raised when reorder=True without labels - pytest.raises(ValueError, plot_matrix, mat, labels=None, reorder=True) - # test if a ValueError is raised when reorder argument is wrong - pytest.raises(ValueError, plot_matrix, mat, labels=labels, reorder=' ') - # test if reordering with default linkage works - idx = [2, 3, 5] - from itertools import permutations - # make symmetric matrix of similarities so we can get a block - for perm in permutations(idx, 2): - mat[perm] = 1 - ax = plot_matrix(mat, labels=labels, reorder=True) - assert len(labels) == len(ax.axes.get_xticklabels()) - reordered_labels = [int(lbl.get_text()) - for lbl in ax.axes.get_xticklabels()] - # block order does not matter - assert reordered_labels[:3] == idx or reordered_labels[-3:] == idx, 'Clustering does not find block structure.' - plt.close() - # test if reordering with specific linkage works - ax = plot_matrix(mat, labels=labels, reorder='complete') - plt.close() def test_show_design_matrix(): From c61e7a4f4779884ddc6a8ca4a28fb1e6bd16d2db Mon Sep 17 00:00:00 2001 From: Ben Greiner Date: Mon, 24 Jan 2022 14:40:29 +0100 Subject: [PATCH 30/44] [FIX] replace interpreter call (#3136) The python command is not guaranteed to exist. On some systems it refers to old python 2. See https://www.python.org/dev/peps/pep-0394/ --- nilearn/plotting/html_document.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nilearn/plotting/html_document.py b/nilearn/plotting/html_document.py index f93377cbb2..bfb166af00 100644 --- a/nilearn/plotting/html_document.py +++ b/nilearn/plotting/html_document.py @@ -1,4 +1,5 @@ import os +import sys import weakref import warnings import tempfile @@ -20,7 +21,7 @@ def set_max_img_views_before_warning(new_value): def _remove_after_n_seconds(file_name, n_seconds): script = os.path.join(os.path.dirname(__file__), 'rm_file.py') - subprocess.Popen(['python', script, file_name, str(n_seconds)]) + subprocess.Popen([sys.executable, script, file_name, str(n_seconds)]) class HTMLDocument(object): From 737c986b00aae07677a240f83156ef024cb961fc Mon Sep 17 00:00:00 2001 From: Gensollen Date: Mon, 24 Jan 2022 16:08:46 +0100 Subject: [PATCH 31/44] [FIX] `FirstLevelModel` signal_scaling (#3135) * Add failing test * get rid of scaling_axis attribute * deprecate scaling_axis * [circle full] add whatsnew entry * Fix --- doc/whats_new.rst | 6 +++++- nilearn/glm/first_level/first_level.py | 15 +++++++++++---- nilearn/glm/tests/test_first_level.py | 26 ++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/doc/whats_new.rst b/doc/whats_new.rst index ec0fdca4a9..2d86c2c2bf 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -84,7 +84,11 @@ Fixes - Convert reference in `nilearn/regions/region_extractor.py` to use footcite / footbibliography. (See issue `#2787 `_ and PR `#3111 `_). - Computation of Benjamini-Hocheberg threshold fixed in `nilearn/glm/thresholding.py` function (see issue `#2879 `_ and PR `#3137 `_) - +- Attribute `scaling_axis` of :class:`~nilearn.glm.first_level.FirstLevelModel` has + been deprecated and will be removed in 0.11.0. When scaling is performed, the + attribute `signal_scaling` is used to define the axis instead. + (See issue `#3134 `_ and PR + `#3135 `_). Enhancements ------------ diff --git a/nilearn/glm/first_level/first_level.py b/nilearn/glm/first_level/first_level.py index b36fe743ba..9bda46fb70 100644 --- a/nilearn/glm/first_level/first_level.py +++ b/nilearn/glm/first_level/first_level.py @@ -369,8 +369,7 @@ def __init__(self, t_r=None, slice_time_ref=0., hrf_model='glover', if signal_scaling is False: self.signal_scaling = signal_scaling elif signal_scaling in [0, 1, (0, 1)]: - self.scaling_axis = signal_scaling - self.signal_scaling = True + self.signal_scaling = signal_scaling self.standardize = False else: raise ValueError('signal_scaling must be "False", "0", "1"' @@ -385,6 +384,14 @@ def __init__(self, t_r=None, slice_time_ref=0., hrf_model='glover', self.results_ = None self.subject_label = subject_label + @property + def scaling_axis(self): + warn(DeprecationWarning( + "Deprecated. `scaling_axis` will be removed in 0.11.0. " + "Please use `signal_scaling` instead." + )) + return self.signal_scaling + def fit(self, run_imgs, events=None, confounds=None, design_matrices=None, bins=100): """Fit the GLM @@ -566,8 +573,8 @@ def fit(self, run_imgs, events=None, confounds=None, sys.stderr.write('Masker took %d seconds \n' % t_masking) - if self.signal_scaling: - Y, _ = mean_scaling(Y, self.scaling_axis) + if self.signal_scaling is not False: # noqa + Y, _ = mean_scaling(Y, self.signal_scaling) if self.memory: mem_glm = self.memory.cache(run_glm, ignore=['n_jobs']) else: diff --git a/nilearn/glm/tests/test_first_level.py b/nilearn/glm/tests/test_first_level.py index aac69394e7..df728241b3 100644 --- a/nilearn/glm/tests/test_first_level.py +++ b/nilearn/glm/tests/test_first_level.py @@ -711,6 +711,32 @@ def test_first_level_from_bids(): bids_path, 'main', 'T1w') # desc not specified +def test_first_level_with_scaling(): + shapes, rk = [(3, 1, 1, 2)], 1 + fmri_data = list() + fmri_data.append(Nifti1Image(np.zeros((1, 1, 1, 2)) + 6, np.eye(4))) + design_matrices = list() + design_matrices.append( + pd.DataFrame( + np.ones((shapes[0][-1], rk)), + columns=list('abcdefghijklmnopqrstuvwxyz')[:rk]) + ) + fmri_glm = FirstLevelModel( + mask_img=False, noise_model='ols', signal_scaling=0, + minimize_memory=True + ) + assert fmri_glm.signal_scaling == 0 + assert not fmri_glm.standardize + with pytest.warns(DeprecationWarning, + match="Deprecated. `scaling_axis` will be removed"): + assert fmri_glm.scaling_axis == 0 + glm_parameters = fmri_glm.get_params() + test_glm = FirstLevelModel(**glm_parameters) + fmri_glm = fmri_glm.fit(fmri_data, design_matrices=design_matrices) + test_glm = test_glm.fit(fmri_data, design_matrices=design_matrices) + assert glm_parameters['signal_scaling'] == 0 + + def test_first_level_with_no_signal_scaling(): """ test to ensure that the FirstLevelModel works correctly with a From 3fcc1554dc6adb85dc97543cfa59b1090f4aa66f Mon Sep 17 00:00:00 2001 From: ThomasBaz <6551732+thomasbazeille@users.noreply.github.com> Date: Tue, 25 Jan 2022 10:24:15 +0100 Subject: [PATCH 32/44] [ENH] Include Hierarchical KMeans in regions.Parcellations (#2282) * Including Hierarchical Kmeans in doc and example * Adding hierarchical k_means and make it available in parcellations * test hierarchical_kmeans and test Parcellation using it * fix incompatible apis of fit() and transform() methods * Improve docstring and example layout * "Upgrade to get_data function" * "changing nose function to pytest function as the rest of the library evolved" * "solving sklearn.utils.testing deprecation" * "improve flake8" * "flake8, missing import, adding test exception" * Apply suggestions from code review Including B.T. suggestions Co-authored-by: bthirion * "adding tests for 'scaling' and warning ; fixed scaling bug" * "test_refactoring" * "flake8 fixes" * "clarify example, fix PEP8" * Apply suggestions from code review Co-authored-by: bthirion * "apply suggestions from N.G. review" * Apply suggestions from code review Co-authored-by: Gensollen * "apply B.T refactoring" * "flake8" * "flake8" * "codespell" * "enforcing final number of clusters is the one asked by the user" * "solving bugging test_case" * "solving edge case" * "missing float casting" * "check that adjusted clusters are int" * "flake8 fix" * Update nilearn/regions/hierarchical_kmeans_clustering.py Co-authored-by: bthirion * Update examples/03_connectivity/plot_data_driven_parcellations.py Co-authored-by: bthirion * Update examples/03_connectivity/plot_data_driven_parcellations.py Co-authored-by: bthirion * "fix code review comments" * 'fix bug introduced by review suggestion' * Update nilearn/regions/hierarchical_kmeans_clustering.py Co-authored-by: Gensollen * Update nilearn/regions/hierarchical_kmeans_clustering.py Co-authored-by: Gensollen * Update nilearn/regions/hierarchical_kmeans_clustering.py Co-authored-by: Gensollen * Update nilearn/regions/hierarchical_kmeans_clustering.py Co-authored-by: Gensollen * "apply code review suggestions" * "add whats_new" * fixing docstring * addressing comments of jdockes * trying to fix pep8 violations * simplifying hierarchical k-means avoiding useless checks * pep8 * Addressing other comments by jdockes Co-authored-by: BAZEILLE Thomas Co-authored-by: bthirion Co-authored-by: Gensollen --- doc/connectivity/parcellating.rst | 18 +- doc/modules/reference.rst | 1 + doc/whats_new.rst | 6 + .../plot_data_driven_parcellations.py | 133 +++++++-- nilearn/regions/__init__.py | 3 +- .../regions/hierarchical_kmeans_clustering.py | 279 ++++++++++++++++++ nilearn/regions/parcellations.py | 21 +- .../test_hierarchical_kmeans_clustering.py | 61 ++++ nilearn/regions/tests/test_parcellations.py | 29 +- 9 files changed, 514 insertions(+), 37 deletions(-) create mode 100644 nilearn/regions/hierarchical_kmeans_clustering.py create mode 100644 nilearn/regions/tests/test_hierarchical_kmeans_clustering.py diff --git a/doc/connectivity/parcellating.rst b/doc/connectivity/parcellating.rst index 300aeb6b73..7d84b6a1df 100644 --- a/doc/connectivity/parcellating.rst +++ b/doc/connectivity/parcellating.rst @@ -49,12 +49,18 @@ Applying clustering * For a small number of clusters, it is preferable to use Kmeans clustering after spatially-smoothing the data. - Both clustering algorithms (as well as many others) are provided by - this object :class:`nilearn.regions.Parcellations` and full - code example in - :ref:`here`. - Ward clustering is the easiest to use, as it can be done with the Feature - agglomeration object. It is also quite fast. We detail it below. + Both algorithms are provided by this object + :class:`nilearn.regions.Parcellations` as well as two algorithms + tailored to more specific usecases: + + * :class:`nilearn.regions.ReNA` is a quicker alternative to Ward with a small loss of precision, it is + ideal to downsize the number of voxels by 10 quickly. + + * Hierarchical KMeans is useful to obtain a small number of clusters after + spatial smoothing, that will be better balanced than with Kmeans. + + All these algorithms are showcased in a full code example : + :ref:`here`. Below, we focus on explaining the principle of Ward. | diff --git a/doc/modules/reference.rst b/doc/modules/reference.rst index 6901ea8279..1ad9a7616b 100644 --- a/doc/modules/reference.rst +++ b/doc/modules/reference.rst @@ -351,6 +351,7 @@ the :ref:`user guide ` for more information and usage examples. RegionExtractor Parcellations ReNA + HierarchicalKMeans :mod:`nilearn.mass_univariate`: Mass-Univariate Analysis diff --git a/doc/whats_new.rst b/doc/whats_new.rst index 2d86c2c2bf..7b41a1c229 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -58,6 +58,12 @@ NEW through the spatial maps with a previous and next button. The users can filter the maps they wish to display by passing an integer, or a list of integers to :meth:`~nilearn.maskers.NiftiMapsMasker.generate_report`. +- New function :func:`nilearn.input_data.fmriprep_confounds` to load confound + variables easily from :term:`fMRIPrep` outputs. +- New class :class:`nilearn.regions.HierarchicalKMeans` which yields more + balanced clusters than `KMeans`. It is also callable through + :class:`nilearn.regions.Parcellations` using `method`=`hierarchical_kmeans` + Fixes ----- diff --git a/examples/03_connectivity/plot_data_driven_parcellations.py b/examples/03_connectivity/plot_data_driven_parcellations.py index 9709ab76d9..dc6215d59d 100644 --- a/examples/03_connectivity/plot_data_driven_parcellations.py +++ b/examples/03_connectivity/plot_data_driven_parcellations.py @@ -2,8 +2,8 @@ Clustering methods to learn a brain parcellation from fMRI ========================================================== -We use spatially-constrained Ward-clustering, KMeans, and Recursive Neighbor -Agglomeration (ReNA) to create a set of parcels. +We use spatially-constrained Ward-clustering, KMeans, Hierarchical KMeans +and Recursive Neighbor Agglomeration (ReNA) to create a set of parcels. In a high dimensional regime, these methods can be interesting to create a 'compressed' representation of the data, replacing the data @@ -11,13 +11,14 @@ subsequently be used for statistical analysis or machine learning. Also, these methods can be used to learn functional connectomes -and subsequently for classification tasks. +and subsequently for classification tasks or to analyze data at a local +level. References ---------- Which clustering method to use, an empirical comparison can be found in this -paper +paper: * Bertrand Thirion, Gael Varoquaux, Elvis Dohmatob, Jean-Baptiste Poline. `Which fMRI clustering gives good brain parcellations ? @@ -25,7 +26,7 @@ 2014. This parcellation may be useful in a supervised learning, see for -instance +instance: * Vincent Michel, Alexandre Gramfort, Gael Varoquaux, Evelyn Eger, Christine Keribin, Bertrand Thirion. `A supervised clustering approach @@ -43,6 +44,14 @@ # # We download one subject of the movie watching dataset from Internet +from matplotlib import patches, ticker +import matplotlib.pyplot as plt +from nilearn.image import get_data +import numpy as np +from nilearn.image import mean_img, index_img +from nilearn import plotting +import time +from nilearn.regions import Parcellations from nilearn import datasets dataset = datasets.fetch_development_fmri(n_subjects=1) @@ -58,11 +67,9 @@ # Transforming list of images to data matrix and build brain parcellations, # all can be done at once using `Parcellations` object. -from nilearn.regions import Parcellations # Computing ward for the first time, will be long... This can be seen by # measuring using time -import time start = time.time() # Agglomerative Clustering: ward @@ -102,8 +109,6 @@ # with the following code: ward_labels_img.to_filename('ward_parcellation.nii.gz') -from nilearn import plotting -from nilearn.image import mean_img, index_img first_plot = plotting.plot_roi(ward_labels_img, title="Ward parcellation", display_mode='xz') @@ -120,8 +125,6 @@ # clustering by averaging the signal on each parcel. # Grab number of voxels from attribute mask image (mask_img_). -import numpy as np -from nilearn.image import get_data original_voxels = np.sum(get_data(ward.mask_img_)) # Compute mean over time on the functional image to use the mean @@ -183,15 +186,109 @@ # Grab parcellations of brain image stored in attribute `labels_img_` kmeans_labels_img = kmeans.labels_img_ -plotting.plot_roi(kmeans_labels_img, mean_func_img, - title="KMeans parcellation", - display_mode='xz') +display = plotting.plot_roi(kmeans_labels_img, mean_func_img, + title="KMeans parcellation", + display_mode='xz') # kmeans_labels_img is a Nifti1Image object, it can be saved to file with # the following code: kmeans_labels_img.to_filename('kmeans_parcellation.nii.gz') -################################################################## +######################################################################### +# Brain parcellations with Hierarchical KMeans Clustering +# ------------------------------------------------------- +# +# As the number of images from which we try to cluster grows, +# voxels display more and more specific activity patterns causing +# KMeans clusters to be very unbalanced with a few big clusters and +# many voxels left as singletons. Hierarchical Kmeans algorithm is +# tailored to enforce more balanced clusterings. To do this, +# Hierarchical Kmeans does a first Kmeans clustering in square root of +# n_parcels. In a second step, it clusters voxels inside each +# of these parcels in m pieces with m adapted to the size of +# the cluster in order to have n balanced clusters in the end. +# +# This object uses method='hierarchical_kmeans' for Hierarchical KMeans +# clustering and 10mm smoothing and standardization to compare +# with the previous method. +start = time.time() +hkmeans = Parcellations(method='hierarchical_kmeans', n_parcels=50, + standardize=True, smoothing_fwhm=10, + memory='nilearn_cache', memory_level=1, + verbose=1) +# Call fit on functional dataset: single subject (less samples) +hkmeans.fit(dataset.func) + +########################################################################### +# Visualize: Brain parcellations (Hierarchical KMeans) +# .................................................... +# +# Grab parcellations of brain image stored in attribute `labels_img_` +hkmeans_labels_img = hkmeans.labels_img_ + +plotting.plot_roi(hkmeans_labels_img, mean_func_img, + title="Hierarchical KMeans parcellation", + display_mode='xz', cut_coords=display.cut_coords) + +# kmeans_labels_img is a :class:`nibabel.nifti1.Nifti1Image` object, it can be +# saved to file with the following code: +hkmeans_labels_img.to_filename('hierarchical_kmeans_parcellation.nii.gz') + +########################################################################### +# Compare Hierarchical Kmeans clusters with those from Kmeans +# ........................................................... +# To compare those, we'll first count how many voxels are contained in +# each of the 50 clusters for both algorithms and compare those sizes +# distribution. Hierarchical KMeans should give clusters closer to +# average (600 here) than KMeans. +# +# First count how many voxels have each label (except 0 which is the +# background). + +kmeans_labels, kmeans_counts = np.unique( + get_data(kmeans_labels_img), return_counts=True) + +_, hkmeans_counts = np.unique( + get_data(hkmeans_labels_img), return_counts=True) + +voxel_ratio = np.round(np.sum(kmeans_counts[1:]) / 50) + +# If all voxels not in background were balanced between clusters ... + +print("... each cluster should contain {} voxels".format(voxel_ratio)) + +########################################################################### +# Let's plot clusters sizes distributions for both algorithms +# +# You can just skip the plotting code, the important part is the figure + + +bins = np.concatenate([np.linspace(0, 500, 11), np.linspace( + 600, 2000, 15), np.linspace(3000, 10000, 8)]) +fig, axes = plt.subplots(nrows=2, sharex=True, gridspec_kw={ + 'height_ratios': [4, 1]}) +plt.semilogx() +axes[0].hist(kmeans_counts[1:], bins, color="blue") +axes[1].hist(hkmeans_counts[1:], bins, color="green") +axes[0].set_ylim(0, 16) +axes[1].set_ylim(4, 0) +axes[1].xaxis.set_major_formatter(ticker.ScalarFormatter()) +axes[1].yaxis.set_label_coords(-.08, 2) +fig.subplots_adjust(hspace=0) +plt.xlabel("Number of voxels (log)", fontsize=12) +plt.ylabel("Number of clusters", fontsize=12) +handles = [patches.Rectangle((0, 0), 1, 1, color=c, ec="k") + for c in ["blue", "green"]] +labels = ["Kmeans", "Hierarchical Kmeans"] +fig.legend(handles, labels, loc=(.5, .8)) +########################################################################### +# As we can see, half of the 50 KMeans clusters contain less than +# 100 voxels whereas three contain several thousands voxels +# Hierarchical KMeans yield better balanced clusters, with a significant +# proportion of them containing hundreds to thousands of voxels. +# + +########################################################################### # Brain parcellations with ReNA Clustering # ---------------------------------------- # @@ -218,7 +315,7 @@ rena.fit_transform(dataset.func) print("ReNA 5000 clusters: %.2fs" % (time.time() - start)) -################################################################## +########################################################################### # Visualize: Brain parcellations (ReNA) # ..................................... # @@ -233,7 +330,7 @@ plotting.plot_roi(ward_labels_img, title="ReNA parcellation", display_mode='xz', cut_coords=cut_coords) -################################################################## +########################################################################### # Compressed representation of ReNA clustering # ............................................ # @@ -264,7 +361,7 @@ title='ReNA compressed representation (5000 parcels)', vmin=vmin, vmax=vmax, display_mode='xz') -#################################################################### +########################################################################### # Even if the compressed signal is relatively close # to the original signal, we can notice that Ward Clustering # gives a slightly more accurate compressed representation. diff --git a/nilearn/regions/__init__.py b/nilearn/regions/__init__.py index 1202bc58f2..22f22a9d5f 100644 --- a/nilearn/regions/__init__.py +++ b/nilearn/regions/__init__.py @@ -11,10 +11,11 @@ from .parcellations import Parcellations from .rena_clustering import ReNA +from .hierarchical_kmeans_clustering import HierarchicalKMeans __all__ = [ 'connected_regions', 'RegionExtractor', 'connected_label_regions', 'img_to_signals_labels', 'signals_to_img_labels', 'img_to_signals_maps', 'signals_to_img_maps', - 'Parcellations', 'ReNA'] + 'Parcellations', 'ReNA', 'HierarchicalKMeans'] diff --git a/nilearn/regions/hierarchical_kmeans_clustering.py b/nilearn/regions/hierarchical_kmeans_clustering.py new file mode 100644 index 0000000000..aacb26e9f0 --- /dev/null +++ b/nilearn/regions/hierarchical_kmeans_clustering.py @@ -0,0 +1,279 @@ +import numpy as np +from sklearn.cluster import MiniBatchKMeans +from sklearn.base import TransformerMixin, ClusterMixin +from sklearn.base import BaseEstimator +from sklearn.utils import check_array +from sklearn.utils.validation import check_is_fitted +import warnings + + +def _remove_empty_labels(labels): + '''Removes empty values label values from labels list. + Returns labels mapped to np.arange(n_unique), + where n_unique is the number of unique values in labels''' + + vals = np.unique(labels) + inverse_vals = - np.ones(labels.max() + 1, dtype=int) + inverse_vals[vals] = np.arange(len(vals)) + return inverse_vals[labels] + + +def _adjust_small_clusters(array, n_clusters): + '''Takes a ndarray of floats summing to n_clusters and try to round it while + enforcing rounded array still sum to n_clusters and every element is at + least 1. + ''' + + array_round = np.rint(array).astype(int) + array_round = np.maximum(array_round, 1) + + if np.sum(array_round) < n_clusters: + while np.sum(array_round) != n_clusters: + idx = np.argmax(array - array_round) + array_round[idx] += 1 + elif np.sum(array_round) == n_clusters: + pass + elif np.sum(array_round) > n_clusters: + parent_idx_ = np.arange(array_round.shape[0]) + while np.sum(array_round) != n_clusters: + # prevent element rounded to 1 to be decreased in edge cases + mask = array_round != 1 + idx = np.argmin(array[mask] - array_round[mask]) + parent_idx = parent_idx_[mask][idx] + array_round[parent_idx] -= 1 + return array_round + + +def hierarchical_k_means(X, n_clusters, init="k-means++", batch_size=1000, + n_init=10, max_no_improvement=10, verbose=0, + random_state=0): + """ Use a recursive k-means to cluster X. First clustering in sqrt(n_clusters) + parcels, and Kmeans a second time on each parcel. s + + Parameters + ---------- + X: ndarray (n_samples, n_features) + Data to cluster + + n_clusters: int, + The number of clusters to find. + + init : {'k-means++', 'random' or an ndarray} + Method for initialization, defaults to 'k-means++': + 'k-means++' : selects initial cluster centers for k-means + clustering in a smart way to speed up convergence. See section + Notes in k_init for more details. + 'random': choose k observations (rows) at random from data for + the initial centroids. + If an ndarray is passed, it should be of shape (n_clusters, n_features) + and gives the initial centers. + + batch_size : int, optional, default: 1000 + Size of the mini batches. (Kmeans performed through MiniBatchKMeans) + + n_init : int, default=10 + Number of random initializations that are tried. + In contrast to KMeans, the algorithm is only run once, using the + best of the ``n_init`` initializations as measured by inertia. + + max_no_improvement : int, default: 10 + Control early stopping based on the consecutive number of mini + batches that does not yield an improvement on the smoothed inertia. + To disable convergence detection based on inertia, set + max_no_improvement to None. + + random_state : int, RandomState instance or None (default) + Determines random number generation for centroid initialization and + random reassignment. Use an int to make the randomness deterministic. + + Returns + ------- + labels : list of ints (len n_features) + Parcellation of features in clusters + """ + + n_big_clusters = int(np.sqrt(n_clusters)) + mbk = MiniBatchKMeans(init=init, n_clusters=n_big_clusters, + batch_size=batch_size, n_init=n_init, + max_no_improvement=max_no_improvement, + verbose=verbose, random_state=random_state).fit(X) + coarse_labels = mbk.labels_ + fine_labels = np.zeros_like(coarse_labels) + q = 0 + counts = np.bincount(coarse_labels) + exact_clusters = np.asarray([n_clusters * counts[i] * 1. + / X.shape[0] for i in range(n_big_clusters)]) + + adjusted_clusters = _adjust_small_clusters(exact_clusters, n_clusters) + for i, n_small_clusters in enumerate(adjusted_clusters): + mbk = MiniBatchKMeans(init=init, n_clusters=n_small_clusters, + batch_size=batch_size, random_state=random_state, + max_no_improvement=max_no_improvement, + verbose=verbose, + n_init=n_init,).fit(X[coarse_labels == i]) + fine_labels[coarse_labels == i] = q + mbk.labels_ + q += n_small_clusters + + return _remove_empty_labels(fine_labels) + + +class HierarchicalKMeans(BaseEstimator, ClusterMixin, TransformerMixin): + """Hierarchical KMeans: + First clusterize the samples into big clusters. Then clusterize the samples + inside these big clusters into smaller ones. + + Parameters + ---------- + n_clusters: int + The number of clusters to find. + + init : {'k-means++', 'random' or an ndarray} + Method for initialization, defaults to 'k-means++': + + * 'k-means++' : selects initial cluster centers for k-means + clustering in a smart way to speed up convergence. See section + Notes in k_init for more details. + + * 'random': choose k observations (rows) at random from data for + the initial centroids. + + * If an ndarray is passed, it should be of shape (n_clusters, + n_features) and gives the initial centers. + + batch_size : int, optional, default: 1000 + Size of the mini batches. (Kmeans performed through MiniBatchKMeans) + + n_init : int, default=10 + Number of random initializations that are tried. + In contrast to KMeans, the algorithm is only run once, using the + best of the ``n_init`` initializations as measured by inertia. + + max_no_improvement : int, default: 10 + Control early stopping based on the consecutive number of mini + batches that does not yield an improvement on the smoothed inertia. + To disable convergence detection based on inertia, set + max_no_improvement to None. + + random_state : int, RandomState instance or None (default) + Determines random number generation for centroid initialization and + random reassignment. Use an int to make the randomness deterministic. + + scaling: bool, optional (default False) + If scaling is True, each cluster is scaled by the square root of its + size during transform(), preserving the l2-norm of the image. + inverse_transform() will apply inversed scaling to yield an image with + same l2-norm as input. + + verbose: int, optional (default 0) + Verbosity level. + + Attributes + ---------- + `labels_ `: ndarray, shape = [n_features] + cluster labels for each feature. + + `sizes_`: ndarray, shape = [n_features] + It contains the size of each cluster. + + """ + + def __init__(self, n_clusters, init="k-means++", batch_size=1000, + n_init=10, max_no_improvement=10, verbose=0, random_state=0, + scaling=False): + self.n_clusters = n_clusters + self.init = init + self.batch_size = batch_size + self.n_init = n_init + self.max_no_improvement = max_no_improvement + self.verbose = verbose + self.random_state = random_state + self.scaling = scaling + + def fit(self, X, y=None): + """Compute clustering of the data. + + Parameters + ---------- + X: ndarray, shape = [n_features, n_samples] + Training data. + y: Ignored + + Returns + ------- + self + """ + + X = check_array(X, ensure_min_features=2, ensure_min_samples=2, + estimator=self) + n_features = X.shape[1] + + if self.n_clusters <= 0: + raise ValueError("n_clusters should be an integer greater than 0." + " %s was provided." % str(self.n_clusters)) + + if self.n_clusters > n_features: + self.n_clusters = n_features + warnings.warn("n_clusters should be at most the number of " + "features. Taking n_clusters = %s instead." + % str(n_features)) + self.labels_ = hierarchical_k_means(X, self.n_clusters, self.init, + self.batch_size, self.n_init, + self.max_no_improvement, + self.verbose, self.random_state) + sizes = np.bincount(self.labels_) + + self.sizes_ = sizes + self.n_clusters = len(sizes) + return self + + def transform(self, X, y=None): + """Apply clustering, reduce the dimensionality of the data. + + Parameters + ---------- + X: ndarray, shape = [n_features, n_samples] + Data to transform with the fitted clustering. + + Returns + ------- + X_red: ndarray, shape = [n_clusters, n_samples] + Data reduced with agglomerated signal for each cluster + """ + + check_is_fitted(self, "labels_") + unique_labels = np.arange(self.n_clusters) + + mean_cluster = np.empty( + (len(unique_labels), X.shape[1]), dtype=X.dtype) + for label in unique_labels: + mean_cluster[label] = np.mean(X[self.labels_ == label], axis=0) + + X_red = np.array(mean_cluster) + + if self.scaling: + X_red = X_red * np.sqrt(self.sizes_[:, np.newaxis]) + + return X_red + + def inverse_transform(self, X_red): + """Send the reduced 2D data matrix back to the original feature + space (voxels). + + Parameters + ---------- + X_red: ndarray , shape = [n_clusters, n_samples] + Data reduced with agglomerated signal for each cluster + + Returns + ------- + X_inv: ndarray, shape = [n_features, n_samples] + Data reduced expanded to the original feature space + """ + + check_is_fitted(self, "labels_") + inverse = self.labels_ + if self.scaling: + X_red = X_red / np.sqrt(self.sizes_[:, np.newaxis]) + X_inv = X_red[inverse, ...] + + return X_inv diff --git a/nilearn/regions/parcellations.py b/nilearn/regions/parcellations.py index c6292434b4..d66ac8d008 100644 --- a/nilearn/regions/parcellations.py +++ b/nilearn/regions/parcellations.py @@ -9,6 +9,7 @@ from joblib import Memory, delayed, Parallel from .rena_clustering import ReNA +from .hierarchical_kmeans_clustering import HierarchicalKMeans from ..decomposition.multi_pca import MultiPCA from nilearn.maskers import NiftiLabelsMasker from .._utils.niimg import _safe_get_data @@ -27,7 +28,10 @@ def _estimator_fit(data, estimator, method=None): estimator : instance of estimator from sklearn MiniBatchKMeans or AgglomerativeClustering. - method : str, {'kmeans', 'ward', 'complete', 'average', 'rena'}, optional + method: str, + {'kmeans', 'ward', 'complete', 'average', 'rena', 'hierarchical_kmeans'}, + optional + A method to choose between for brain parcellations. Returns @@ -128,7 +132,8 @@ class Parcellations(MultiPCA): Parameters ---------- - method : :obj:`str`, {'kmeans', 'ward', 'complete', 'average', 'rena'} + method: :obj:`str`, {'kmeans', 'ward', 'complete', 'average', 'rena', + 'hierarchical_kmeans'} A method to choose between for brain parcellations. For a small number of parcels, kmeans is usually advisable. For a large number of parcellations (several hundreds, or thousands), @@ -248,7 +253,8 @@ class Parcellations(MultiPCA): giving the matrix. """ - VALID_METHODS = ['kmeans', 'ward', 'complete', 'average', 'rena'] + VALID_METHODS = ['kmeans', 'ward', 'complete', + 'average', 'rena', 'hierarchical_kmeans'] def __init__(self, method, n_parcels=50, random_state=0, mask=None, smoothing_fwhm=4., @@ -339,6 +345,15 @@ def _raw_fit(self, data): verbose=max(0, self.verbose - 1)) labels = self._cache(_estimator_fit, func_memory_level=1)(components.T, kmeans) + elif self.method == 'hierarchical_kmeans': + hkmeans = HierarchicalKMeans(self.n_parcels, init="k-means++", + batch_size=1000, n_init=10, + max_no_improvement=10, + random_state=self.random_state, + verbose=max(0, self.verbose - 1)) + # data ou data.T + labels = self._cache(_estimator_fit, + func_memory_level=1)(components.T, hkmeans) elif self.method == 'rena': rena = ReNA(mask_img_, n_clusters=self.n_parcels, diff --git a/nilearn/regions/tests/test_hierarchical_kmeans_clustering.py b/nilearn/regions/tests/test_hierarchical_kmeans_clustering.py new file mode 100644 index 0000000000..2dc4845acb --- /dev/null +++ b/nilearn/regions/tests/test_hierarchical_kmeans_clustering.py @@ -0,0 +1,61 @@ +from nilearn.input_data import NiftiMasker +import numpy as np +from numpy.testing import assert_array_almost_equal +from nilearn._utils.data_gen import generate_fake_fmri +from nilearn.regions.hierarchical_kmeans_clustering import ( + hierarchical_k_means, _adjust_small_clusters, + HierarchicalKMeans) +import pytest +525.25 / 2 + + +def test_adjust_small_clusters(): + test_lists = [[2.4, 2.6], [2.7, 3.0, 3.3], [ + 10 / 3, 10 / 3, 10 / 3], [1 / 3, 11 / 3, 11 / 3, 10 / 3]] + n_clusters_list = [5, 9, 10, 11] + + for list, n_clusters in zip(test_lists, n_clusters_list): + list = np.asarray(list) + assert(np.sum(list) == n_clusters) + list_round = _adjust_small_clusters(list, n_clusters) + assert(np.all(list_round != 0)) + assert(np.sum(list_round) == n_clusters) + for a in list_round: + assert(isinstance(a, (int, np.integer))) + + +def test_hierarchical_k_means(): + X = [[10, -10, 30], [12, -8, 24]] + truth_labels = np.tile([0, 1, 2], 5) + X = np.tile(X, 5).T + test_labels = hierarchical_k_means(X, 3) + truth_labels = np.tile([test_labels[0], test_labels[1], test_labels[2]], 5) + assert_array_almost_equal(test_labels, truth_labels) + + +def test_hierarchical_k_means_clustering(): + data_img, mask_img = generate_fake_fmri(shape=(10, 11, 12), length=15) + masker = NiftiMasker(mask_img=mask_img).fit() + X = masker.transform(data_img).T + + with pytest.raises(ValueError, + match="n_clusters should be an integer greater than 0." + " -2 was provided."): + HierarchicalKMeans(n_clusters=-2).fit(X) + + hkmeans = HierarchicalKMeans(n_clusters=8) + X_red = hkmeans.fit_transform(X) + X_compress = hkmeans.inverse_transform(X_red) + + assert_array_almost_equal(X.shape, X_compress.shape) + + hkmeans_scaled = HierarchicalKMeans(n_clusters=8, scaling=True) + X_red_scaled = hkmeans_scaled.fit_transform(X) + sizes = hkmeans_scaled.sizes_ + X_compress_scaled = hkmeans_scaled.inverse_transform(X_red_scaled) + + assert_array_almost_equal(np.asarray( + [np.sqrt(s) * a for s, a in zip(sizes, X_red)]), X_red_scaled) + assert_array_almost_equal(X_compress, X_compress_scaled) + + del X_red, X_compress, X_red_scaled, X_compress_scaled diff --git a/nilearn/regions/tests/test_parcellations.py b/nilearn/regions/tests/test_parcellations.py index 059ef413d4..d77cf431d2 100644 --- a/nilearn/regions/tests/test_parcellations.py +++ b/nilearn/regions/tests/test_parcellations.py @@ -9,7 +9,8 @@ _check_parameters_transform) -METHODS = ['kmeans', 'ward', 'complete', 'average', 'rena'] +METHODS = ['kmeans', 'ward', 'complete', 'average', 'rena', + 'hierarchical_kmeans'] @pytest.fixture @@ -58,19 +59,18 @@ def test_parcellations_fit_on_single_nifti_image(method, n_parcel, test_image): parcellator = Parcellations(method=method, n_parcels=n_parcel) parcellator.fit(test_image) # Test that object returns attribute labels_img_ - assert parcellator.labels_img_ is not None + labels_img = parcellator.labels_img_ + assert labels_img is not None + # After inverse_transform, shape must match with + # original input data + assert labels_img.shape == test_image.shape[:3] # Test object returns attribute masker_ assert parcellator.masker_ is not None assert parcellator.mask_img_ is not None - if method not in ['kmeans', 'rena']: + if method not in ['kmeans', 'rena', 'hierarchical_kmeans']: # Test that object returns attribute connectivity_ # only for AgglomerativeClustering methods assert parcellator.connectivity_ is not None - labels_img = parcellator.labels_img_ - assert parcellator.labels_img_ is not None - # After inverse_transform, shape must match with - # original input data - assert labels_img.shape == test_image.shape[:3] def test_parcellations_warnings(test_empty_image): @@ -92,6 +92,15 @@ def test_parcellations_fit_on_multi_nifti_images(method, test_image): parcellator = Parcellations(method=method, n_parcels=5) parcellator.fit(fmri_imgs) assert parcellator.labels_img_ is not None + + parcellator = Parcellations(method='rena', n_parcels=5) + parcellator.fit(fmri_imgs) + assert parcellator.labels_img_ is not None + + parcellator = Parcellations(method='hierarchical_kmeans', n_parcels=5) + parcellator.fit(fmri_imgs) + assert parcellator.labels_img_ is not None + # Smoke test with explicit mask image mask_img = np.ones((10, 11, 12)) mask_img = nibabel.Nifti1Image(mask_img, np.eye(4)) @@ -136,6 +145,7 @@ def test_parcellations_transform_multi_nifti_images(method, assert len(signals) == len(fmri_imgs) + def test_check_parameters_transform(test_image_2): rng = np.random.RandomState(42) # single confound @@ -163,6 +173,7 @@ def test_check_parameters_transform(test_image_2): # Test the error when length of images and confounds are not same msg = ("Number of confounds given does not match with the " "given number of images") + not_match_confounds_list = [confounds] * 2 with pytest.raises(ValueError, match=msg): _check_parameters_transform(fmri_imgs, not_match_confounds_list) @@ -194,7 +205,7 @@ def test_fit_transform(method, n_parcel, test_image_2): parcellator = Parcellations(method=method, n_parcels=n_parcel) signals = parcellator.fit_transform(fmri_imgs) assert parcellator.labels_img_ is not None - if method not in ['kmeans', 'rena']: + if method not in ['kmeans', 'rena', 'hierarchical_kmeans']: assert parcellator.connectivity_ is not None assert parcellator.masker_ is not None # fit_transform with confounds From da18fdc1b42741358b397355521f5d663dd2f463 Mon Sep 17 00:00:00 2001 From: Gensollen Date: Tue, 25 Jan 2022 13:47:49 +0100 Subject: [PATCH 33/44] [DOC] Fix wrong whats_new entry (#3142) --- doc/whats_new.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/whats_new.rst b/doc/whats_new.rst index 7b41a1c229..13fa36220d 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -58,8 +58,6 @@ NEW through the spatial maps with a previous and next button. The users can filter the maps they wish to display by passing an integer, or a list of integers to :meth:`~nilearn.maskers.NiftiMapsMasker.generate_report`. -- New function :func:`nilearn.input_data.fmriprep_confounds` to load confound - variables easily from :term:`fMRIPrep` outputs. - New class :class:`nilearn.regions.HierarchicalKMeans` which yields more balanced clusters than `KMeans`. It is also callable through :class:`nilearn.regions.Parcellations` using `method`=`hierarchical_kmeans` From d1466c231699f9db876cd6e0e9b77b0dd1b309ed Mon Sep 17 00:00:00 2001 From: bthirion Date: Tue, 25 Jan 2022 15:40:33 +0100 Subject: [PATCH 34/44] [FIX] Fix hommel value computation (#3109) * added deploy key * clean deploy key * clean deploy key * clean cricreci.yml * clean circleci.yml * clean circleci.yml * clean circleci.yml * fixed Hommel function + added test * pep8 fixes * pep8 fixes * pep8 fixes * correct use of assert * revert unrelated change * minor fixed on hommel value computation * addedwhatsnew entry Co-authored-by: Gensollen --- doc/whats_new.rst | 2 ++ nilearn/glm/tests/test_thresholding.py | 19 +++++++++++++++++++ nilearn/glm/thresholding.py | 11 +++++++---- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/doc/whats_new.rst b/doc/whats_new.rst index 13fa36220d..748004baf5 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -87,6 +87,8 @@ Fixes index (See PR `#3078 `_). - Convert reference in `nilearn/regions/region_extractor.py` to use footcite / footbibliography. (See issue `#2787 `_ and PR `#3111 `_). +- Fixed Hommel value computation in `nilearn/glm/thresholding.py` used in the + `cluster_level_inference` function. See PR `#3109 `_ - Computation of Benjamini-Hocheberg threshold fixed in `nilearn/glm/thresholding.py` function (see issue `#2879 `_ and PR `#3137 `_) - Attribute `scaling_axis` of :class:`~nilearn.glm.first_level.FirstLevelModel` has been deprecated and will be removed in 0.11.0. When scaling is performed, the diff --git a/nilearn/glm/tests/test_thresholding.py b/nilearn/glm/tests/test_thresholding.py index 340676c90e..cfd3125ee1 100644 --- a/nilearn/glm/tests/test_thresholding.py +++ b/nilearn/glm/tests/test_thresholding.py @@ -9,6 +9,7 @@ from nilearn.image import get_data from nilearn.glm import (cluster_level_inference, fdr_threshold, threshold_stats_img) +from nilearn.glm.thresholding import _compute_hommel_value def test_fdr(): @@ -108,6 +109,24 @@ def test_threshold_stats_img(): threshold_stats_img(None, None, alpha=0.05, height_control='plop') +def test_hommel(): + # Check that the computation of Hommel value + # For these, we take the example in Meijer et al. 2017 + # 'A shortcut for Hommel's procedure in linearithmic time' + # and check that we obtain the same values + z = norm.isf([1.e-8, .01, .08, .1, .5, .7, .9]) + assert _compute_hommel_value(z, 1.e-9) == 7 + assert _compute_hommel_value(z, 1.e-7) == 6 + assert _compute_hommel_value(z, .059) == 6 + assert _compute_hommel_value(z, .061) == 5 + assert _compute_hommel_value(z, .249) == 5 + assert _compute_hommel_value(z, .251) == 4 + assert _compute_hommel_value(z, .399) == 4 + assert _compute_hommel_value(z, .401) == 3 + assert _compute_hommel_value(z, .899) == 3 + assert _compute_hommel_value(z, .901) == 0 + + def test_all_resolution_inference(): shape = (9, 10, 11) p = np.prod(shape) diff --git a/nilearn/glm/thresholding.py b/nilearn/glm/thresholding.py index ca0dd124be..92f775d7f5 100644 --- a/nilearn/glm/thresholding.py +++ b/nilearn/glm/thresholding.py @@ -27,9 +27,11 @@ def _compute_hommel_value(z_vals, alpha, verbose=False): return p_vals[0] > alpha if p_vals[0] > alpha: return n_samples - slopes = (alpha - p_vals[: - 1]) / np.arange(n_samples, 1, -1) + if p_vals[-1] < alpha: + return 0 + slopes = (alpha - p_vals[: - 1]) / np.arange(n_samples - 1, 0, -1) slope = np.max(slopes) - hommel_value = np.trunc(n_samples + (alpha - slope * n_samples) / slope) + hommel_value = np.trunc(alpha / slope) if verbose: try: from matplotlib import pyplot as plt @@ -38,11 +40,11 @@ def _compute_hommel_value(z_vals, alpha, verbose=False): 'Please install it using `pip install matplotlib`.') else: plt.figure() - plt.plot(p_vals, 'o') + plt.plot(np.arange(1, 1 + n_samples), p_vals, 'o') plt.plot([n_samples - hommel_value, n_samples], [0, alpha]) plt.plot([0, n_samples], [0, 0], 'k') plt.show(block=False) - return np.minimum(hommel_value, n_samples) + return int(np.minimum(hommel_value, n_samples)) def _true_positive_fraction(z_vals, hommel_value, alpha): @@ -170,6 +172,7 @@ def cluster_level_inference(stat_img, mask_img=None, for threshold_ in sorted(threshold): label_map, n_labels = label(stat_map > threshold_) labels = label_map[get_data(masker.mask_img_) > 0] + for label_ in range(1, n_labels + 1): # get the z-vals in the cluster cluster_vals = stats[labels == label_] From 3e900a94f5dd188296d5347339249d72b9e5281d Mon Sep 17 00:00:00 2001 From: Gensollen Date: Wed, 26 Jan 2022 10:09:02 +0100 Subject: [PATCH 35/44] [DOC] Refactor change logs (#3049) * Add gh_substitutions * Add links to contributor profiles (unfinished) * Use contributor links in AUTHORS * Break and refactor changelog (unfinished...) * [circle full] Fix typo and run full build in strict mode. * Add more links * iter * [circle full] request full build * Add more links again * [circle full] Iter. * Update AUTHORS.rst * gh_role --> _gh_role * [circle full] Add fundings. * [circle full] Fix wrong ref. * [circle full] update niconnect link * [circle full] fix ref * fix refs: input_data -> maskers * [circle full] request full build * [circle full] fix old ref to fetch_cobre * [circle full] fix broken ref * [circle full] Fix error in rebase --- AUTHORS.rst | 90 +- doc/changes/0.1.0.rst | 44 + doc/changes/0.1.1.rst | 24 + doc/changes/0.1.2.rst | 14 + doc/changes/0.1.3.rst | 59 + doc/changes/0.1.4.rst | 31 + doc/changes/0.2.0.rst | 86 ++ doc/changes/0.2.1.rst | 10 + doc/changes/0.2.2.rst | 76 + doc/changes/0.2.3.rst | 30 + doc/changes/0.2.4.rst | 31 + doc/changes/0.2.5.rst | 83 + doc/changes/0.2.6.rst | 47 + doc/changes/0.3.0.rst | 115 ++ doc/changes/0.3.1.rst | 51 + doc/changes/0.4.0.rst | 98 ++ doc/changes/0.4.1.rst | 43 + doc/changes/0.4.2.rst | 29 + doc/changes/0.5.0.rst | 290 ++++ doc/changes/0.5.1.rst | 89 ++ doc/changes/0.5.2.rst | 32 + doc/changes/0.6.0.rst | 282 ++++ doc/changes/0.6.1.rst | 28 + doc/changes/0.6.2.rst | 40 + doc/changes/0.7.0.rst | 117 ++ doc/changes/0.7.1.rst | 56 + doc/changes/0.8.0.rst | 112 ++ doc/changes/0.8.1.rst | 66 + doc/changes/latest.rst | 202 +++ doc/changes/names.rst | 191 +++ doc/changes/whats_new.rst | 62 + doc/conf.py | 1 + doc/index.rst | 2 +- doc/logos/hbp-logo.png | Bin 0 -> 24409 bytes doc/sphinxext/gh_substitutions.py | 30 + doc/themes/nilearn/layout.html | 8 +- doc/whats_new.rst | 2408 ----------------------------- 37 files changed, 2525 insertions(+), 2452 deletions(-) create mode 100644 doc/changes/0.1.0.rst create mode 100644 doc/changes/0.1.1.rst create mode 100644 doc/changes/0.1.2.rst create mode 100644 doc/changes/0.1.3.rst create mode 100644 doc/changes/0.1.4.rst create mode 100644 doc/changes/0.2.0.rst create mode 100644 doc/changes/0.2.1.rst create mode 100644 doc/changes/0.2.2.rst create mode 100644 doc/changes/0.2.3.rst create mode 100644 doc/changes/0.2.4.rst create mode 100644 doc/changes/0.2.5.rst create mode 100644 doc/changes/0.2.6.rst create mode 100644 doc/changes/0.3.0.rst create mode 100644 doc/changes/0.3.1.rst create mode 100644 doc/changes/0.4.0.rst create mode 100644 doc/changes/0.4.1.rst create mode 100644 doc/changes/0.4.2.rst create mode 100644 doc/changes/0.5.0.rst create mode 100644 doc/changes/0.5.1.rst create mode 100644 doc/changes/0.5.2.rst create mode 100644 doc/changes/0.6.0.rst create mode 100644 doc/changes/0.6.1.rst create mode 100644 doc/changes/0.6.2.rst create mode 100644 doc/changes/0.7.0.rst create mode 100644 doc/changes/0.7.1.rst create mode 100644 doc/changes/0.8.0.rst create mode 100644 doc/changes/0.8.1.rst create mode 100644 doc/changes/latest.rst create mode 100644 doc/changes/names.rst create mode 100644 doc/changes/whats_new.rst create mode 100644 doc/logos/hbp-logo.png create mode 100644 doc/sphinxext/gh_substitutions.py delete mode 100644 doc/whats_new.rst diff --git a/AUTHORS.rst b/AUTHORS.rst index eb97242616..f0335a8c0c 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -1,5 +1,7 @@ .. -*- mode: rst -*- +.. include:: changes/names.rst + People ------ @@ -11,7 +13,7 @@ and the `scikit-learn `_ but grew much further. An up-to-date list of contributors can be seen in on `GitHub `_ -Additional credit goes to M. Hanke and Y. Halchenko for data and packaging. +Additional credit goes to `Michael Hanke`_ and `Yaroslav Halchenko`_ for data and packaging. .. _core_devs: @@ -20,20 +22,18 @@ Core developers The nilearn core developers are: -* `Alexandre Gramfort `_ -* `Alexis Thual `_ -* `Bertrand Thirion `_ -* `Binh Nguyen `_ -* `Elizabeth DuPre `_ -* `Gael Varoquaux `_ -* `Hao-Ting Wang `_ -* `Jerome Dockes `_ -* `Julia Huntenburg `_ -* `Kamalaker Dadi `_ -* `Kshitij Chawla `_ -* `Nicolas Gensollen `_ -* `Taylor Salo `_ -* `Thomas Bazeille `_ +* `Alexandre Gramfort`_ +* `Alexis Thual`_ +* `Bertrand Thirion`_ +* `Binh Nguyen`_ +* `Elizabeth DuPre`_ +* `Gael Varoquaux`_ +* `Hao-Ting Wang`_ +* `Jerome Dockes`_ +* `Julia Huntenburg`_ +* `Nicolas Gensollen`_ +* `Taylor Salo`_ +* `Thomas Bazeille`_ .. _triage: @@ -47,34 +47,41 @@ Other contributors Some other past or present contributors are: -* Abadie, A. -* Abraham, A. -* Bellec, P. -* Bougacha, S. -* Bzdok, D. -* Chevalier, J.A. -* Cipollini., B. -* Dohmatob, E. -* Eickenberg, M. -* Esteve, L. -* Fritsch, V. -* Gervais, P. -* Hoyos Idrobo, A. -* Gorgolewski, C.F. -* Kossaifi, J. -* Michel, V. -* Pedregosa, F. -* Perez, M. +* `Alexandre Abadie`_ +* `Alexandre Abraham`_ +* `Andrés Hoyos Idrobo`_ +* `Ben Cipollini`_ +* `Chris Gorgolewski`_ +* `Danilo Bzdok`_ +* `Elvis Dohmatob`_ +* `Fabian Pedregosa`_ +* `Jean Kossaifi`_ +* `Jerome-Alexis Chevalier`_ +* `Kamalakar Reddy Daddy`_ +* `Kshitij Chawla`_ +* `Loic Estève`_ +* `Martin Perez-Guevara`_ +* `Michael Eickenberg`_ +* `Philippe Gervais`_ +* `Pierre Bellec`_ +* `Salma Bougacha`_ +* `Vincent Michel`_ +* `Virgile Fritsch`_ Funding ....... -Alexandre Abraham, Gael Varoquaux, Kamalakar Reddy Daddy, Loïc Estève, -Mehdi Rahim, Philippe Gervais were paid by the `NiConnect -`_ +`Alexandre Abraham`_, `Gael Varoquaux`_, `Kamalakar Reddy Daddy`_, `Loic Estève`_, +`Mehdi Rahim`_, `Philippe Gervais`_ were paid by the `NiConnect +`_ project, funded by the French `Investissement d'Avenir `_. +`Kshitij Chawla`_ was paid by `INRIA `_. + +`Nicolas Gensollen`_ is paid by the `Human Brain Project `_ +|HBP logo|. + NiLearn is also supported by `DigiCosme `_ |digicosme logo| and `DataIA `_ |dataia_logo|. @@ -95,11 +102,12 @@ We suggest that you read and cite the paper. Thank you. Citing scikit-learn ------------------- -A huge amount of work goes into scikit-learn, upon which nilearn relies heavily. +A huge amount of work goes into `scikit-learn `_, +upon which nilearn relies heavily. Researchers who invest their time in developing and maintaining the package deserve recognition with citations. -In addition, the Parietal team needs citations to the paper in order to -justify paying a software engineer on the project. +In addition, the `Parietal team `_ needs citations +to the paper in order to justify paying a software engineer on the project. To guarantee the future of the toolkit, if you use it, please cite it. See the scikit-learn documentation on `how to cite @@ -113,3 +121,7 @@ See the scikit-learn documentation on `how to cite .. |dataia_logo| image:: logos/dataia.png :height: 25 :alt: DataIA Logo + +.. |HBP logo| image:: logos/hbp-logo.png + :height: 25 + :alt: HBP Logo diff --git a/doc/changes/0.1.0.rst b/doc/changes/0.1.0.rst new file mode 100644 index 0000000000..1f1a9ab305 --- /dev/null +++ b/doc/changes/0.1.0.rst @@ -0,0 +1,44 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.1.0 +===== + +**Released February 2015** + +Changelog +--------- + +First release of nilearn. + +Contributors (from ``git shortlog -ns 0.1``): + + * `Gael Varoquaux`_ (600) + * `Alexandre Abraham`_ (483) + * `Loic Estève`_ (302) + * `Philippe Gervais`_ (254) + * `Virgile Fritsch`_ (122) + * `Michael Eickenberg`_ (83) + * `Jean Kossaifi`_ (59) + * `Jaques Grobler`_ (57) + * `Danilo Bzdok`_ (46) + * `Chris Gorgolewski`_ (35) + * `Ronald Phlypo`_ (28) + * `Ben Cipollini`_ (25) + * `Bertrand Thirion`_ (15) + * `Alexandre Gramfort`_ (13) + * `Fabian Pedregosa`_ (12) + * Yannick Schwartz (11) + * `Mehdi Rahim`_ (9) + * `Óscar Nájera`_ (7) + * `Elvis Dohmatob`_ (6) + * `Konstantin Shmelkov`_ (4) + * `Jason Gors`_ (3) + * `Salma Bougacha`_ (3) + * `Alexandre Savio`_ (1) + * `Jan Margeta`_ (1) + * `Matthias Ekman`_ (1) + * `Michael Waskom`_ (1) + * `Vincent Michel`_ (1) \ No newline at end of file diff --git a/doc/changes/0.1.1.rst b/doc/changes/0.1.1.rst new file mode 100644 index 0000000000..2348f1d157 --- /dev/null +++ b/doc/changes/0.1.1.rst @@ -0,0 +1,24 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.1.1 +===== + +**Released February 2015** + +Changelog +--------- + +The main change compared to ``0.1.0`` is the addition of connectome plotting +via the function :func:`~plotting.plot_connectome`. +See the `plotting documentation `_ for more details. + +Contributors (from ``git shortlog -ns 0.1..0.1.1``): + + * `Loic Estève`_ (81) + * `Alexandre Abraham`_ (18) + * `Danilo Bzdok`_ (18) + * `Ben Cipollini`_ (14) + * `Gael Varoquaux`_ (2) \ No newline at end of file diff --git a/doc/changes/0.1.2.rst b/doc/changes/0.1.2.rst new file mode 100644 index 0000000000..41e817cda5 --- /dev/null +++ b/doc/changes/0.1.2.rst @@ -0,0 +1,14 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.1.2 +===== + +**Released March 2015** + +Changelog +--------- + +The ``0.1.2`` release is a bugfix release, specifically to fix the :class:`~maskers.NiftiMapsMasker`. diff --git a/doc/changes/0.1.3.rst b/doc/changes/0.1.3.rst new file mode 100644 index 0000000000..62bec00c4f --- /dev/null +++ b/doc/changes/0.1.3.rst @@ -0,0 +1,59 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.1.3 +===== + +**Released May 2015** + +Changelog +--------- + +The ``0.1.3`` release is a bugfix release that fixes a lot of minor bugs. +It also includes a full rewamp of the documentation, and support for Python 3. + +.. warning:: + + Minimum version of supported packages are now: + + - ``numpy -- 1.6.1`` + - ``scipy -- 0.9.0`` + - ``scikit-learn -- 0.12.1`` + - ``Matplotlib -- 1.1.1`` (optional) + +Fixes +----- + +- Dealing with ``NaNs`` in function :func:`~plotting.plot_connectome`. + +- Fix extreme values in colorbar were sometimes brok. + +- Fix confounds removal with single confounds. + +- Fix frequency filtering. + +- Keep header information in images. + +- ``add_overlay`` finds ``vmin`` and ``vmax`` automatically. + +- Function :func:`~plotting.plot_connectome` now supports ``vmin`` and ``vmax``. + +- Detrending 3D images no longer puts them to zero. + + +Contributors (from ``git shortlog -ns 0.1.2..0.1.3``): + + * `Alexandre Abraham`_ (129) + * `Loic Estève`_ (67) + * `Gael Varoquaux`_ (57) + * `Ben Cipollini`_ (44) + * `Danilo Bzdok`_ (37) + * `Elvis Dohmatob`_ (20) + * `Óscar Nájera`_ (14) + * `Salma Bougacha`_ (9) + * `Alexandre Gramfort`_ (8) + * `Kamalakar Reddy Daddy`_ (7) + * `Demian Wassermann`_ (3) + * `Bertrand Thirion`_ (1) \ No newline at end of file diff --git a/doc/changes/0.1.4.rst b/doc/changes/0.1.4.rst new file mode 100644 index 0000000000..1402f14c07 --- /dev/null +++ b/doc/changes/0.1.4.rst @@ -0,0 +1,31 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.1.4 +===== + +**Released July 2015** + +Highlights +---------- + +- New class :class:`nilearn.maskers.NiftiSpheresMasker` which extracts signals from balls specified by their coordinates. + +- Obey Debian packaging rules. + +- Add the Destrieux 2009 and Power 2011 atlas. + +- Better caching in maskers. + + +Contributors (from ``git shortlog -ns 0.1.3..0.1.4``): + + * `Alexandre Abraham`_ (141) + * `Gael Varoquaux`_ (15) + * `Loic Estève`_ (10) + * `Arthur Mensch`_ (2) + * `Danilo Bzdok`_ (2) + * `Michael Hanke`_ (2) + * `Mehdi Rahim`_ (1) diff --git a/doc/changes/0.2.0.rst b/doc/changes/0.2.0.rst new file mode 100644 index 0000000000..ec3c8a4e82 --- /dev/null +++ b/doc/changes/0.2.0.rst @@ -0,0 +1,86 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.2.0 +===== + +**Released December 2015** + +Changelog +--------- + +.. warning:: + + The new minimum required version of scikit-learn is ``0.13``. + +New features +------------ + +- The new module :mod:`nilearn.connectome` now has class :class:`nilearn.connectome.ConnectivityMeasure` can be useful for computing functional connectivity matrices. + +- The function ``nilearn.connectome.sym_to_vec`` in same module :mod:`nilearn.connectome` is also implemented as a helper function to class :class:`nilearn.connectome.ConnectivityMeasure`. + +- The class :class:`decomposition.DictLearning` in :mod:`nilearn.decomposition` is a decomposition method similar to :term:`ICA` that imposes sparsity on components instead of independence between them. + +- Integrating back references template from ``sphinx-gallery`` of ``0.0.11`` version release. + +- Globbing expressions can now be used in all nilearn functions expecting a list of files. + +- The new module :mod:`nilearn.regions` now has class :class:`regions.RegionExtractor` which can be used for post processing brain regions of interest extraction. + +- The function :func:`~regions.connected_regions` in :mod:`nilearn.regions` is also implemented as a helper function to :class:`regions.RegionExtractor`. + +- The function :func:`~image.threshold_img` in :mod:`nilearn.image` is implemented to use it for thresholding statistical maps. + +Enhancements +------------ + +- Making website a bit elaborated & modernise by using ``sphinx-gallery``. + +- Documentation enhancement by integrating ``sphinx-gallery`` notebook style examples. + +- Documentation about class :class:`maskers.NiftiSpheresMasker`. + +Bug fixes +--------- + +- Fixed bug to control the behaviour when ``cut_coords=0`` in function :func:`~plotting.plot_stat_map` in :mod:`nilearn.plotting` (See :gh:`784`). + +- Fixed bug in function :func:`~image.copy_img` occurred while caching the Nifti images (See :gh:`793`). + +- Fixed bug causing an ``IndexError`` in ``fast_abs_percentile`` (See :gh:`875`). + +API changes summary +------------------- + +- The utilities in function :func:`~connectome.group_sparse_covariance` have been moved into module :mod:`nilearn.connectome`. + +- The default value for number of cuts (``n_cuts``) in function :func:`~plotting.find_cut_slices` in :mod:`nilearn.plotting` module has been changed from 12 to 7 i.e. ``n_cuts=7``. + +Contributors +------------ + +Contributors (from ``git shortlog -ns 0.1.4..0.2.0``): + + * `Elvis Dohmatob`_ (822) + * `Gael Varoquaux`_ (142) + * `Alexandre Abraham`_ (119) + * `Loic Estève`_ (90) + * `Kamalakar Reddy Daddy`_ (85) + * `Alexandre Abadie`_ (65) + * `Chris Gorgolewski`_ (43) + * `Salma Bougacha`_ (39) + * `Danilo Bzdok`_ (29) + * `Martin Perez-Guevara`_ (20) + * `Mehdi Rahim`_ (19) + * `Óscar Nájera`_ (19) + * `Arthur Mensch`_ (8) + * `Ben Cipollini`_ (8) + * `Aina Frau-Pascual`_ (4) + * `Julia Huntenburg`_ (4) + * `Michael Hanke`_ (2) + * `Ariel Rokem`_ (2) + * `Bertrand Thirion`_ (1) + * `Dimitri Papadopoulos Orfanos`_ (1) diff --git a/doc/changes/0.2.1.rst b/doc/changes/0.2.1.rst new file mode 100644 index 0000000000..f2ce172aae --- /dev/null +++ b/doc/changes/0.2.1.rst @@ -0,0 +1,10 @@ + +0.2.1 +===== + +**Released December 2015** + +Changelog +--------- + +Small bugfix for more flexible input types (targetter in particular at making code easier in nistats). \ No newline at end of file diff --git a/doc/changes/0.2.2.rst b/doc/changes/0.2.2.rst new file mode 100644 index 0000000000..28018ffc85 --- /dev/null +++ b/doc/changes/0.2.2.rst @@ -0,0 +1,76 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.2.2 +===== + +**Released February 2016** + +The ``0.2.2`` is a bugfix + dependency update release (for ``sphinx-gallery``). +It aims at preparing a renewal of the tutorials. + +New +--- + +- Fetcher for Megatrawl Netmats dataset. + +Enhancements +------------ + +- Flake8 is now run on pull requests. + +- Reworking of the documentation organization. + +- ``Sphinx-gallery`` updated to version ``0.1.1``. + +- The default ``n_subjects=None`` in function :func:`~datasets.fetch_adhd` is now changed to ``n_subjects=30``. + +Fixes +----- + +- Fix ``symmetric_split`` behavior in function :func:`~datasets.fetch_atlas_harvard_oxford`. + +- Fix casting errors when providing integer data to function :func:`~image.high_variance_confounds`. + +- Fix matplotlib ``1.5.0`` compatibility in function :func:`~plotting.plot_prob_atlas`. + +- Fix matplotlib backend choice on Mac OS X. + +- Function :func:`~plotting.find_xyz_cut_coords` raises a meaningful error when 4D data is provided instead of 3D. + +- Class :class:`~maskers.NiftiSpheresMasker` handles radius smaller than the size of a :term:`voxel`. + +- Class :class:`~regions.RegionExtractor` handles data containing ``Nans``. + +- Confound regression does not force systematically the normalization of the confounds. + +- Force time series normalization in :class:`~connectome.ConnectivityMeasure` and check dimensionality of the input. + +- Function ``nilearn._utils.numpy_conversions.csv_to_array`` could consider valid CSV files as invalid. + +Changes +------- + +- Deprecated dataset downloading function have been removed. + +- Download progression message refreshing rate has been lowered to sparsify CircleCI logs. + +Contributors +------------ + +Contributors (from ``git shortlog -ns 0.2.1..0.2.2``): + + * `Kamalakar Reddy Daddy`_ (39) + * `Alexandre Abraham`_ (22) + * `Loic Estève`_ (21) + * `Gael Varoquaux`_ (19) + * `Alexandre Abadie`_ (12) + * `Salma Bougacha`_ (7) + * `Danilo Bzdok`_ (3) + * `Arthur Mensch`_ (1) + * `Ben Cipollini`_ (1) + * `Elvis Dohmatob`_ (1) + * `Óscar Nájera`_ (1) + diff --git a/doc/changes/0.2.3.rst b/doc/changes/0.2.3.rst new file mode 100644 index 0000000000..f81f38be00 --- /dev/null +++ b/doc/changes/0.2.3.rst @@ -0,0 +1,30 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.2.3 +===== + +**Released February 2016** + +Changelog +--------- + +The ``0.2.3`` is a small feature release for BrainHack 2016. + +New features +------------ + +- Mathematical formulas based on ``numpy`` functions can be applied on an image or a list of images using function :func:`~image.math_img`. + +- Downloader for COBRE datasets of 146 rest :term:`fMRI` subjects with function ``nilearn.datasets.fetch_cobre``. + +- Downloader for Dosenbach atlas :func:`~datasets.fetch_coords_dosenbach_2010`. + +- Fetcher for multiscale functional brain parcellations (BASC) :func:`~datasets.fetch_atlas_basc_multiscale_2015`. + +Bug fixes +--------- + +- Better dimming on white background for plotting. diff --git a/doc/changes/0.2.4.rst b/doc/changes/0.2.4.rst new file mode 100644 index 0000000000..28b33eec3f --- /dev/null +++ b/doc/changes/0.2.4.rst @@ -0,0 +1,31 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.2.4 +===== + +**Released April 2016** + +The ``0.2.4`` is a small release focused on documentation for teaching. + +New +--- + +- The path given to the ``memory`` argument of object now have their "~" expanded to the homedir. + +- Display object created by plotting now uniformly expose an ``add_markers`` method. + +- Function :func:`~plotting.plot_connectome` now plots connectome with colorbars. + +- New function :func:`~image.resample_to_img` to resample one image on another one (just resampling / interpolation, no coregistration). + +Changes +------- + +- Atlas fetcher :func:`~datasets.fetch_atlas_msdl` now returns directly labels of the regions in output variable ``labels`` and its coordinates in output variable ``region_coords`` and its type of network in ``networks``. + +- The output variable name ``regions`` is now changed to ``maps`` in AAL atlas fetcher :func:`~datasets.fetch_atlas_aal`. + +- AAL atlas now returns directly its labels in variable ``labels`` and its index values in variable ``indices``. diff --git a/doc/changes/0.2.5.rst b/doc/changes/0.2.5.rst new file mode 100644 index 0000000000..19a35f36ab --- /dev/null +++ b/doc/changes/0.2.5.rst @@ -0,0 +1,83 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.2.5.1 +======= + +**Released August 2016** + +This is a bugfix release. +The new minimum required version of ``scikit-learn`` is ``0.14.1``. + +Changes +------- + +- Default option for ``dim`` argument in plotting functions which uses :term:`MNI` template as a background image is now changed to 'auto' mode. Meaning that an automatic contrast setting on background image is applied by default. + +- ``Scikit-learn`` validation tools have been imported and are now used to check consistency of input data, in SpaceNet for example. + +New +--- + +- Add an option to select only off-diagonal elements in function ``sym_to_vec``. Also, the scaling of matrices is modified: we divide the diagonal by ``sqrt(2)`` instead of multiplying the off-diagonal elements. + +- Connectivity examples rely on :class:`~connectome.ConnectivityMeasure`. + +Fixes +----- + +- ``Scipy 0.18`` introduces a bug in a corner-case of resampling. Nilearn ``0.2.5`` can give wrong results with ``scipy 0.18``, but this is fixed in ``0.2.6``. + +- Broken links and references fixed in docs. + + +0.2.5 +===== + +**Released June 2016** + +The ``0.2.5`` release includes plotting for connectomes and glass brain with +hemisphere-specific projection, as well as more didactic examples and +improved documentation. + +New +--- + +- New display_mode options in functions :func:`~plotting.plot_glass_brain` and :func:`~plotting.plot_connectome`. It is possible to plot right and left hemisphere projections separately. + +- New function :func:`~datasets.load_mni152_brain_mask` to load canonical brain mask image in :term:`MNI` template space. + +- New function :func:`~datasets.fetch_icbm152_brain_gm_mask` to load brain grey matter mask image. + +- New function :func:`~image.load_img` loads data from a filename or a list of filenames. + +- New function :func:`~image.clean_img` applies the cleaning function :func:`~signal.clean` on all :term:`voxels`. + +- New simple data downloader :func:`~datasets.fetch_localizer_button_task` to simplify some examples. + +- Function :func:`~datasets.fetch_localizer_contrasts` can now download a specific list of subjects rather than a range of subjects. + +- New function :func:`~datasets.get_data_dirs` to check where nilearn downloads data. + +Contributors +------------ + +Contributors (from ``git shortlog -ns 0.2.4..0.2.5``): + + * `Gael Varoquaux`_ (55) + * `Alexandre Abraham`_ (39) + * `Martin Perez-Guevara`_ (26) + * `Kamalakar Reddy Daddy`_ (20) + * `Amadeus Kanaan`_ (8) + * `Alexandre Abadie`_ (3) + * `Arthur Mensch`_ (3) + * `Elvis Dohmatob`_ (3) + * `Loic Estève`_ (3) + * `Jerome Dockes`_ (2) + * Alexandre M. S (1) + * `Bertrand Thirion`_ (1) + * Ivan Gonzalez (1) + * `Roberto Guidotti`_ (1) + \ No newline at end of file diff --git a/doc/changes/0.2.6.rst b/doc/changes/0.2.6.rst new file mode 100644 index 0000000000..f33cb7bb06 --- /dev/null +++ b/doc/changes/0.2.6.rst @@ -0,0 +1,47 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.2.6 +===== + +**Released September 2016** + +This release enhances usage of several functions by fine tuning their parameters. +It allows to select which Haxby subject to fetch. +It also refactors documentation to make it easier to understand. +``Sphinx-gallery`` has been updated and nilearn is ready for new ``nibabel 2.1`` version. +Several bugs related to masks in Searchlight and ABIDE fetching have been resolved. + +Fixes +----- + +- Change default ``dtype`` in function :func:`~image.concat_imgs` to be the original type of the data (see :gh:`1238`). + +- Fix ``SearchLight`` that did not run without ``process_mask`` or with one :term:`voxel` mask. + +- Fix flipping of left hemisphere when plotting glass brain. + +- Fix bug when downloading ABIDE timeseries. + +Enhancements +------------ + +- ``Sphinx-gallery`` updated to version ``0.1.3``. + +- Refactoring of examples and documentation. + +- Better ordering of regions in function :func:`~datasets.fetch_coords_dosenbach_2010`. + +- Remove outdated power atlas example. + + +Changes +------- + +- The parameter ``n_subjects`` is deprecated and will be removed in future release. Use ``subjects`` instead in function :func:`~datasets.fetch_haxby`. + +- The function :func:`~datasets.fetch_haxby` will now fetch the data accepting input given in ``subjects`` as a list than integer. + +- Replace ``get_affine`` by ``affine`` with recent versions of ``nibabel``. diff --git a/doc/changes/0.3.0.rst b/doc/changes/0.3.0.rst new file mode 100644 index 0000000000..854d74c65a --- /dev/null +++ b/doc/changes/0.3.0.rst @@ -0,0 +1,115 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.3.0 +===== + +**Released April 2017** + +In addition, more details of this release are listed below. +Please checkout in **0.3.0 beta** release section for minimum version +support of dependencies, latest updates, highlights, changelog and enhancements. + +Changes +------- + +- Function :func:`~plotting.find_cut_slices` now supports to accept :class:`~nibabel.nifti1.Nifti1Image` as an input for argument ``img``. + +- Helper functions ``_get_mask_volume`` and ``_adjust_screening_percentile`` are now moved to ``param_validation`` file in utilities module to be used in common with Decoder object. + +Fixes +----- + +- Fix bug uncompressing tar files with datasets fetcher. + +- Fixed bunch of CircleCI documentation build failures. + +- Fixed deprecations ``set_axis_bgcolor`` related to matplotlib in plotting functions. + +- Fixed bug related to not accepting a list of arrays as an input to unmask, in :mod:`nilearn.masking` module. + +Enhancements +------------ + +- :term:`ANOVA` :term:`SVM` example on Haxby datasets ``plot_haxby_anova_svm`` in Decoding section now uses ``SelectPercentile`` to select :term:`voxels` rather than ``SelectKBest``. + +- New function ``fast_svd`` implementation in base decomposition module to automatically switch between randomized and lapack SVD (heuristic of ``scikit-learn``). + +0.3.0 beta +=========== + +**Released February 2017** + +To install the beta version, use:: + + pip install --upgrade --pre nilearn + +Highlights +---------- + +- Simple surface plotting. + +- A function to break a parcellation into its connected components. + +- **Dropped support for scikit-learn older than 0.14.1** Minimum supported version is now ``0.14.1``. + +- **Dropped support for Python 2.6** + +- Minimum required version of ``NiBabel`` is now ``1.2.0``, to support loading annotated data with freesurfer. + +Changes +------- + +- A helper function ``_safe_get_data`` as a nilearn utility now safely removes ``NaN`` values in the images with argument ``ensure_finite=True``. + +- Functions :func:`~connectome.cov_to_corr` and :func:`~connectome.prec_to_partial` can now be used. + +Fixes +----- + +- Fix colormap issue with ``colorbar=True`` when using qualitative colormaps. Fixed in according with changes of ``matplotlib 2.0`` fixes. + +- Fix plotting functions to work with ``NaN`` values in the images. + +- Fix bug related get ``dtype`` of the images with ``nibabel get_data()``. + +- Fix bug in function :func:`~image.clean_img`. + +Enhancements +------------ + +- New function :func:`~regions.connected_label_regions` to extract the connected components represented as same label to regions apart with each region labelled as unique label. + +- New plotting modules for surface plotting visualization. ``Matplotlib`` with version higher ``1.3.1`` is required for plotting surface data using these functions. + +- Function :func:`~plotting.plot_surf` can be used for plotting surfaces mesh data with optional background. + +- Function :func:`~plotting.plot_surf_stat_map` can be used for plotting statistical maps on a brain surface with optional background. + +- Function :func:`~plotting.plot_surf_roi` can be used for plotting statistical maps rois onto brain surface. + +- Function ``nilearn.datasets.fetch_surf_fsaverage5`` can be used for surface data object to be as background map for the above plotting functions. + +- New function :func:`~datasets.fetch_atlas_surf_destrieux` can give you Destrieux et. al 2010 cortical atlas in ``fsaverage5`` surface space. + +- New function :func:`~datasets.fetch_surf_nki_enhanced` gives you resting state data preprocessed and projected to ``fsaverage5`` surface space. + +- Two good examples in plotting gallery shows how to fetch atlas and NKI data and used for plotting on brain surface. + +- New function :func:`~surface.load_surf_mesh` in ``surf_plotting`` module for loading surface mesh data into two arrays, containing ``(x, y, z)`` coordinates for mesh vertices and indices of mesh faces. + +- New function :func:`~surface.load_surf_data` in ``surf_plotting`` module for loading data of numpy array to represented on a surface mesh. + +- Add fetcher for Allen et al. 2011 RSN atlas in :func:`~datasets.fetch_atlas_allen_2011`. + +- Function ``nilearn.datasets.fetch_cobre`` is now updated to new light release of COBRE data (schizophrenia). + +- A new example to show how to extract regions on labels image in example section manipulating images. + +- ``coveralls`` is replaced with ``codecov``. + +- Upgraded to ``Sphinx`` version ``0.1.7``. + +- Extensive plotting example shows how to use contours and filled contours on glass brain. diff --git a/doc/changes/0.3.1.rst b/doc/changes/0.3.1.rst new file mode 100644 index 0000000000..7d99d03064 --- /dev/null +++ b/doc/changes/0.3.1.rst @@ -0,0 +1,51 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.3.1 +===== + +**Released June 2017** + +This is a minor release for BrainHack. + +Highlights +---------- + +- **Dropped support for scikit-learn older than 0.14.1** Minimum supported version is now ``0.15``. + +Changes +------- + +- The function ``sym_to_vec`` is deprecated and will be removed in release ``0.4``. Use function :func:`~connectome.sym_matrix_to_vec` instead. + +- Added argument ``smoothing_fwhm`` to :class:`~regions.RegionExtractor` to control smoothing according to the resolution of atlas images. + +Fixes +----- + +- The helper function ``largest_connected_component`` should now work with inputs of non-native data ``dtypes``. + +- Fix plotting issues when non-finite values are present in background anatomical image. + +- A workaround to handle non-native endianness in :class:`~nibabel.nifti1.Nifti1Image` passed to resampling the image. + +Enhancements +------------ + +- New functions :func:`~datasets.fetch_neurovault` and :func:`~datasets.fetch_neurovault_ids` help you download statistical maps from the `Neurovault `_ platform. + +- New function :func:`~connectome.vec_to_sym_matrix` reshapes vectors to symmetric matrices. It acts as the reverse of function :func:`~connectome.sym_matrix_to_vec`. + +- Add an option allowing to vectorize connectivity matrices returned by the ``transform`` method of class :class:`~connectome.ConnectivityMeasure`. + +- Class :class:`~connectome.ConnectivityMeasure` now exposes an ``inverse_transform`` method, useful for going back from vectorized connectivity coefficients to connectivity matrices. Also, it allows to recover the covariance matrices for the "tangent" kind. + +- Reworking and renaming of connectivity measures example. Renamed from ``plot_connectivity_measures`` to ``plot_group_level_connectivity``. + +- Tighter bounding boxes when using ``add_contours`` for plotting. + +- Function :func:`~image.largest_connected_component_img` to directly extract the largest connected component from :class:`~nibabel.nifti1.Nifti1Image`. + +- Improvements in plotting, decoding and functional connectivity examples. diff --git a/doc/changes/0.4.0.rst b/doc/changes/0.4.0.rst new file mode 100644 index 0000000000..f894a3cb63 --- /dev/null +++ b/doc/changes/0.4.0.rst @@ -0,0 +1,98 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.4.0 +===== + +**Released November 2017** + +Highlights +---------- + +- New function :func:`~surface.vol_to_surf` to project volume data to the surface. + +- New function :func:`~plotting.plot_matrix` to display matrices, eg connectomes. + +Enhancements +------------ + +- New function :func:`~surface.vol_to_surf` to project a 3d or 4d brain volume on the cortical surface. + +- New function :func:`~plotting.plot_matrix` to display connectome matrices. + +- Expose function :func:`~image.coord_transform` for end users. Useful to transform coordinates (x, y, z) from one image space to another space. + +- Function :func:`~image.resample_img` now takes a linear resampling option (implemented by Joe Necus). + +- Function :func:`~datasets.fetch_atlas_talairach` to fetch the `Talairach atlas `_ (:gh:`1523` by `Jerome Dockes`_). + +- Enhancing new surface plotting functions, added new parameters ``axes`` and ``figure`` to accept user-specified instances in :func:`~plotting.plot_surf`, :func:`~plotting.plot_surf_stat_map`, and :func:`~plotting.plot_surf_roi`. + +- Class :class:`~decoding.SearchLight` has new parameter ``groups`` to do ``LeaveOneGroupOut`` type cv with new scikit-learn module model selection. + +- Enhancing the glass brain plotting in back view 'y' direction. + +- New parameter ``resampling_interpolation`` is added in most used plotting functions to have user control for faster visualizations. + +- Upgraded to ``Sphinx-Gallery 0.1.11``. + +Fixes +----- + +- Dimming factor applied to background image in plotting functions with ``dim`` parameter will no longer accepts as string ('-1'). An error will be raised. + +- Fixed issues with ``matplotlib 2.1.0``. + +- Fixed issues with ``SciPy 1.0.0``. + +Changes +------- + +- **Backward incompatible change**: Function :func:`~plotting.find_xyz_cut_coords` now takes a ``mask_img`` argument which is a niimg, rather than a ``mask`` argument, which used to be a numpy array. + +- The minimum required version for ``scipy`` is now ``0.14``. + +- Dropped support for ``Nibabel`` older than ``2.0.2``. + +- Function :func:`~image.smooth_img` no longer accepts smoothing parameter :term:`FWHM` as 0. Behavior is changed in according to the issues with recent ``SciPy`` version ``1.0.0``. + +- ``dim`` factor range is slightly increased to -2 to 2 from -1 to 1. Range exceeding -1 meaning more increase in contrast should be cautiously set. + +- New ``anterior`` and ``posterior`` view added to the ``plot_surf`` family views. + +- Using argument ``anat_img`` for placing background image in function :func:`~plotting.plot_prob_atlas` is deprecated. Use argument ``bg_img`` instead. + +- The examples now use ``pandas`` for the behavioral information. + +Contributors +------------ + +The following people contributed to this release: + + * `Jerome Dockes`_ (127) + * `Gael Varoquaux`_ (62) + * `Kamalakar Reddy Daddy`_ (36) + * Jeff Chiang (11) + * `Elizabeth DuPre`_ (9) + * `Jona Sassenhagen`_ (9) + * `Sylvain Lan`_ (7) + * J Necus (6) + * `Pierre-Olivier Quirion`_ (5) + * AnaLu (3) + * `Jean-Rémi King` (3) + * MADHYASTHA Meghana (3) + * `Salma Bougacha`_ (3) + * sfvnMAC (3) + * `Eric Larson`_ (2) + * `Christian Horea`_ (2) + * `Moritz Boos`_ (2) + * `Alex Rothberg`_ (1) + * `Bertrand Thirion`_ (1) + * Christophe Bedetti (1) + * John Griffiths (1) + * `Mehdi Rahim`_ (1) + * Sylvain LANNUZEL (1) + * Yaroslav Halchenko (1) + * clfs (1) diff --git a/doc/changes/0.4.1.rst b/doc/changes/0.4.1.rst new file mode 100644 index 0000000000..3652817e51 --- /dev/null +++ b/doc/changes/0.4.1.rst @@ -0,0 +1,43 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.4.1 +===== + +**Released March 2018** + +This bug fix release is focused on few bug fixes and minor developments. + +Enhancements +------------ + +- Classes :class:`~decomposition.CanICA` and :class:`~decomposition.DictLearning` have a new attribute ``components_img_`` providing directly the components learned as a :class:`~nibabel.nifti1.Nifti1Image`. This avoids the step of unmasking the attribute ``components_`` which is true for older versions (:gh:`1536` by `Kamalakar Reddy Daddy`_). + +- New class :class:`nilearn.regions.Parcellations` for learning brain parcellations on :term:`fMRI` data (:gh:`1370` by `Kamalakar Reddy Daddy`_). + +- Add optional reordering of the matrix using a argument ``reorder`` with function :func:`~plotting.plot_matrix`. + +.. note:: + This feature is usable only if ``SciPy`` version is ``>= 1.0.0``. + +Changes +------- + +- Using output attribute ``components_`` which is an extracted components in classes :class:`~decomposition.CanICA` and :class:`~decomposition.DictLearning` is deprecated and will be removed in next two releases. Use ``components_img_`` instead (:gh:`1536` by `Kamalakar Reddy Daddy`_). + +Bug fixes +--------- + +- Fix issues using function :func:`~plotting.plot_connectome` when string is passed in ``node_color`` with display modes left and right hemispheric cuts in the glass brain. + +- Fix bug while plotting only coordinates using ``add_markers`` on glass brain (:gh:`1595` by `Kamalakar Reddy Daddy`_). + +- Fix issues with estimators in decomposition module when input images are given in glob patterns. + +- Fix bug loading :class:`~nibabel.nifti2.Nifti2Image`. + +- Fix bug while adjusting contrast of the background template while using function :func:`~plotting.plot_prob_atlas`. + +- Fix colormap bug with recent ``matplotlib 2.2.0``. \ No newline at end of file diff --git a/doc/changes/0.4.2.rst b/doc/changes/0.4.2.rst new file mode 100644 index 0000000000..e1563a0bba --- /dev/null +++ b/doc/changes/0.4.2.rst @@ -0,0 +1,29 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.4.2 +===== + +**Released June 2018** + +Few important bugs fix release for OHBM conference. + +Changes +------- + +- Default colormaps for surface plotting functions have changed to be more consistent with slice plotting. :func:`~plotting.plot_surf_stat_map` now uses ``cold_hot``, as :func:`~plotting.plot_stat_map` does, and :func:`~plotting.plot_surf_roi` now uses ``gist_ncar``, as :func:`~plotting.plot_roi` does. + +- Improve 3D surface plotting: lock the aspect ratio of the plots and reduce the whitespace around the plots. + +Fixes +----- + +- Fix bug with input repetition time (:term:`TR`) which had no effect in signal cleaning (fixed by `Pradeep Reddy Raamana`_). + +- Fix issues with signal extraction on list of 3D images in :class:`~regions.Parcellations`. + +- Fix issues with raising ``AttributeError`` rather than ``HTTPError`` in datasets fetching utilities (by `Jerome Dockes`_). + +- Fix issues in datasets testing function uncompression of files (by `Pierre Glaser`_). \ No newline at end of file diff --git a/doc/changes/0.5.0.rst b/doc/changes/0.5.0.rst new file mode 100644 index 0000000000..cbbbdc9c5c --- /dev/null +++ b/doc/changes/0.5.0.rst @@ -0,0 +1,290 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.5.0 +===== + +**Released November 2018** + +NEW +--- + +- :ref:`interactive plotting functions `, eg for use in a notebook. + +- New functions :func:`~plotting.view_surf` and :func:`~plotting.view_img_on_surf` for interactive visualization of maps on the cortical surface in a web browser. + +- New functions :func:`~plotting.view_connectome` and :func:`~plotting.view_markers` for interactive visualization of connectomes and seed locations in 3D. + +- New function :func:`~plotting.view_img` for interactive visualization of volumes with 3 orthogonal cuts. + +.. note:: + Function :func:`~plotting.view_img` was ``nilearn.plotting.view_stat_map`` in alpha and beta releases. + +- Function :func:`~plotting.find_parcellation_cut_coords` for extraction of coordinates on brain parcellations denoted as labels. + +- Function :func:`~plotting.find_probabilistic_atlas_cut_coords` for extraction of coordinates on brain probabilistic maps. + + +**Minimum supported versions of packages have been bumped up.** + - ``scikit-learn -- v0.18``. + - ``scipy -- v0.17``. + - ``pandas -- v0.18``. + - ``numpy -- v1.11`` + - ``matplotlib -- v1.5.1`` + +**Nilearn Python2 support is being removed in the near future.** + Users with a Python2 environment will be warned + at their first Nilearn import. + +**Additional dataset downloaders for examples and tutorials.** + +- :func:`~datasets.fetch_surf_fsaverage`. + +- :func:`~datasets.fetch_atlas_pauli_2017`. + +- :func:`~datasets.fetch_neurovault_auditory_computation_task`. + +- :func:`~datasets.fetch_neurovault_motor_task`. + + +ENHANCEMENTS +------------ + +- Function :func:`~image.clean_img` now accepts a mask to restrict the cleaning of the image, reducing memory load and computation time. + +- ``NiftiMaskers`` now have a ``dtype`` parameter, by default keeping the same data type as the input data. + +- Displays by plotting functions can now add a scale bar (see :ref:`plotting`). + +- Lots of other fixes in documentation and examples. + +- A cleaner layout and improved navigation for the website, with a better introduction. + +- Dataset fetchers are now more reliable, less verbose. + +- The :meth:`~decoding.SearchLight.fit` method now accepts 4D niimgs. + +- Anaconda link in the installation documentation updated. + +- ``Scipy`` is listed as a dependency for Nilearn installation. + +Changes +------- + +- Default value of ``t_r`` in functions :func:`~signal.clean` and :func:`~image.clean_img` is ``None`` and cannot be ``None`` if ``low_pass`` or ``high_pass`` is specified. + +Lots of changes and improvements. Detailed change list for each release follows. + +0.5.0 rc +======== + +Highlights +---------- + +- Function :func:`~plotting.view_img` (formerly ``nilearn.plotting.view_stat_map`` in Nilearn ``0.5.0`` pre-release versions) generates significantly smaller notebooks and HTML pages while getting a more consistent look and feel with Nilearn's plotting functions. Huge shout out to `Pierre Bellec`_ (pbellec) for making a great feature awesome and for sportingly accommodating all our feedback. + +- Function :func:`~image.clean_img` now accepts a mask to restrict the cleaning of the image. This approach can help to reduce the memory load and computation time. Big thanks to `Michael Notter`_ (miykael). + +Enhancements +------------ + +- Function :func:`~plotting.view_img` is now using the ``brainsprite.js`` library, which results in much smaller notebooks or html pages. The interactive viewer also looks more similar to the plots generated by function :func:`~plotting.plot_stat_map`, and most parameters found in :func:`~plotting.plot_stat_map` are now supported in :func:`~plotting.view_img`. + +- Function :func:`~image.clean_img` now accepts a mask to restrict the cleaning of the image. This approach can help to reduce the memory load and computation time. + +- Method :meth:`~decoding.SpaceNetRegressor.fit` raises a meaningful error in regression tasks if the target Y contains all 1s. + +Changes +------- + +- Default value of ``t_r`` in functions :func:`~signal.clean` and :func:`~image.clean_img` is changed from 2.5 to ``None``. If ``low_pass`` or ``high_pass`` is specified, then ``t_r`` needs to be specified as well otherwise it will raise an error. + +- Order of filters in functions :func:`~signal.clean` and :func:`~image.clean_img` has changed to detrend, low- and high-pass filter, remove confounds and standardize. To ensure orthogonality between temporal filter and confound removal, an additional temporal filter will be applied on the confounds before removing them. This is according to Lindquist et al. (2018). + +- Function :func:`~image.clean_img` now accepts a mask to restrict the cleaning of the image. This approach can help to reduce the memory load and computation time. + +- Function :func:`~plotting.view_img` is now using the ``brainsprite.js`` library, which results in much smaller notebooks or html pages. The interactive viewer also looks more similar to the plots generated by :func:`~plotting.plot_stat_map`, and most parameters found in :func:`~plotting.plot_stat_map` are now supported in :func:`~plotting.view_img`. + + +Contributors +------------- + +The following people contributed to this release: + + * `Gael Varoquaux`_ (15) + * `Pierre Bellec`_ (114) + * `Michael Notter`_ (30) + * `Kshitij Chawla`_ (28) + * `Kamalakar Reddy Daddy`_ (4) + * himanshupathak21061998 (4) + * `Christian Horea`_ (1) + * `Jerome Dockes`_ (7) + +0.5.0 beta +========== + +**Released October 2018** + +Highlights +---------- + +**Nilearn Python2 support is being removed in the near future. +Users with a Python2 environment will be warned at their first Nilearn import.** + +Enhancements +------------ + +- Displays created by plotting functions can now add a scale bar to indicate the size in mm or cm (see :ref:`plotting`) (by `Oscar Esteban`_). + +- Colorbars in plotting functions now have a middle gray background suitable for use with custom colormaps with a non-unity alpha channel (by `Eric Larson`_). + +Loads of fixes and quality of life improvements + +- A cleaner layout and improved navigation for the website, with a better introduction. + +- Less warnings and verbosity while using certain functions and during dataset downloads. + +- Improved backend for the dataset fetchers means more reliable dataset downloads. + +- Some datasets, such as the ICBM, are now compressed to take up less disk space. + + +Fixes +----- + +- Method :meth:`decoding.SearchLight.fit` now accepts 4D niimgs (by `Dan Gale`_). + +- ``plotting.view_markers.open_in_browser()`` in ``js_plotting_utils`` fixed. + +- Brainomics dataset has been replaced in several examples. + +- Lots of other fixes in documentation and examples. + + +Changes +------- + +- In function :func:`~regions.img_to_signals_labels`, the ``See Also`` section in documentation now also points to :class:`~maskers.NiftiLabelsMasker` and :class:`~maskers.NiftiMapsMasker`. + +- ``Scipy`` is listed as a dependency for Nilearn installation. + +- Anaconda link in the installation documentation updated. + +Contributors +------------- + +The following people contributed to this release: + + * `Gael Varoquaux`_ (58) + * `Kshitij Chawla`_ (115) + * `Jerome Dockes`_ (15) + * `Oscar Esteban`_ (14) + * `Eric Larson`_ (10) + * `Kamalakar Reddy Daddy`_ (6) + * `Bertrand Thirion`_ (3) + * `Alexandre Abadie`_ (5) + * `Sourav Singh`_ (4) + * `Alex Rothberg`_ (3) + * AnaLu (3) + * `Demian Wassermann`_ (3) + * `Christian Horea`_ (3) + * `Jason Gors`_ (3) + * Jean Remi King (3) + * MADHYASTHA Meghana (3) + * `Simon Steinkamp`_ (3) + * `Jerome-Alexis Chevalier`_ (3) + * `Salma Bougacha`_ (3) + * sfvnMAC (3) + * Akshay (2) + * `Daniel Gomez`_ (2) + * `Guillaume Lemaitre`_ (2) + * `Pierre Bellec`_ (2) + * `Ariel Rokem`_ (2) + * erramuzpe (2) + * foucault (2) + * jehane (2) + * Sylvain LANNUZEL (1) + * Aki Nikolaidis (1) + * Christophe Bedetti (1) + * `Dan Gale`_ (1) + * Dillon Plunkett (1) + * `Dimitri Papadopoulos Orfanos`_ (1) + * Greg Operto (1) + * Ivan Gonzalez (1) + * Yaroslav Halchenko (1) + * dtyulman (1) + +0.5.0 alpha +=========== + +**Released August 2018** + +This is an alpha release: to download it, you need to explicitly ask for +the version number:: + + pip install nilearn==0.5.0a0 + +Highlights +---------- + +- **Minimum supported versions of packages have been bumped up.** + - ``scikit-learn -- v0.18`` + - ``scipy -- v0.17`` + - ``pandas -- v0.18`` + - ``numpy -- v1.11`` + - ``matplotlib -- v1.5.1`` + +- New :ref:`interactive plotting functions `, eg for use in a notebook. + +Enhancements +------------ + +- All ``NiftiMaskers`` now have a ``dtype`` argument. For now the default behaviour is to keep the same data type as the input data. + +- Displays created by plotting functions can now add a scale bar to indicate the size in mm or cm (see :ref:`plotting`) (by `Oscar Esteban`_). + +- New functions :func:`~plotting.view_surf` and :func:`~plotting.view_surf` and :func:`~plotting.view_img_on_surf` for interactive visualization of maps on the cortical surface in a web browser. + +- New functions :func:`~plotting.view_connectome` and :func:`~plotting.view_markers` to visualize connectomes and seed locations in 3D + +- New function ``nilearn.plotting.view_stat_map`` (renamed to :func:`~plotting.view_img` in stable release) for interactive visualization of volumes with 3 orthogonal cuts. + +- New function :func:`~datasets.fetch_surf_fsaverage` to download either ``fsaverage`` or ``fsaverage5`` (Freesurfer cortical meshes). + +- New function :func:`~datasets.fetch_atlas_pauli_2017` to download a recent subcortical neuroimaging atlas. + +- New function :func:`~plotting.find_parcellation_cut_coords` for extraction of coordinates on brain parcellations denoted as labels. + +- New function :func:`~plotting.find_probabilistic_atlas_cut_coords` for extraction of coordinates on brain probabilistic maps. + +- New functions :func:`~datasets.fetch_neurovault_auditory_computation_task` and :func:`~datasets.fetch_neurovault_motor_task` for simple example data. + +Changes +------- + +- Function ``nilearn.datasets.fetch_surf_fsaverage5`` is deprecated and will be removed in a future release. Use function :func:`~datasets.fetch_surf_fsaverage`, with the parameter ``mesh="fsaverage5"`` (the default) instead. + +- ``fsaverage5`` surface data files are now shipped directly with Nilearn (see :gh:`1705` for discussion). + +- ``sklearn.cross_validation`` and ``sklearn.grid_search`` have been replaced by ``sklearn.model_selection`` in all the examples. + +- Colorbars in plotting functions now have a middle gray background suitable for use with custom colormaps with a non-unity alpha channel. + +Contributors +------------ + +The following people contributed to this release: + + * `Gael Varoquaux`_ (49) + * `Jerome Dockes`_ (180) + * `Kshitij Chawla`_ (57) + * `Sylvain Lan`_ (38) + * `Kamalakar Reddy Daddy`_ (36) + * `Gilles de Hollander`_ (10) + * `Bertrand Thirion`_ (4) + * MENUET Romuald (4) + * `Moritz Boos`_ (3) + * `Peer Herholz`_ (1) + * `Pierre Bellec`_ (1) diff --git a/doc/changes/0.5.1.rst b/doc/changes/0.5.1.rst new file mode 100644 index 0000000000..0fc33a5b6a --- /dev/null +++ b/doc/changes/0.5.1.rst @@ -0,0 +1,89 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.5.1 +===== + +**Released April 2019** + +NEW +--- + +- **Support for Python2 & Python3.4 will be removed in the next release.** + We recommend Python 3.6 and up. + Users with a Python2 or Python3.4 environment will be warned at their first Nilearn import. + +- Calculate image data ``dtype`` from header information. + +- New display mode ``tiled`` which allows 2x2 plot arrangement when plotting three cuts (see :ref:`plotting`). + +- Class :class:`~maskers.NiftiLabelsMasker` now consumes less memory when extracting the signal from a 3D/4D image. This is especially noteworthy when extracting signals from large 4D images. + +- New function :func:`~datasets.fetch_atlas_schaefer_2018`. + +- New function :func:`~datasets.fetch_coords_seitzman_2018`. + +Changes +------- + +- Lighting used for interactive surface plots changed; plots may look a bit different. + +- Function :func:`~plotting.view_connectome` default colormap is ``bwr``, consistent with function :func:`~plotting.plot_connectome`. + +- Function :func:`~plotting.view_connectome` parameter names are consistent with function :func:`~plotting.plot_connectome`: + + - ``coords`` is now ``node_coord``. + - ``marker_size`` is now ``node_size``. + - ``cmap`` is now ``edge_cmap``. + - ``threshold`` is now ``edge_threshold``. + +- Functions :func:`~plotting.view_markers` and :func:`~plotting.view_connectome` can accept different marker sizes for each node / marker. + +- Function :func:`plotting.view_markers` default marker color is now ``red``, consistent with ``add_markers()``. + +- Function :func:`plotting.view_markers` parameter names are consistent with ``add_markers()``: + + - ``coords`` is now ``marker_coords``. + - ``colors`` is now ``marker_color``. + +- Function :func:`~plotting.view_img_on_surf` now accepts a ``symmetric_cmap`` argument to control whether the colormap is centered around 0 and a ``vmin`` argument. + +- Users can now control the size and fontsize of colorbars in interactive surface and connectome plots, or disable the colorbar. + +Fixes +----- + +- Example ``plot_seed_to_voxel_correlation`` now really saves z-transformed maps. + +- Function :func:`~regions.connected_regions` and class :class:`~regions.RegionExtractor` now correctly use the provided ``mask_img``. + +- Function ``load_niimg`` no longer drops header if ``dtype`` is changed. + +- Class :class:`~maskers.NiftiSpheresMasker` no longer silently ignores :term:`voxels` if no ``mask_img`` is specified. + +- Interactive brainsprites generated from ``view_img`` are correctly rendered in Jupyter Book. + +Known Issues +------------ + +- On Python2, functions :func:`~plotting.view_connectome` and function :func:`~plotting.view_markers` do not show parameters names in function signature when using ``help()`` and similar features. Please refer to their docstrings for this information. + +- Plotting ``.mgz`` files in MNE is broken. + +Contributors +------------ + +The following people contributed to this release: + + * `Bertrand Thirion`_ (2) + * `Kshitij Chawla`_ (90) + * `Franz Liem`_ (22) + * `Jerome Dockes`_ (16) + * `Gael Varoquaux`_ (11) + * `Salma Bougacha`_ (8) + * himanshupathak21061998 (7) + * `Elizabeth DuPre`_ (2) + * `Eric Larson`_ (1) + * `Pierre Bellec`_ (1) diff --git a/doc/changes/0.5.2.rst b/doc/changes/0.5.2.rst new file mode 100644 index 0000000000..7855dc1ca4 --- /dev/null +++ b/doc/changes/0.5.2.rst @@ -0,0 +1,32 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.5.2 +===== + +**Released April 2019** + +NEW +--- + +.. warning:: + + This is the **last** release supporting Python2 and ``3.4``. + The lowest Python version supported is now Python ``3.5``. + We recommend switching to Python ``3.6``. + +Fixes +----- + +- Plotting ``.mgz`` files in MNE broke in ``0.5.1`` and has been fixed. + +Contributors +------------ + +The following people contributed to this release: + + * `Kshitij Chawla`_ (11) + * `Gael Varoquaux`_ (3) + * `Alexandre Gramfort`_ (2) \ No newline at end of file diff --git a/doc/changes/0.6.0.rst b/doc/changes/0.6.0.rst new file mode 100644 index 0000000000..8ad653683e --- /dev/null +++ b/doc/changes/0.6.0.rst @@ -0,0 +1,282 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.6.0 +===== + +**Released December 2019** + +HIGHLIGHTS +---------- + +.. warning:: + + | **Python2 and 3.4 are no longer supported. We recommend upgrading to Python 3.6 minimum.** (:gh:`2214` by `Kshitij Chawla`_). + | + | **Support for Python3.5 will be removed in the 0.7.x release.** + | Users with a Python ``3.5`` environment will be warned at their first Nilearn import. + | + | **joblib is now a dependency** + | + | **Minimum supported versions of packages have been bumped up.** + | - ``Matplotlib -- v2.0``. + | - ``Scikit-learn -- v0.19``. + | - ``Scipy -- v0.19``. + +NEW +--- + +- New method for :class:`~maskers.NiftiMasker` instances for generating reports viewable in a web browser, Jupyter Notebook, or VSCode (:gh:`2019` by `Elizabeth DuPre`_). + +- New function :func:`~image.get_data` to replace the deprecated nibabel method ``Nifti1Image.get_data``. Now use ``nilearn.image.get_data(img)`` rather than ``img.get_data()``. This is because Nibabel is removing the ``get_data`` method. You may also consider using the Nibabel method ``nibabel.nifti1.Nifti1Image.get_fdata``, which returns the data cast to floating-point. See `BIAP8 `_. As a benefit, the :func:`~image.get_data` function works on niimg-like objects such as filenames (see `input_output `_) (:gh:`2172` by `Jerome Dockes`_). + +- New class :class:`~regions.ReNA` implementing parcellation method :term:`ReNA`: Fast agglomerative clustering based on recursive nearest neighbor grouping. Yields very fast & accurate models, without creation of giant clusters (:gh:`1336` by `Andrés Hoyos Idrobo`_). + +- New function ``nilearn.plotting.plot_connectome_strength`` to plot the strength of a connectome on a glass brain. Strength is absolute sum of the edges at a node (:gh:`2028` by `Guillaume Lemaitre`_). + +- Function :func:`~image.resample_img` has been optimized to pad rather than resample images in the special case when there is only a translation between two spaces. This is a common case in class :class:`~maskers.NiftiMasker` when using the ``mask_strategy="template"`` option for brains in :term:`MNI` space (:gh:`2025` by `Greg Kiar`_). + +- New brain development :term:`fMRI` dataset fetcher :func:`datasets.fetch_development_fmri` can be used to download movie-watching data in children and adults. A light-weight dataset implemented for teaching and usage in the examples. All the connectivity examples are changed from ADHD to brain development :term:`fMRI` dataset (:gh:`1953` by `Kamalakar Reddy Daddy`_). + +ENHANCEMENTS +------------ + +- Functions :func:`~plotting.view_img_on_surf`, :func:`~plotting.view_surf` and :func:`~plotting.view_connectome` can display a title, and allow disabling the colorbar, and setting its height and the fontsize of its ticklabels (:gh:`1951` by `Jerome Dockes`_). + +- Rework of the standardize-options of function :func:`~signal.clean` and the various Maskers in :mod:`nilearn.maskers`. You can now set ``standardize`` to ``zscore`` or ``psc``. ``psc`` stands for ``Percent Signal Change``, which can be a meaningful metric for :term:`BOLD` (:gh:`1952` by `Gilles de Hollander`_). + +- Class :class:`~maskers.NiftiLabelsMasker` now accepts an optional ``strategy`` parameter which allows it to change the function used to reduce values within each labelled ROI. Available functions include ``mean``, ``median``, ``minimum``, ``maximum``, ``standard_deviation`` and ``variance``. This change is also introduced in function :func:`~regions.img_to_signals_labels` (:gh:`2221` by `Daniel Gomez`_). + +- Function :func:`~plotting.view_surf` now accepts surface data provided as a file path (:gh:`2057` by `Jerome Dockes`_). + +CHANGES +------- + +- Function :func:`~plotting.plot_img` now has explicit keyword arguments ``bg_img``, ``vmin`` and ``vmax`` to control the background image and the bounds of the colormap. These arguments were already accepted in ``kwargs`` but not documented before (:gh:`2157` by `Jerome Dockes`_). + +FIXES +----- + +- Class :class:`~maskers.NiftiLabelsMasker` no longer truncates region means to their integral part when input images are of integer type (:gh:`2195` by `Kshitij Chawla`_). + +- The argument ``version='det'`` in function :func:`~datasets.fetch_atlas_pauli_2017` now works as expected (:gh:`2235` by `Ryan Hammonds`_). + +- ``pip install nilearn`` now installs the necessary dependencies (:gh:`2214` by `Kshitij Chawla`_). + +**Lots of other fixes in documentation and examples.** More detailed change list follows: + +0.6.0rc +======= + +NEW +--- +.. warning:: + + - Function :func:`~plotting.view_connectome` no longer accepts old parameter names. Instead of ``coords``, ``threshold``, ``cmap``, and ``marker_size``, use ``node_coords``, ``edge_threshold``, ``edge_cmap``, and ``node_size`` respectively (:gh:`2255` by `Kshitij Chawla`_). + + - Function :func:`~plotting.view_markers` no longer accepts old parameter names. Instead of ``coord`` and ``color``, use ``marker_coords`` and ``marker_color`` respectively (:gh:`2255` by `Kshitij Chawla`_). + + - **Support for Python3.5 will be removed in the 0.7.x release.** Users with a Python3.5 environment will be warned at their first Nilearn import (:gh:`2214` by `Kshitij Chawla`_). + +Changes +------- + +- Add a warning to :class:`~regions.Parcellations` if the generated number of parcels does not match the requested number of parcels (:gh:`2240` by `Elizabeth DuPre`_). + +- Class :class:`~maskers.NiftiLabelsMasker` now accepts an optional ``strategy`` parameter which allows it to change the function used to reduce values within each labelled ROI. Available functions include ``mean``, ``median``, ``minimum``, ``maximum``, ``standard_deviation`` and ``variance``. This change is also introduced in function :func:`~regions.img_to_signals_labels` (:gh:`2221` by `Daniel Gomez`_). + +Fixes +----- + +- Class :class:`~maskers.NiftiLabelsMasker` no longer truncates region means to their integral part when input images are of integer type (:gh:`2195` by `Kshitij Chawla`_). + +- Function :func:`~image.smooth_img` no longer fails if ``fwhm`` is a :class:`numpy.ndarray` (:gh:`2107` by `Paula Sanz-Leon`_). + +- ``pip install nilearn`` now installs the necessary dependencies (:gh:`2214` by `Kshitij Chawla`_). + +- Function :func:`~image.new_img_like` no longer attempts to copy non-iterable headers (:gh:`2212` by `Kshitij Chawla`_). + +- Nilearn no longer raises ``ImportError`` for nose when Matplotlib is not installed (:gh:`2231` by `Kshitij Chawla`_). + +- The argument ``version='det'`` in function :func:`~datasets.fetch_atlas_pauli_2017` now works as expected (:gh:`2235` by `Ryan Hammonds`_). + +- Method :meth:`~maskers.NiftiLabelsMasker.inverse_transform` now works without the need to call ``transform`` first (:gh:`2248` by `Gael Varoquaux`_). + +Contributors +------------ + +The following people contributed to this release (in alphabetical order): + + * `Chris Markiewicz`_ + * `Dan Gale`_ + * `Daniel Gomez`_ + * `Derek Pisner`_ + * `Elizabeth DuPre`_ + * `Eric Larson`_ + * `Gael Varoquaux`_ + * `Jerome Dockes`_ + * `Johannes Wiesner`_ + * `Kshitij Chawla`_ + * `Paula Sanz-Leon`_ + * `Loic Tetrel`_ + * `Ryan Hammonds`_ + + +0.6.0b0 +======= + +**Released November 2019** + + +.. warning:: + + | **Python2 and 3.4 are no longer supported. Pip will raise an error in these environments.** + | **Minimum supported version of Python is now 3.5 .** + | **We recommend upgrading to Python 3.6 .** + + +NEW +--- + +- New function :func:`~image.get_data` to replace the deprecated nibabel method ``Nifti1Image.get_data``. Now use ``nilearn.image.get_data(img)`` rather than ``img.get_data()``. This is because Nibabel is removing the ``get_data`` method. You may also consider using the Nibabel method ``nibabel.nifti1.Nifti1Image.get_fdata``, which returns the data cast to floating-point. See `BIAP8 `_. As a benefit, the :func:`~image.get_data` function works on niimg-like objects such as filenames (see `input_output `_) (:gh:`2172` by `Jerome Dockes`_). + +Changes +------- + +- All functions and examples now use function :func:`~image.get_data` rather than the deprecated method ``nibabel.Nifti1Image.get_data`` (:gh:`2172` by `Jerome Dockes`_). + +- Function :func:`~datasets.fetch_neurovault` now does not filter out images that have their metadata field ``is_valid`` cleared by default (:gh:`2169` by `Jerome Dockes`_). + +- Users can now specify fetching data for adults, children, or both from :func:`~datasets.fetch_development_fmri`. + + +Fixes +----- + +- Function :func:`~plotting.plot_connectome` now correctly displays marker size on 'l' and 'r' orientations, if an array or a list is passed to the function. + +Contributors +------------ + +The following people contributed to this release (in alphabetical order): + + * `Jake Vogel`_ + * `Jerome Dockes`_ + * `Kshitij Chawla`_ + * `Roberto Guidotti`_ + +0.6.0a0 +======= + +**Released October 2019** + +NEW +--- + +.. warning:: + + | **Python2 and 3.4 are no longer supported. We recommend upgrading to Python 3.6 minimum.** + | + | **Minimum supported versions of packages have been bumped up.** + | - ``Matplotlib -- v2.0``. + | - ``Scikit-learn -- v0.19``. + | - ``Scipy -- v0.19``. + +- A new method for :class:`~maskers.NiftiMasker` instances for generating reports viewable in a web browser, Jupyter Notebook, or VSCode (:gh:`2019` by `Elizabeth DuPre`_). + +- ``joblib`` is now a dependency (:gh:`2090` by `Jerome Dockes`_). + +- New class :class:`~regions.ReNA` implementing parcellation method :term:`ReNA`: Fast agglomerative clustering based on recursive nearest neighbor grouping. Yields very fast & accurate models, without creation of giant clusters (:gh:`1336` by `Andrés Hoyos Idrobo`_). + +- New function ``nilearn.plotting.plot_connectome_strength`` to plot the strength of a connectome on a glass brain. Strength is absolute sum of the edges at a node (:gh:`2028` by `Guillaume Lemaitre`_). + +- Function :func:`~image.resample_img` has been optimized to pad rather than resample images in the special case when there is only a translation between two spaces. This is a common case in class :class:`~maskers.NiftiMasker` when using the ``mask_strategy="template"`` option for brains in :term:`MNI` space (:gh:`2025` by `Greg Kiar`_). + +- New brain development :term:`fMRI` dataset fetcher :func:`~datasets.fetch_development_fmri` can be used to download movie-watching data in children and adults; a light-weight dataset implemented for teaching and usage in the examples. + +- New example in ``examples/05_advanced/plot_age_group_prediction_cross_val.py`` to compare methods for classifying subjects into age groups based on functional connectivity. Similar example in ``examples/03_connectivity/plot_group_level_connectivity.py`` simplified (:gh:`2063` by `Jerome Dockes`_). + +- Merged ``examples/03_connectivity/plot_adhd_spheres.py`` and ``examples/03_connectivity/plot_sphere_based_connectome.py`` to remove duplication across examples. The improved ``examples/03_connectivity/plot_sphere_based_connectome.py`` contains concepts previously reviewed in both examples (:gh:`2013` by `Jake Vogel`_). + +- Merged ``examples/03_connectivity/plot_compare_decomposition.py`` and ``examples/03_connectivity/plot_canica_analysis.py`` into an improved ``examples/03_connectivity/plot_compare_decomposition.py`` (:gh:`2013` by `Jake Vogel`_). + +- The Localizer dataset now follows the :term:`BIDS` organization. + +Changes +------- + +- All the connectivity examples are changed from ADHD to brain development :term:`fMRI` dataset. + +- Examples ``plot_decoding_tutorial``, ``plot_haxby_decoder``, ``plot_haxby_different_estimators``, ``plot_haxby_full_analysis``, ``plot_oasis_vbm`` now use :class:`~decoding.Decoder` and :class:`~decoding.DecoderRegressor` instead of sklearn SVC and SVR (:gh:`2000` by `Binh Nguyen`_). + +- Functions :func:`~plotting.view_img_on_surf`, :func:`~plotting.view_surf` and :func:`~plotting.view_connectome` can display a title, and allow disabling the colorbar, and setting its height and the fontsize of its ticklabels (:gh:`1951` by `Jerome Dockes`_). + +- Rework of the standardize-options of function :func:`~signal.clean` and the various Maskers in :mod:`nilearn.maskers`. You can now set ``standardize`` to ``zscore`` or ``psc``. ``psc`` stands for ``Percent Signal Change``, which can be a meaningful metric for :term:`BOLD` (:gh:`1952` by `Gilles de Hollander`_). + +- Function :func:`~plotting.plot_img` now has explicit keyword arguments ``bg_img``, ``vmin`` and ``vmax`` to control the background image and the bounds of the colormap. These arguments were already accepted in ``kwargs`` but not documented before (:gh:`2157` by `Jerome Dockes`_). + +- Function :func:`~plotting.view_connectome` now converts ``NaNs`` in the adjacency matrix to 0 (:gh:`2166` by `Jerome Dockes`_). + +- Removed the plotting connectomes example which used the Seitzman atlas from ``examples/03_connectivity/plot_sphere_based_connectome.py``. The atlas data is unsuitable for the method & the example is redundant (:gh:`2177` by `Kshitij Chawla`_). + +Fixes +----- + +- Function :func:`~plotting.plot_glass_brain` with ``colorbar=True`` does not crash when images have ``NaNs`` (:gh:`1953` by `Kamalakar Reddy Daddy`_). + +- Function ``add_contours`` now accepts ``threshold`` argument for ``filled=False``. Now ``threshold`` is equally applied when asked for fillings in the contours. + +- Functions :func:`~plotting.plot_surf` and :func:`~plotting.plot_surf_stat_map` no longer threshold zero values when no threshold is given (:gh:`1997` by `Julia Huntenburg`_). + +- Function :func:`~plotting.plot_surf_stat_map` used with a thresholded map but without a background map results in the surface mesh being displayed in half-transparent grey to maintain a 3D perception (:gh:`1997` by `Julia Huntenburg`_). + +- Function :func:`~plotting.view_surf` now accepts surface data provided as a file path. + +- Function :func:`~plotting.plot_glass_brain` now correctly displays the left 'l' orientation even when the given images are completely masked (empty images) (:gh:`1888` by `Kamalakar Reddy Daddy`_). + +- Function :func:`~plotting.plot_matrix` with providing ``labels=None``, ``False``, or an empty list now correctly disables labels (:gh:`2083` by `Moritz Boos`_). + +- Function :func:`~plotting.plot_surf_roi` now takes ``vmin``, and ``vmax`` parameters (:gh:`2052` by `Ian Abenes`_). + +- Function :func:`~datasets.fetch_surf_nki_enhanced` is now downloading the correct left and right functional surface data for each subject (:gh:`2118` by `Julia Huntenburg`_). + +- Function :func:`~datasets.fetch_atlas_schaefer_2018` now downloads from release version ``0.14.3`` (instead of ``0.8.1``) by default, which includes corrected region label names along with 700 and 900 region parcelations (:gh:`2138` by `Dan Gale`_). + +- Colormap creation functions have been updated to avoid matplotlib deprecation warnings about colormap reversal (:gh:`2131` by `Eric Larson`_). + +- Neurovault fetcher no longer fails if unable to update dataset metadata file due to faulty permissions. + +Contributors +------------ + +The following people contributed to this release (in alphabetical order): + + * `Alexandre Abraham`_ + * `Alexandre Gramfort`_ + * `Ana Luisa Pinho`_ + * `Andrés Hoyos Idrobo`_ + * `Thomas Bazeille`_ + * `Bertrand Thirion`_ + * `Colin Reininger`_ + * `Céline Delettre`_ + * `Dan Gale`_ + * `Daniel Gomez`_ + * `Elizabeth DuPre`_ + * `Eric Larson`_ + * `Franz Liem`_ + * `Gael Varoquaux`_ + * `Gilles de Hollander`_ + * `Greg Kiar`_ + * `Guillaume Lemaitre`_ + * `Ian Abenes`_ + * `Jake Vogel`_ + * `Jerome Dockes`_ + * `Jerome-Alexis Chevalier`_ + * `Julia Huntenburg`_ + * `Kamalakar Reddy Daddy`_ + * `Kshitij Chawla`_ + * `Mehdi Rahim`_ + * `Moritz Boos`_ + * `Sylvain Takerkart`_ diff --git a/doc/changes/0.6.1.rst b/doc/changes/0.6.1.rst new file mode 100644 index 0000000000..a82cd690ec --- /dev/null +++ b/doc/changes/0.6.1.rst @@ -0,0 +1,28 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.6.1 +===== + +**Released January 2020** + +ENHANCEMENTS +------------ + +- HTML pages use the user-provided plot title, if any, as their title (:gh:`2272` by `Jerome Dockes`_). + +Fixes +----- + +- Fetchers for developmental_fmri and localizer datasets resolve URLs correctly (:gh:`2290` by `Elizabeth DuPre`_). + +Contributors +------------ + +The following people contributed to this release: + + * `Elizabeth DuPre`_ + * `Jerome Dockes`_ + * `Kshitij Chawla`_ \ No newline at end of file diff --git a/doc/changes/0.6.2.rst b/doc/changes/0.6.2.rst new file mode 100644 index 0000000000..456e398b6d --- /dev/null +++ b/doc/changes/0.6.2.rst @@ -0,0 +1,40 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.6.2 +====== + +**Released February 2020** + +ENHANCEMENTS +------------ + +- Generated documentation now includes Binder links to launch examples interactively in the browser (:gh:`2300` by `Elizabeth DuPre`_). +- :class:`~maskers.NiftiSpheresMasker` now has an inverse transform, projecting spheres to the corresponding ``mask_img`` (:gh:`2429` by `Simon Steinkamp`_). + +Fixes +----- + +- More robust matplotlib backend selection (:gh:`2302` by `Gael Varoquaux`_). +- Typo in example fixed (:gh:`2312` by `Jon Haitz Legarreta Gorrono`_). + +Changes +------- + +- Function ``nilearn.datasets.fetch_nyu_rest`` has been deprecated and will be removed in Nilearn ``0.8.0`` (:gh:`2308` by `Joshua Teves`_). + +Contributors +------------ + +The following people contributed to this release: + + * `Elizabeth DuPre`_ + * `Franz Liem`_ + * `Gael Varoquaux`_ + * `Jon Haitz Legarreta Gorrono`_ + * `Joshua Teves`_ + * `Kshitij Chawla`_ + * `Zvi Baratz`_ + * `Simon Steinkamp`_ diff --git a/doc/changes/0.7.0.rst b/doc/changes/0.7.0.rst new file mode 100644 index 0000000000..fe5823be3a --- /dev/null +++ b/doc/changes/0.7.0.rst @@ -0,0 +1,117 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.7.0 +===== + +**Released November 2020** + +HIGHLIGHTS +---------- + +- Nilearn now includes the functionality of `Nistats `_ as :mod:`nilearn.glm`. This module is experimental, hence subject to change in any future release. :ref:`Here's a guide to replacing Nistats imports to work in Nilearn. ` (:gh:`2299`, :gh:`2304`, and :gh:`2307` by `Kshitij Chawla`_, and :gh:`2509` by `Binh Nguyen`_). + +- New classes :class:`nilearn.decoding.Decoder` (for :term:`classification`) and :class:`nilearn.decoding.DecoderRegressor` (for :term:`regression`) implement a model selection scheme that averages the best models within a cross validation loop (:gh:`2000` by `Binh Nguyen`_). + +- New classes :class:`nilearn.decoding.FREMClassifier` (for :term:`classification`) and :class:`nilearn.decoding.FREMRegressor` (for :term:`regression`) extend the :class:`~decoding.Decoder` object with one fast clustering step at the beginning and aggregates a high number of estimators trained on various splits of the training set (:gh:`2327` by `Thomas Bazeille`_). + +- New plotting functions: + + * :func:`~plotting.plot_event` to visualize events file. + * :func:`~plotting.plot_roi` can now plot ROIs in contours with ``view_type`` argument. + * :func:`~plotting.plot_carpet` generates a "carpet plot" (also known as a "Power plot" or a "grayplot") + * :func:`~plotting.plot_img_on_surf` generates multiple views of :func:`~plotting.plot_surf_stat_map` in a single figure. + * :func:`~plotting.plot_markers` shows network nodes (markers) on a glass brain template + * :func:`~plotting.plot_surf_contours` plots the contours of regions of interest on the surface + +.. warning:: + + Minimum required version of ``Joblib`` is now ``0.12``. + + +NEW +--- +- Nilearn now includes the functionality of `Nistats `_. + :ref:`Here's a guide to replacing Nistats imports to work in Nilearn. ` +- New decoder object + :class:`nilearn.decoding.Decoder` (for classification) and + :class:`nilearn.decoding.DecoderRegressor` (for regression) implement a model + selection scheme that averages the best models within a cross validation loop. + The resulting average model is the one used as a classifier or a regressor. + These two objects also leverage the `NiftiMaskers` to provide a direct + interface with the Nifti files on disk. +- New FREM object + :class:`nilearn.decoding.FREMClassifier` (for classification) and + :class:`nilearn.decoding.FREMRegressor` (for regression) extend the decoder + object pipeline with one fast clustering step at the beginning (yielding an + implicit spatial regularization) and aggregates a high number of estimators + trained on various splits of the training set. This returns a state-of-the-art + decoding pipeline at a low computational cost. + These two objects also leverage the `NiftiMaskers` to provide a direct + interface with the Nifti files on disk. +- Plot events file + Use :func:`nilearn.plotting.plot_event` to visualize events file. + The function accepts the :term:`BIDS` events file read using `pandas` + utilities. +- Plotting function :func:`nilearn.plotting.plot_roi` can now plot ROIs + in contours with `view_type` argument. +- New plotting function + :func:`nilearn.plotting.plot_carpet` generates a "carpet plot" (also known + as a "Power plot" or a "grayplot"), for visualizing global patterns in + 4D functional data over time. +- New plotting function + :func:`nilearn.plotting.plot_img_on_surf` generates multiple views of + :func:`nilearn.plotting.plot_surf_stat_map` in a single figure. +- :func:`nilearn.plotting.plot_markers` shows network nodes (markers) on a glass + brain template and color code them according to provided nodal measure (i.e. + connection strength). This function will replace + ``nilearn.plotting.plot_connectome_strength``. +- New plotting function + :func:`nilearn.plotting.plot_surf_contours` plots the contours of regions of + interest on the surface, optionally overlaid on top of a statistical map. +- The position annotation on the plot methods now implements the `decimals` option + to enable annotation of a slice coordinate position with the float. +- New example in + :ref:`sphx_glr_auto_examples_02_decoding_plot_haxby_searchlight_surface.py` + to demo how to do cortical surface-based searchlight decoding with Nilearn. +- confounds or additional regressors for design matrix can be specified as + numpy arrays or pandas DataFrames interchangeably +- The decomposition estimators will now accept argument `per_component` + with `score` method to explain the variance for each component. + + +Fixes +----- + +- :class:`nilearn.maskers.NiftiLabelsMasker` no longer ignores its `mask_img` +- :func:`nilearn.masking.compute_brain_mask` has replaced + nilearn.masking.compute_gray_matter_mask. Features remained the same but + some corrections regarding its description were made in the docstring. +- the default background (MNI template) in plotting functions now has the + correct orientation; before left and right were inverted. +- first level modelling can deal with regressors + having multiple events which share onsets or offsets. + Previously, such cases could lead to an erroneous baseline shift. +- :func:`nilearn.mass_univariate.permuted_ols` no longer returns transposed + t-statistic arrays when no permutations are performed. +- Fix decomposition estimators returning explained variance score as 0. + based on all components i.e., when per_component=False. +- Fix readme file of the Destrieux 2009 atlas. + + +Changes +------- + +- Function ``nilearn.datasets.fetch_cobre`` has been deprecated and will be + removed in release 0.9 . +- Function ``nilearn.plotting.plot_connectome_strength`` has been deprecated and will + be removed in release 0.9 . + +- :class:`nilearn.connectome.ConnectivityMeasure` can now remove + confounds in its transform step. +- :func:`nilearn.surface.vol_to_surf` can now sample between two nested surfaces + (eg white matter and pial surfaces) at specific cortical depths +- :func:`nilearn.datasets.fetch_surf_fsaverage` now also downloads white matter + surfaces. diff --git a/doc/changes/0.7.1.rst b/doc/changes/0.7.1.rst new file mode 100644 index 0000000000..1d9ddfa110 --- /dev/null +++ b/doc/changes/0.7.1.rst @@ -0,0 +1,56 @@ +.. currentmodule:: nilearn + +.. include:: names.rst + +0.7.1 +===== + +**Released March 2021** + +HIGHLIGHTS +---------- + +- New atlas fetcher :func:`~datasets.fetch_atlas_difumo` to download *Dictionaries of Functional Modes*, or “DiFuMo”, that can serve as atlases to extract functional signals with different dimensionalities (64, 128, 256, 512, and 1024). These modes are optimized to represent well raw :term:`BOLD` timeseries, over a with range of experimental conditions (:gh:`2619` by `Nicolas Gensollen`_). + +- :class:`~decoding.Decoder` and :class:`~decoding.DecoderRegressor` are now implemented with random predictions to estimate a chance level (:gh:`2622` by `Kamalakar Reddy Daddy`_). + +- Functions :func:`~plotting.plot_epi`, :func:`~plotting.plot_roi`, :func:`~plotting.plot_stat_map`, :func:`~plotting.plot_prob_atlas` are now implemented with new display mode ``Mosaic``. That implies plotting 3D maps in multiple columns and rows in a single axes (:gh:`2684` by `Kamalakar Reddy Daddy`_). + +- Function :func:`~plotting.plot_carpet` now supports discrete atlases. When an atlas is used, a colorbar is added to the figure, optionally with labels corresponding to the different values in the atlas (:gh:`2702` by `Taylor Salo`_). + +NEW +--- + +- New atlas fetcher :func:`~datasets.fetch_atlas_difumo` to download *Dictionaries of Functional Modes*, or “DiFuMo”, that can serve as atlases to extract functional signals with different dimensionalities (64, 128, 256, 512, and 1024). These modes are optimized to represent well raw :term:`BOLD` timeseries, over a with range of experimental conditions (:gh:`2619` by `Nicolas Gensollen`_). + +- Function :func:`glm.Contrast.one_minus_pvalue` was added to ensure numerical stability of p-value estimation. It computes 1 - p-value using the Cumulative Distribution Function in the same way as function :func:`nilearn.glm.Contrast.p_value` computes the p-value using the Survival Function. (:gh:`2567` by `Ana Luisa Pinho`_). + +Fixes +----- + +- Fix altered, non-zero baseline in design matrices where multiple events in the same condition end at the same time (see :gh:`2674`) (:gh:`2553` by `Martin Wegrzyn`_). + +- Fix testing issues on ARM machine (:gh:`2606` by `Kamalakar Reddy Daddy`_). + +Enhancements +------------ + +- :class:`~decoding.Decoder` and :class:`~decoding.DecoderRegressor` are now implemented with random predictions to estimate a chance level (:gh:`2622` by `Kamalakar Reddy Daddy`_). + +- :class:`~decoding.Decoder`, :class:`~decoding.DecoderRegressor`, :class:`~decoding.FREMRegressor`, and :class:`~decoding.FREMClassifier` now override the ``score`` method to use whatever scoring strategy was defined through the ``scoring`` attribute instead of the sklearn default. If the ``scoring`` attribute of the decoder is set to ``None``, the scoring strategy will default to accuracy for classifiers and to r2 score for regressors (:gh:`2669` by `Nicolas Gensollen`_). + +- Function :func:`~plotting.plot_surf` and deriving functions like :func:`~plotting.plot_surf_roi` now accept an optional argument ``cbar_tick_format`` to specify how numbers should be displayed on the colorbar of surface plots. The default format is scientific notation except for function :func:`~plotting.plot_surf_roi` for which it is set as integers (:gh:`2643` by `Nicolas Gensollen`_). + +- Function :func:`~plotting.plot_carpet` now supports discrete atlases. When an atlas is used, a colorbar is added to the figure, optionally with labels corresponding to the different values in the atlas (:gh:`2702` by `Taylor Salo`_). + +- :class:`~maskers.NiftiMasker`, :class:`~maskers.NiftiLabelsMasker`, :class:`~maskers.MultiNiftiMasker`, :class:`~maskers.NiftiMapsMasker`, and :class:`~maskers.NiftiSpheresMasker` can now compute high variance confounds on the images provided to ``transform`` and regress them out automatically. This behaviour is controlled through the ``high_variance_confounds`` boolean parameter of these maskers which default to ``False`` (:gh:`2697` by `Nicolas Gensollen`_). + +- :class:`~maskers.NiftiLabelsMasker` now automatically replaces ``NaNs`` in input data with zeros, to match the behavior of other maskers (:gh:`2712` by `Taylor Salo`_). + +- Function :func:`~datasets.fetch_neurovault` now implements a ``resample`` boolean argument to either perform a fixed resampling during download or keep original images. This can be handy to reduce disk usage. By default, the downloaded images are not resampled (:gh:`2696` by `Raphael Meudec`_). + +- Functions :func:`~plotting.plot_epi`, :func:`~plotting.plot_roi`, :func:`~plotting.plot_stat_map`, :func:`~plotting.plot_prob_atlas` are now implemented with new display mode ``Mosaic``. That implies plotting 3D maps in multiple columns and rows in a single axes (:gh:`2684` by `Kamalakar Reddy Daddy`_). + +- Function :func:`~signal.clean` now has a ``psc`` standardization option which allows time series with negative mean values (:gh:`2714` by `Hao-Ting Wang`_). + +- Functions :func:`~reporting.make_glm_report` and :func:`~reporting.get_clusters_table` have a new argument, ``two_sided``, which allows for two-sided thresholding, which is disabled by default (:gh:`2719` by `Taylor Salo`_). diff --git a/doc/changes/0.8.0.rst b/doc/changes/0.8.0.rst new file mode 100644 index 0000000000..f159cded0a --- /dev/null +++ b/doc/changes/0.8.0.rst @@ -0,0 +1,112 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.8.0 +===== + +**Released June 2021** + +HIGHLIGHTS +---------- + +.. warning:: + + | **Python 3.5 is no longer supported. We recommend upgrading to Python 3.8.** + | + | **Support for Nibabel 2.x is deprecated and will be removed in the 0.9 release.** + | Users with a version of Nibabel < 3.0 will be warned at their first Nilearn import. + | + | **Minimum supported versions of packages have been bumped up:** + | - Numpy -- v1.16 + | - SciPy -- v1.2 + | - Scikit-learn -- v0.21 + | - Nibabel -- v2.5 + | - Pandas -- v0.24 + +- Class :class:`~maskers.NiftiLabelsMasker` can now generate HTML reports in the same way as the :class:`~maskers.NiftiMasker` (:gh:`2707` by `Nicolas Gensollen`_). + +- Function :func:`~signal.clean` now accepts a new parameter ``sample_mask`` of shape ``(number of scans - number of volumes removed, )`` (:gh:`2858` by `Hao-Ting Wang`_). + +- All inherent classes of :class:`nilearn.maskers.BaseMasker` can use the parameter ``sample_mask`` for sub-sample masking (:gh:`2858` by `Hao-Ting Wang`_). + +- Function :func:`~datasets.fetch_surf_fsaverage` now accepts ``fsaverage3``, ``fsaverage4`` and ``fsaverage6`` as values for parameter ``mesh``, so that all resolutions of fsaverage from 3 to 7 are now available (:gh:`2815` by `Alexis Thual`_). + +- Function :func:`~datasets.fetch_surf_fsaverage` now provides attributes ``{area, curv, sphere, thick}_{left, right}`` for all fsaverage resolutions (:gh:`2815` by `Alexis Thual`_). + +- Function :func:`~glm.first_level.run_glm` now allows auto regressive noise models of order greater than one (:gh:`2532` by `Robert Luke`_). + +NEW +--- + +- Function :func:`~signal.clean` now accepts a new parameter ``sample_mask`` of shape ``(number of scans - number of volumes removed, )``. Masks the niimgs along time/fourth dimension to perform scrubbing (remove volumes with high motion) and/or non-steady-state volumes. Masking is applied before signal cleaning (:gh:`2858` by `Hao-Ting Wang`_). + +- All inherent classes of :class:`nilearn.maskers.BaseMasker` can use the parameter ``sample_mask`` for sub-sample masking (:gh:`2858` by `Hao-Ting Wang`_). + +- Class :class:`~maskers.NiftiLabelsMasker` can now generate HTML reports in the same way as :class:`~maskers.NiftiMasker`. The report shows the regions defined by the provided label image and provide summary statistics on each region (name, volume...). If a functional image was provided to fit, the middle image is plotted with the regions overlaid as contours. Finally, if a mask is provided, its contours are shown in green (:gh:`2707` by `Nicolas Gensollen`_). + +Fixes +----- + +- Convert references in ``signal.py``, ``atlas.py``, ``func.py``, ``neurovault.py``, and ``struct.py`` to use footcite / footbibliography (:gh:`2806` by `Jeremy Lefort-Besnard`_). + +- Fix detrending and temporal filtering order for confounders in function :func:`~signal.clean`, so that these operations are applied in the same order as for the signals, i.e., first detrending and then temporal filtering (see :gh:`2730`) (:gh:`2732` by `Javier Rasero`_). + +- Fix number of attributes returned by the `nilearn.glm.first_level.FirstLevelModel._get_voxelwise_model_attribute` method in the :class:`~glm.first_level.FirstLevelModel`. It used to return only the first attribute, and now returns as many attributes as design matrices (:gh:`2792` by `Raphael Meudec`_). + +- Plotting functions that show a stack of slices from a 3D image (e.g. :func:`~plotting.plot_stat_map`) will now plot the slices in the user specified order, rather than automatically sorting into ascending order (see :gh:`1155`) (:gh:`2831` by `Evan Edmond`_). + +- Fix the axes zoom in function :func:`~plotting.plot_img_on_surf` so brain would not be cutoff, and edited function so less white space surrounds brain views and smaller colorbar using gridspec (:gh:`2798` by `Tom Vanasse`_). + +- Fix inconsistency in prediction values of :class:`sklearn.dummy.DummyClassifier` for :class:`~decoding.Decoder` (see :gh:`2767`) (:gh:`2826` by `Binh Nguyen`_). + +Enhancements +------------ + +- Function :func:`~plotting.view_markers` now accepts an optional argument ``marker_labels`` to provide labels to each marker (:gh:`2745` by `Greydon Gilmore`_). + +- Function :func:`~plotting.plot_surf` now accepts new values for ``avg_method`` argument, such as ``min``, ``max``, or even a custom python function to compute the value displayed for each face of the plotted mesh (:gh:`2790` by `Alexis Thual`_). + +- Function :func:`~plotting.view_img_on_surf` can now optionally pass through parameters to function :func:`~surface.vol_to_surf` using the ``vol_to_surf_kwargs`` argument. One application is better HTML visualization of atlases (https://nilearn.github.io/auto_examples/01_plotting/plot_3d_map_to_surface_projection.html) (:gh:`2805` by `Evan Edmond`_). + +- Function :func:`~plotting.view_connectome` now accepts an optional argument ``node_color`` to provide a single color for all nodes, or one color per node. It defaults to ``auto`` which colors markers according to the viridis colormap (:gh:`2810` by `Raphael Meudec`_). + +- Function :func:`~signal.clean` has been refactored to clarify the data flow (:gh:`2821` by `Hao-Ting Wang`_). + +- Parameter ``sessions`` has been replaced with ``runs`` in :func:`~signal.clean` to match BIDS semantics. ``sessions`` has been deprecated and will be removed in ``0.9.0`` (:gh:`2821` by `Hao-Ting Wang`_). + +- Add argument ``filter`` in :func:`~signal.clean` and allow a selection of signal filtering strategies: ``butterwoth`` for butterworth filter, ``cosine`` for discrete cosine transformation, and ``False`` for no filtering (:gh:`2821` by `Hao-Ting Wang`_). + +- Change the default strategy for :class:`sklearn.dummy.DummyClassifier` from ``prior`` to ``stratified`` (:gh:`2826` by `Binh Nguyen`_). + +- Function :func:`~glm.first_level.run_glm` now allows auto regressive noise models of order greater than one (:gh:`2532` by `Robert Luke`_). + +- Moves parameter ``sample_mask`` from :class:`~maskers.NiftiMasker` to method ``transform`` in base class :class:`nilearn.maskers.BaseMasker` (:gh:`2858` by `Hao-Ting Wang`_). + +- Function :func:`~datasets.fetch_surf_fsaverage` now accepts ``fsaverage3``, ``fsaverage4`` and ``fsaverage6`` as values for parameter ``mesh``, so that all resolutions of fsaverage from 3 to 7 are now available (:gh:`2815` by `Alexis Thual`_). + +- Function :func:`~datasets.fetch_surf_fsaverage` now provides attributes ``{area, curv, sphere, thick}_{left, right}`` for all fsaverage resolutions (:gh:`2815` by `Alexis Thual`_). + +Changes +------- + +- Python ``3.5`` is no longer supported. We recommend upgrading to Python ``3.7`` (:gh:`2869` by `Nicolas Gensollen`_). + +- Support for Nibabel ``2.x`` is now deprecated and will be removed in the ``0.9`` release. Users with a version of Nibabel ``< 3.0`` will be warned at their first Nilearn import (:gh:`2869` by `Nicolas Gensollen`_). + +- Minimum supported versions of packages have been bumped up: + + * Numpy -- v1.16 + * SciPy -- v1.2 + * Scikit-learn -- v0.21 + * Nibabel -- v2.5 + * Pandas -- v0.24 + + (:gh:`2869` by `Nicolas Gensollen`_). + +- Function ``sym_to_vec`` from :mod:`nilearn.connectome` was deprecated since release ``0.4`` and has been removed (:gh:`2867` by `Nicolas Gensollen`_). + +- Function ``nilearn.datasets.fetch_nyu_rest`` was deprecated since release ``0.6.2`` and has been removed (:gh:`2868` by `Nicolas Gensollen`_). + +- Class :class:`~maskers.NiftiMasker` replaces attribute ``sessions`` with ``runs`` and deprecates attribute ``sessions`` in ``0.9.0``. Match the relevant change in function :func:`~signal.clean` (:gh:`2858` by `Hao-Ting Wang`_). diff --git a/doc/changes/0.8.1.rst b/doc/changes/0.8.1.rst new file mode 100644 index 0000000000..5bc542beb7 --- /dev/null +++ b/doc/changes/0.8.1.rst @@ -0,0 +1,66 @@ +.. currentmodule:: nilearn + +.. include:: names.rst + +0.8.1 +===== + +**Released September 2021** + +HIGHLIGHTS +---------- + +- New atlas fetcher :func:`~datasets.fetch_atlas_juelich` to download Juelich atlas from FSL (:gh:`2723` by `Ahmad Chamma`_). + +- New grey and white-matter template and mask loading functions: :func:`~datasets.load_mni152_gm_template`, :func:`~datasets.load_mni152_wm_template`, :func:`~datasets.load_mni152_gm_mask`, and :func:`~datasets.load_mni152_wm_mask` (:gh:`2738` by `Ana Luisa Pinho`_). + +- The :ref:`development_process` has been reworked. It now provides insights on nilearn organization as a project as well as more explicit :ref:`contribution_guidelines` (:gh:`2755` by `Thomas Bazeille`_). + +- Function :func:`~image.binarize_img` binarizes images into 0 and 1 (:gh:`2900` by `Daniel Gomez`_). + +NEW +--- + +- New atlas fetcher :func:`~datasets.fetch_atlas_juelich` to download Juelich atlas from FSL (:gh:`2723` by `Ahmad Chamma`_). + +- The :ref:`development_process` has been reworked. It now provides insights on nilearn organization as a project as well as more explicit :ref:`contribution_guidelines` (:gh:`2755` by `Thomas Bazeille`_). + +- Function :func:`~datasets.load_mni152_gm_template` takes the skullstripped 1mm-resolution version of the grey-matter MNI152 template and re-samples it using a different resolution, if specified (:gh:`2738` by `Ana Luisa Pinho`_). + +- Function :func:`~datasets.load_mni152_wm_template` takes the skullstripped 1mm-resolution version of the white-matter MNI152 template and re-samples it using a different resolution, if specified (:gh:`2738` by `Ana Luisa Pinho`_). + +- Function :func:`~datasets.load_mni152_gm_mask` loads mask from the grey-matter MNI152 template (:gh:`2738` by `Ana Luisa Pinho`_). + +- Function :func:`~datasets.load_mni152_wm_mask` loads mask from the white-matter MNI152 template (:gh:`2738` by `Ana Luisa Pinho`_). + +- Function :func:`~image.binarize_img` binarizes images into 0 and 1 (:gh:`2900` by `Daniel Gomez`_). + +- Classes :class:`~maskers.NiftiMasker`, :class:`~maskers.MultiNiftiMasker`, and objects relying on such maskers (:class:`~decoding.Decoder` or :class:`~decomposition.CanICA` for example) can now use new options for the argument ``mask_strategy``:``whole-brain-template`` for whole-brain template (same as previous option ``template``), ``gm-template`` for grey-matter template, and ``wm-template`` for white-matter template (:gh:`2904` by + `Nicolas Gensollen`_). + +Fixes +----- + +- Function :func:`~masking.compute_multi_brain_mask` has replaced ``nilearn.masking.compute_multi_grey_matter_mask``. A ``mask`` parameter has been added; it accepts three types of masks---i.e. ``whole-brain``, ``grey-matter``, and ``white-matter``---following the enhancements made in the function :func:`nilearn.masking.compute_brain_mask` in this release (:gh:`2738` by `Ana Luisa Pinho`_). + +- Fix colorbar of function :func:`~plotting.view_img` which was not visible for some combinations of `black_bg` and `bg_img` parameters (:gh:`2876` by `Nicolas Gensollen`_). + +- Fix missing title with function :func:`~plotting.plot_surf` and deriving functions (:gh:`2941` by `Nicolas Gensollen`_). + +Enhancements +------------ + +- Function :func:`~datasets.load_mni152_template` resamples now the template to a preset resolution different from the resolution of the original template, i.e. 1mm. The default resolution is 2mm, which means that the new template is resampled to the resolution of the old template. Nevertheless, the shape of the template changed from ``(91, 109, 91)`` to ``(99, 117, 95)``; the affine also changed from array([[-2., 0., 0., 90.], [0., 2., 0., -126.], [0., 0., 2., -72.], [0., 0., 0., 1.]]) to array([[1., 0., 0., -98.], [0., 1., 0., -134.], [0., 0., 1., -72.], [0., 0., 0., 1.]]). Additionally, the new template has also been rescaled; whereas the old one varied between 0 and 8339, the new one varies between 0 and 255 (:gh:`2738` by `Ana Luisa Pinho`_). + +- Function :func:`~datasets.load_mni152_brain_mask` accepts now the parameter ``resolution``, which will set the resolution of the template used for the masking (:gh:`2738` by `Ana Luisa Pinho`_). + +- Function :func:`~masking.compute_brain_mask` accepts now as input the whole-brain, 1mm-resolution, MNI152 T1 template instead of the averaged, whole-brain, 2mm-resolution MNI152 T1 template; it also accepts as input the grey-matter and white-matter ICBM152 1mm-resolution templates dated from 2009 (:gh:`2738` by `Ana Luisa Pinho`_). + +- Common parts of docstrings across Nilearn can now be filled automatically using the decorator `nilearn._utils.fill_doc`. This can be applied to common function parameters or common lists of options for example. The standard parts are defined in a single location (`nilearn._utils.docs.py`) which makes them easier to maintain and update (:gh:`2875` by `Nicolas Gensollen`_). + +- The ``data_dir`` argument can now be either a :class:`pathlib.Path` or a :obj:`str`. This extension affects datasets and atlas fetchers (:gh:`2928` by `Raphael Meudec`_). + +Changes +------- + +- The version of the script `jquery.min.js` was bumped from ``3.3.1`` to ``3.6.0`` due to potential vulnerability issues with versions ``< 3.5.0`` (:gh:`2944` by `Nicolas Gensollen`_). diff --git a/doc/changes/latest.rst b/doc/changes/latest.rst new file mode 100644 index 0000000000..a1945f644d --- /dev/null +++ b/doc/changes/latest.rst @@ -0,0 +1,202 @@ + +.. currentmodule:: nilearn + +.. include:: names.rst + +0.8.2.dev +========= + +NEW +--- + +- **Support for Python 3.6 is deprecated and will be removed in release 0.10.** + Users with a Python 3.6 environment will be warned at their first Nilearn + import and encouraged to update to more recent versions of Python. +- Masker objects like :class:`~nilearn.maskers.NiftiMasker` now belong to the + new module :mod:`nilearn.maskers`. The old import style, through the module + ``input_data``, still works but has been deprecated. + (See PR `#3065 `_). +- New module :mod:`nilearn.interfaces` to implement loading and saving utilities + with various interfaces (fmriprep, bids...). + (See PR `#3061 `_). +- New submodule :mod:`nilearn.interfaces.fmriprep` to implement loading utilities + for :term:`fMRIPrep`. + (See PR `#3061 `_). +- New function :func:`nilearn.interfaces.fmriprep.load_confounds` to load confound + variables easily from :term:`fMRIPrep` outputs. + (See PR `#2946 `_). +- New function :func:`nilearn.interfaces.fmriprep.load_confounds_strategy` to load + confound variables from :term:`fMRIPrep` outputs using four preset strategies: + ``simple``, ``scrubbing``, ``compcor``, and ``ica_aroma``. + (See PR `#3016 `_). +- New submodule :mod:`nilearn.interfaces.bids` to implement loading utilities + for :term:`BIDS` datasets. + (See PR `#3126 `_). +- New function :func:`nilearn.interfaces.bids.get_bids_files` to select files + easily from :term:`BIDS` datasets. + (See PR `#3126 `_). +- New function :func:`nilearn.interfaces.bids.parse_bids_filename` to identify + subparts of :term:`BIDS` filenames. + (See PR `#3126 `_). +- New submodule :mod:`nilearn.interfaces.fsl` to implement loading utilities + for FSL outputs. + (See PR `#3126 `_). +- New function :func:`nilearn.interfaces.fsl.get_design_from_fslmat` to load + design matrices from FSL files. + (See PR `#3126 `_). +- Surface plotting functions like :func:`nilearn.plotting.plot_surf_stat_map` + now have an `engine` parameter, defaulting to "matplotlib", but which can be + set to "plotly". If plotly and kaleido are installed, this will generate an + interactive plot of the surface map using plotly instead of matplotlib. + Note that this functionality is still experimental, and that some capabilities + supported by our matplotlib engine are not yet supported by the plotly engine. + (See PR `#2902 `_). +- When using the `plotly` engine, surface plotting functions derived from + :func:`~nilearn.plotting.plot_surf` return a new display object, a + :class:`~nilearn.plotting.displays.PlotlySurfaceFigure`, which provides a + similar interface to the :class:`~matplotlib.figure.Figure` returned with the + `matplotlib` engine. + (See PR `#3036 `_). +- :class:`~nilearn.maskers.NiftiMapsMasker` can now generate HTML reports in the same + way as :class:`~nilearn.maskers.NiftiMasker` and + :class:`~nilearn.maskers.NiftiLabelsMasker`. The report enables the users to browse + through the spatial maps with a previous and next button. The users can filter the maps + they wish to display by passing an integer, or a list of integers to + :meth:`~nilearn.maskers.NiftiMapsMasker.generate_report`. +- New class :class:`nilearn.regions.HierarchicalKMeans` which yields more + balanced clusters than `KMeans`. It is also callable through + :class:`nilearn.regions.Parcellations` using `method`=`hierarchical_kmeans` + + +Fixes +----- + +- When a label image with non integer values was provided to the + :class:`nilearn.maskers.NiftiLabelsMasker`, its `generate_report` + method was raising an ``IndexError``. + (See issue `#3007 `_ and + fix `#3009 `_). +- :func:`nilearn.plotting.plot_markers` did not work when the `display_mode` + parameter included `l` and `r` and the parameter `node_size` was provided + as an array. + (See issue `#3012 `_) and fix + `#3013 `_). +- :meth:`nilearn.glm.first_level.FirstLevelModel.generate_report` threw a `TypeError` + when `FirstLevelModel` was instantiated with `mask_img` + being a :class:`~nilearn.maskers.NiftiMasker`. + :func:`nilearn.reporting.make_glm_report` was fixed accordingly. + (See issue `#3034 `_) and fix + `#3035 `_). +- Function :func:`~nilearn.plotting.find_parcellation_cut_coords` now returns + coordinates and labels having the same order as the one of the input labels + index (See PR `#3078 `_). +- Convert reference in `nilearn/regions/region_extractor.py` to use footcite / footbibliography. + (See issue `#2787 `_ and PR `#3111 `_). +- Fixed Hommel value computation in `nilearn/glm/thresholding.py` used in the + `cluster_level_inference` function. See PR `#3109 `_ +- Computation of Benjamini-Hocheberg threshold fixed in `nilearn/glm/thresholding.py` function (see issue `#2879 `_ and PR `#3137 `_) +- Attribute `scaling_axis` of :class:`~nilearn.glm.first_level.FirstLevelModel` has + been deprecated and will be removed in 0.11.0. When scaling is performed, the + attribute `signal_scaling` is used to define the axis instead. + (See issue `#3134 `_ and PR + `#3135 `_). + +Enhancements +------------ + +- :func:`nilearn.image.threshold_img` accepts new parameters `cluster_threshold` + and `two_sided`. + `cluster_threshold` applies a cluster-size threshold (in voxels). + `two_sided`, which is `True` by default, separately thresholds both positive + and negative values in the map, as was done previously. + When `two_sided` is `False`, only values greater than or equal to the threshold + are retained. +- :func:`nilearn.signal.clean` raises a warning when the user sets + parameters `detrend` and `standardize_confound` to False. + The user is suggested to set one of + those options to `True`, or standardize/demean the confounds before using the + function. +- The :doc:`contributing documentation` and + :doc:`maintenance` pages were improved, especially towards ways + of contributing to the project which do not require to write code. + The roles of the :ref:`triage` were defined more clearly with sections on issue + :ref:`issue_labels` and issue :ref:`closing_policy`. + (See PR `#3010 `_). +- It is now possible to provide custom :term:`HRF` models to + :class:`nilearn.glm.first_level.FirstLevelModel`. The custom model should be + defined as a function, or a list of functions, implementing the same API as + Nilearn's usual models (see :func:`nilearn.glm.first_level.spm_hrf` for + example). The example + :ref:`sphx_glr_auto_examples_04_glm_first_level_plot_hrf.py` was + also modified to demo how to define custom :term:`HRF` models. + (See issue `#2940 `_). +- :class:`nilearn.maskers.NiftiLabelsMasker` now gives a warning when some + labels are removed from the label image at transform time due to resampling + of the label image to the data image. +- Function :func:`~nilearn.glm.second_level.non_parametric_inference` now accepts + :class:`~pandas.DataFrame` as possible values for its ``second_level_input`` + parameter. Note that a new parameter ``first_level_contrast`` has been added + to this function to enable this feature. + (See PR `#3042 `_). +- Tests from `nilearn/plotting/tests/test_img_plotting.py` have been refactored + and reorganized in separate files in new folder + `nilearn/plotting/tests/test_img_plotting/`. + (See PR `#3015 `_) +- Once a :class:`~nilearn.glm.second_level.SecondLevelModel` has been fitted and + contrasts have been computed, it is now possible to access the ``residuals``, + ``predicted``, and ``r_square`` model attributes like it was already possible + for :class:`~nilearn.glm.first_level.FirstLevelModel`. + (See FR `#3027 `_ + and PR `#3033 `_) +- Importing :mod:`nilearn.plotting` will now raise a warning if the matplotlib + backend has been changed from its original value, instead of silently modifying + it. +- Function :func:`~nilearn.plotting.plot_img` and deriving functions like + :func:`~nilearn.plotting.plot_anat`, :func:`~nilearn.plotting.plot_stat_map`, or + :func:`~nilearn.plotting.plot_epi` now accept an optional argument + ``cbar_tick_format`` to specify how numbers should be displayed on the colorbar. + This is consistent with the API of surface plotting functions (see release 0.7.1). + The default format is scientific notation. + +Changes +------- + +- Nibabel 2.x is no longer supported. Please consider upgrading to Nibabel >= 3.0. + (See PR `#3106 `_). +- Deprecated function ``nilearn.datasets.fetch_cobre`` has been removed. + (See PR `#3081 `_). +- Deprecated function ``nilearn.plotting.plot_connectome_strength`` has been removed. + (See PR `#3082 `_). +- Deprecated function ``nilearn.masking.compute_gray_matter_mask`` has been removed. + (See PR `#3090 `_). +- Deprecated parameter ``sessions`` of function :func:`~nilearn.signal.clean` + has been removed. Use ``runs`` instead. + (See PR `#3093 `_). +- Deprecated parameters ``sessions`` and ``sample_mask`` of + :class:`~nilearn.maskers.NiftiMasker` have been removed. Please use ``runs`` instead of + ``sessions``, and provide a ``sample_mask`` through + :meth:`~nilearn.maskers.NiftiMasker.transform`. + (See PR `#3133 `_). +- :func:`nilearn.glm.first_level.compute_regressor` will now raise an exception if + parameter `cond_id` is not a string which could be used to name a python variable. + For instance, number strings (ex: "1") will no longer be accepted as valid condition names. + In particular, this will also impact + :func:`nilearn.glm.first_level.make_first_level_design_matrix` and + :class:`nilearn.glm.first_level.FirstLevelModel`, for which proper condition names + will also be needed (see PR `#3025 `_). +- Replace parameter `sessions` with `runs` in :func:`nilearn.image.clean_img` as this + replacement was already made for :func:`nilearn.signal.clean` in + `#2821 `_ in order to match BIDS + semantics. The use of `sessions` in :func:`nilearn.image.clean_img` is deprecated and + will be removed in 0.10.0. +- Display objects have been reorganized. For example, Slicers (like the + :class:`~nilearn.plotting.displays.OrthoSlicer`) are all in file + `nilearn/plotting/displays/_slicers.py`, and Projectors (like the + :class:`~nilearn.plotting.displays.OrthoProjector`) are all in file + `nilearn/plotting/displays/_projectors.py`. All display objects have been added to + the public API, and examples have been improved to show how to use these objects + to customize figures obtained with plotting functions. + (See PR `#3073 `_). +- Descriptions of datasets retrieved with fetchers from :mod:`nilearn.datasets` are + now python strings rather than `bytes`. Therefore, decoding the descriptions is no + longer necessary. diff --git a/doc/changes/names.rst b/doc/changes/names.rst new file mode 100644 index 0000000000..1851ea1146 --- /dev/null +++ b/doc/changes/names.rst @@ -0,0 +1,191 @@ +.. _Ahmad Chamma: https://github.com/achamma723 + +.. _Aina Frau-Pascual: https://github.com/ainafp + +.. _Alex Rothberg: https://github.com/cancan101 + +.. _Alexandre Abadie: https://github.com/aabadie + +.. _Alexandre Abraham: https://twinee.fr/ + +.. _Alexandre Gramfort: http://alexandre.gramfort.net/ + +.. _Alexandre Savio: https://github.com/alex-savio + +.. _Alexis Thual: https://github.com/alexisthual + +.. _Amadeus Kanaan: https://github.com/amadeuskanaan + +.. _Ana Luisa Pinho: https://github.com/alpinho + +.. _Andrés Hoyos Idrobo: https://github.com/ahoyosid + +.. _Ariel Rokem: http://arokem.org/ + +.. _Arthur Mensch: https://www.amensch.fr/ + +.. _Ben Cipollini: https://github.com/bcipolli + +.. _Bertrand Thirion: https://pages.saclay.inria.fr/bertrand.thirion/ + +.. _Binh Nguyen: https://www.imo.universite-paris-saclay.fr/~tbnguyen/ + +.. _Céline Delettre: https://github.com/celinede + +.. _Chris Gorgolewski: https://github.com/chrisgorgo + +.. _Chris Markiewicz: https://github.com/effigies + +.. _Christian Horea: http://chymera.eu/ + +.. _Colin Reininger: https://github.com/reiningc + +.. _Dan Gale: https://danjgale.github.io/ + +.. _Daniel Gomez: https://github.com/dangom + +.. _Danilo Bzdok: https://github.com/banilo + +.. _Demian Wassermann: https://github.com/demianw + +.. _Derek Pisner: https://github.com/dPys + +.. _Dimitri Papadopoulos Orfanos: https://github.com/DimitriPapadopoulos + +.. _Elizabeth DuPre: https://elizabeth-dupre.com/#/ + +.. _Elvis Dohmatob: https://dohmatob.github.io/ + +.. _Eric Larson: https://larsoner.com/ + +.. _Evan Edmond: https://evan.science/ + +.. _Fabian Pedregosa: https://github.com/fabianp + +.. _Franz Liem: https://github.com/fliem + +.. _Gael Varoquaux: http://gael-varoquaux.info/ + +.. _Gilles de Hollander: https://github.com/Gilles86 + +.. _Greg Kiar: https://gkiar.me/ + +.. _Greydon Gilmore: https://www.greydongilmore.com/ + +.. _Guillaume Lemaitre: https://glemaitre.github.io/ + +.. _Hao-Ting Wang: https://wanghaoting.com/ + +.. _Ian Abenes: https://github.com/boredStats + +.. _Jake Vogel: https://github.com/illdopejake + +.. _Jan Margeta: https://github.com/jmargeta + +.. _Jaques Grobler: https://github.com/jaquesgrobler + +.. _Jason Gors: http://jgors.com/ + +.. _Javier Rasero: https://jrasero.github.io/ + +.. _Jean Kossaifi: http://jeankossaifi.com/ + +.. _Jean-Rémi King: https://github.com/kingjr + +.. _Jeremy Lefort-Besnard: https://jlefortbesnard.github.io/ + +.. _Jerome Dockes: https://jeromedockes.github.io/ + +.. _Jerome-Alexis Chevalier: https://github.com/ja-che + +.. _Johannes Wiesner: https://github.com/JohannesWiesner + +.. _Jon Haitz Legarreta Gorrono: https://github.com/jhlegarreta + +.. _Jona Sassenhagen: https://github.com/jona-sassenhagen + +.. _Joshua Teves: https://github.com/jbteves + +.. _Julia Huntenburg: https://github.com/juhuntenburg + +.. _Kamalakar Reddy Daddy: https://github.com/KamalakerDadi + +.. _Konstantin Shmelkov: https://github.com/kshmelkov + +.. _Kshitij Chawla: https://github.com/kchawla-pi + +.. _Loic Estève: https://github.com/lesteve + +.. _Loic Tetrel: https://ltetrel.github.io/ + +.. _Matthias Ekman: https://github.com/mekman + +.. _Martin Perez-Guevara: https://github.com/MartinPerez + +.. _Martin Wegrzyn: https://github.com/mwegrzyn + +.. _Mehdi Rahim: https://github.com/mrahim + +.. _Michael Eickenberg: https://github.com/eickenberg + +.. _Michael Hanke: https://github.com/mih + +.. _Michael Notter: https://github.com/miykael + +.. _Michael Waskom: https://mwaskom.github.io/ + +.. _Moritz Boos: https://github.com/mjboos + +.. _Nicolas Gensollen: https://nicolasgensollen.github.io/ + +.. _Oscar Esteban: https://github.com/oesteban + +.. _Óscar Nájera: https://github.com/Titan-C + +.. _Paula Sanz-Leon: https://github.com/pausz + +.. _Peer Herholz: https://peerherholz.github.io/ + +.. _Philippe Gervais: https://github.com/pgervais + +.. _Pierre Bellec: https://github.com/pbellec + +.. _Pierre Glaser: https://pierreglaser.github.io/ + +.. _Pierre-Olivier Quirion: https://github.com/poquirion + +.. _Pradeep Reddy Raamana: https://github.com/raamana + +.. _Raphael Meudec: https://github.com/RaphaelMeudec + +.. _Robert Luke: https://github.com/rob-luke + +.. _Roberto Guidotti: https://github.com/robbisg + +.. _Ronald Phlypo: https://github.com/rphlypo + +.. _Ryan Hammonds: https://github.com/ryanhammonds + +.. _Salma Bougacha: https://github.com/salma1601 + +.. _Simon Steinkamp: https://github.com/SRSteinkamp + +.. _Sourav Singh: https://github.com/souravsingh + +.. _Sylvain Lan: https://github.com/SylvainLan + +.. _Sylvain Takerkart: https://github.com/SylvainTakerkart + +.. _Taylor Salo: https://tsalo.github.io/ + +.. _Thomas Bazeille: https://github.com/thomasbazeille + +.. _Tom Vanasse: https://github.com/tvanasse + +.. _Vincent Michel: https://github.com/vmichel + +.. _Virgile Fritsch: https://github.com/VirgileFritsch + +.. _Yaroslav Halchenko: https://github.com/yarikoptic + +.. _Zvi Baratz: https://github.com/ZviBaratz diff --git a/doc/changes/whats_new.rst b/doc/changes/whats_new.rst new file mode 100644 index 0000000000..3e0fbe3749 --- /dev/null +++ b/doc/changes/whats_new.rst @@ -0,0 +1,62 @@ + +.. _whats_new: + +What's new +========== + +.. _latest: +.. include:: latest.rst +.. _v0.8.1: +.. include:: 0.8.1.rst +.. _v0.8.0: +.. include:: 0.8.0.rst +.. _v0.7.1: +.. include:: 0.7.1.rst +.. _v0.7.0: +.. include:: 0.7.0.rst +.. _v0.6.2: +.. include:: 0.6.2.rst +.. _v0.6.1: +.. include:: 0.6.1.rst +.. _v0.6.0: +.. include:: 0.6.0.rst +.. _v0.5.2: +.. include:: 0.5.2.rst +.. _v0.5.1: +.. include:: 0.5.1.rst +.. _v0.5.0: +.. include:: 0.5.0.rst +.. _v0.4.2: +.. include:: 0.4.2.rst +.. _v0.4.1: +.. include:: 0.4.1.rst +.. _v0.4.0: +.. include:: 0.4.0.rst +.. _v0.3.1: +.. include:: 0.3.1.rst +.. _v0.3.0: +.. include:: 0.3.0.rst +.. _v0.2.6: +.. include:: 0.2.6.rst +.. _v0.2.5: +.. include:: 0.2.5.rst +.. _v0.2.4: +.. include:: 0.2.4.rst +.. _v0.2.3: +.. include:: 0.2.3.rst +.. _v0.2.2: +.. include:: 0.2.2.rst +.. _v0.2.1: +.. include:: 0.2.1.rst +.. _v0.2.0: +.. include:: 0.2.0.rst +.. _v0.1.4: +.. include:: 0.1.4.rst +.. _v0.1.3: +.. include:: 0.1.3.rst +.. _v0.1.2: +.. include:: 0.1.2.rst +.. _v0.1.1: +.. include:: 0.1.1.rst +.. _v0.1.0: +.. include:: 0.1.0.rst diff --git a/doc/conf.py b/doc/conf.py index 621d14aff1..2e53ddd21e 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -55,6 +55,7 @@ 'sphinxcontrib.bibtex', 'numpydoc', 'sphinx.ext.linkcode', + 'gh_substitutions', 'sphinx_copybutton', 'sphinxext.opengraph', ] diff --git a/doc/index.rst b/doc/index.rst index d5ee78b64e..16ffe229e3 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -105,7 +105,7 @@ authors.rst user_guide.rst auto_examples/index.rst - whats_new.rst + changes/whats_new.rst development.rst maintenance.rst glossary.rst diff --git a/doc/logos/hbp-logo.png b/doc/logos/hbp-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5fa97f13b9a18f69d6f9d231244bd70673bc7a26 GIT binary patch literal 24409 zcmaI6b9iP!voHF_wllG9+fF97?c|MZ+xEn^ZQFJ-aVE|LcfNi0KIi^%?p^BD{nW3j zx~f(`tE)RwQ9%*`78e!(03b+9i7Edp$N$}-(4haGi62DX{|X!zaZMK$2Xhy9BPTO} zu&INw8IiP|k%gJEnUSd{aKela001MlQq^?Pl$YZ%aj;`B`VS3*hn?d;GyuRS=;3H& zVq@k)WNc<(WzSD?+to)xWM#@vqQNfDB=0C{W@#nm+GN zU{CZPjz-1~t}gr}|1|wyU9fYMm;c|4?VbPIQ2$KE=wal@$jrdRXlM7Ie*G71f8NZ079X>SXfIALgY01O8{b|9?UMA^fKekC=mrtDTv>i?kR&$-fo` zQ!7&*CRTA)HdZlKQ7&$7W@hn!y%v=a6BXm+VrJ(M<6`6dAFQ;!vx||viP`^Pt^N;| z<^LDUBkE*kfm7eKi*TcbZ~KSwsdeL5)~z)(y+2Ob#Qm4{*PtpM! z2`2|TqW>}tkJbN0yo4CLn6Nk(D0eYATjNCl06MeMV#2B( zn^!$B?ZsAV6tCCcm|L;!I=kCVjVw)-sMaPL>cD{pyEeCh)iF=J#MbcNR=(zn5(}6{ z=-{?u1;WVUrg#`K$hz7}4PxjZ(T&gaFWuhN-_JG9vxHhJ@2}JFtB>oPQ!$;HIIa%c z5rT*Q-!I*_Z?oKl2*e3xj|jU&p?%cA5JeFj;2kG%wdWB?-~H|!cHQL zA1Q3Q`Idib@ejhvFL8FcygrBeMFpskvfLQQXLp0CA^%r4jXZ>}``6!xaEpLB_`Q&> zm=D(W$TF@<+$*+rSdxA%q&%1a^x)fl>X!gAjxo%VO%w+Z;EAQjzzLRehr%S3G?3w; z>snnaNk>}mv%=Be?f#E;f-KOdv8P>ZqL4~kM}HQ(fSIY{ZUvW)y$8}krT zKT{uUb;bXeMtL|<8dZ+++&-Pk`|BL|2RpqU`D6_MmL5`U86HqzC@k@PMzF=0 zk7_9GqfPZT{UCQY=t)PM4%;(up&7||jFE5ujL*M(TPMEI zztv)IK`x)znJ_{1X%ST6kJ(?;kCws-yZCfp_FKt3V2~IL zpSt229!no&b=4u{LNwJ}Kro(r%0yDa24T0u{gDHlz2%gyw+U)o8UKkGb3_V*8=YAU z?cx4C+g-%HSUsE2y4>pep=`M}nH=1G&em@yhDFs0EO(8E#_g6?aZ=G(U@Msmric~Y zi@w#b7_+p&2d&t9Rhv0LS(Klj6DH#RSiWm;1WP-B4kbr`U2RPTL9-ghj{_irSLOt( z`xMy5u>1K#99B>_%|>ZmpK@3nz<#ljOlP|tNfC5{rVJEg(autw zYly(5ynaTe8$C*e35@TT;k|ns17#r10BUKGkcothf?R+}xf&BJ(Nwp|w)K`;ceb0H zS|GFU-ca(>4rA|;S({?2A?P7BE^NNjDyO34!k5x45oi`tZ-e*Q-_Jo55mNTuRI$-d zfkaSCFn-*-WK%Zlt zYXPn;?LzxB+Q@0&Wt`=Ep1k}%TxS@R)421Zp|K^lZNdBc$e2KAMHW5N2^MM0h>NZA zlar!|G`-Hj_crAEw z5=4oz8Mx`aka}$%OOqij~TG%IM!^&@7O+yg4g__x9~DRJ<~M~?#8ZZ2iRF9 zkyziY-RGWHa^IK4Oe6Lu5!Awo%Z>2Hm=cesvGi7;Vtf~yj$tK+M|cGUDr3W{5eaM7 zRaw#8BUeC@JFBtHYq1!SkgJJB=uyi9jz)M9hfpgPC9MbpRO9$tl4=!6Tq<3*7(-auwBd%LGyd& zA)m-Qpe6{)eFQ?R|GsN)-EYh06Jcy9u}p=cIT!Mm7M{^^d=j7x6S)*!N#++q%<&}k z;?^1VyoxXa(`<}{EZa_<=mcLGsHMH!74)NkhkW#a%&9rYqgTJ0sBtNliTlh<E*O4oD(3PG~$IUCOLBUHLaUZp&9|h?g!-y2D#^$yI}bJ zxWSU9cTl~eF|$NK0JKN{!QZ_VzsvZh5|FMN3C8lX$R*r;hy)Uv2kB@E`ca5)K8Eeo6T3-KO`8_w zL-+(zla>}chWu3=Jn2P0lB9jWauTQxOraQw)+o&IL3cGSDnfV~7N&aI?pqns=lu7Z z6>4Q!OeU%Zbphzeh$&wi(IgBbOlJ2{8P@KHSJxsOCx5a;gCXB~#WKj9n1=)x;FmaQ zL^>=q`E^}VwS(!P)v)ah7&!4IpzOCF2~=Q8l-Ynyil*0~$PS%pFsw+nAsD_!sv71L zPCGgS9c*pWm59D3phl6XwEu>lX63Xp$NP+;#DDIkJEK1}C>`GSV~&0Fo$@|_pvr*H^2tzIUE2Tf zcl8!%iHMp6!h_PC6@{vfj6U4SVGPpqLuzuhYl`KNT_`HOY6^`@gwjtkT9E1hlMrrv zum~EZIy6F*>0dU0q{7i9CT3(~J5afaa4l4;6Rksyy!v*7xx?lJDJ8?9Y&2pq0PN%#>(JF!)HnWCx1 z@;BC^OC!mC^JPe1O6jzAiUBxaQ3G633aFiRX0KSNBRMrmprfXSTE^Y=T5O_9ig}%8 zz3P7nr2Xj^aj@Vh34lbDnGH@`^z4ARk4wZf+rH z=6#Fec93*<`}`Xf)cx?cHzpY6>EL4JUgJkSlMNuH9~@T%BK`R|_f}Q#A#5JS*epqY7g8I-r4s3;>;>N0YzNy;l6dO|b#eU0o#p~EBlimZwI+Jz+8@rB3EJvb>)^_h60Ak~Tqf0tY z4MVe?%BE%7jgR|p^qNUt&ZHg|kfUav;3`DVn_>}C?%#*}18c$*xb}<~ls}S_X^IY3 ztX$GiT&}G(m5iDh=FJqwe55lPpfE_6%AhRr(y}SJnaf%;F{HCkM?YqumT2zS;4!g^ z+2ygEd?D!f_@!m!e-EYKU*0~d`7Jgc1PxL?2{Yk;ko)^m|BQF?rP1^rFu@ZBMa){8 z1cv&fIY`n z7y}c{1O~jDF2XzImfSU}F$DUUTLisC9a{FSeKoC7A!jv}cwDm^gWTew5Y+1g+{fbg zc5Q9i(PO8+1-mriZVq27D?~7|_;}xFMkrk#B2VY3lK1oOULRxH)%D(s**vxq6RrmW7f-Y*FLmI7@gZJCYY#pv2sB`VoC+;Wd^;UIq+1u>O-?f!{0>ye0NI52 zt}^95v(9)@NEzactR$<+N{a_=Q4EB@WDN5cw7vqbobvHD`Q26AX=|;`UR<&T-j;iD z`gR+0p7o}ZM6hPncAIj%b85q)A$ z6dQVZ1V7XuGFcunZRofT)aF;@4;&2GF2efn0aj4IM(C7K55Yp*VN?fgQod61Z2(^& za%vN(AHuQVhz#UF#=fy_<<#3UPgX@SqwsEG7L>ixSSlo$w#paf%JTa`dq9DA^A^2p zLyfC!KYO6~D=oi}-mpp9)1krpy2;*O{kurqsz4?@1C#1+8O~rhJh>n^@Wmv&_Q~$A zvm`=)J??#CtzzN%7SWYILZg$kht(8AdS8!Qy8a7-UinX~gk@wWY*9iko&%*!pti^tu^JgFZ+`UBDz7P z5h)SdE4`NHBn96$`7jm8y0axX@ifK|t(Xi~ku|n9LM-&W{_xCeNHGKqZ7|@Uslx_G z66Zc{aa?*WKL2&l7^(HYVpXb)h-nDHp(EI3Iz~Mv=8A;)s!5Y}iBL@kJEgC9Fd~n_ zgxIS@(Ws@Sf0W-Mvb%x1i$sP&=yATRHV)6{z>c{JjWF$SJBy~45<~`WZ^Xd#o61h| ztpC8m`gSvNG2-KwYE&I3lPFAs0iJG$tr4FcYWO`Y&~-fE3*LzgzOE?$Xg_1e6bnDa zg=i6YJ0P_Ap4Pco@jZO4SRG(*%<1s;b$qDK@YFFWG1rR7cKB5^^2aD*QE>&?15}o} zV%%dWh9TvL7zK=;CQNQB(}xbtmXJ5HH4GBfVZb*Y)TyXp;QkB7Q6gAvqyvdL{x<%Y zxUCzTRT-#Fs?8aVF?ui)v~EcM5u!p@<8%!ukUUp#ck_bP6_}QfbBo!LZ`md&9aq|) zXNc8q7=UK&6XD~rIxx~SDYNO zkvbGZLYNQ(r@DgF$gk;*#2r0KUZn6bfum;w!dx%JrGg}HVJ>(p`M5$Ys>6YxG&i=x zejj4UQEd^oqGrn9)>X2g=Y9sfdfe%N6=tY??N*z~V^PIS<9alSiL(up-Qf79)9pL^b1G-GfFtmA zqKnh-amW9C^ZS4tRt~atQv@DSUbT2F;3>YBn{UhXaV`Hgr-!QVjMoPFYKUGiE0o6q z^sy0k)6zgi1%Np`v6LZICn1l!Vj|roS`1Fp(2~F@JL)8KNnC&YLv05d+)i2Fi`^avJ4SQM z(B;&%XfbthP_)_HnnvPO1Oc#+=NGVx`a?YEL^lAkxHy}dH7q80G(VVmU|J~;I}8P2 z*XI^su&L549d2@1f4NfmJ7+(A)9rmk-gc8;r&pAZ@qt^Pr%P7MPF#~KqUUbOfzt$+ z4p9L!{==b($m&A}3i#SEh^--}>}86DX!=Xn=MVKx z|F?6m-J7z_fWIjwnEy?(cXCI^l4d9{bGnnm^ z-5Puzg%i-82x-@4h5gbp>s-Fp(Xui7{k~cY1o12DP;`vVx>k#BUkijV60(m!u3s!r z8fDSGdi`Z{vh%W}Y@)rbDUh9{fAKSiq$w)Bgq*{p-fYu5wgfgOcoO2&a&n>~6(#UI zO(Y}A6c-93x_wBSpU^!*Dv**d!ipK%elUr^2q)1FDG+0tkk!iR%5vGMHEbUv=Gw!P zOYxG8j6WCgAOJcG{VhERw%JMVY)hr^~kh-~HRy5)? zpo63xn3uoZ=5f3FylRg_iQ+n{{VGey>sPQRO|i6rEdZIPzrD`gy(v+%dVE;NyqYYN zfXd?Ycm+@}(`!)fs6hV=y=wjOboRv|CreUO<>Wd=Pb|BBgBbv@k?)3FG&019B$ZK~ z=3t%@$0LUgl1>7xr&2-ppqiB0BmoYmkQuHogQ`%^LseBz#Bp_ynS#>9iqi+d%&y`l z0u&A`DUtppYL0IW#N|Y$?68+_TOJcvzN{ey2(S^ zJ4ZEtDtAK>8mv=jqaB@F$|O}&aq-r#My|Z7_=_;=7E2-~9zh+?PA}s=r0@2#-{8H9 zA!t)5gQP?DC>DWLi<-!=NSla@i!{;|2T?FbVo5Dipazgf+Jaz%ZXjzKQ`VO&29CiT-t*Kz!3 z*X>7MdIEDLK^ma4==O70!}pZc9iP`tQ36yneaO)KAl`7Ri}&aNxfsU~Vm)fCLB^}6 zWOo2<4gb3lt9r*HYh!k{K z4xQb6Uu4^Nes-o#{pixx*nEHi*WRbDNkHF{q6FUse= zpap8lQTTr%-EM-w+S+ppUXNn+yn1$W{8H*@TpYm^r}HM}(pQe)io5N3VR(HH4|ktp z&AVSr_fr$dgduKWUfQ@?fFgXIzV%Bnl;Plc+qMum^ZvSaWqgmaBX$o%ONF+l4;hSz zv{H*}k*~+D$6=FV+OuN5Y0Rxq7xCNE*mZL%VI{C%0~j&<*`Bqw;Hw4NoqTOecwQhA zlj+KG@=auS*4s#^v`=bT)ht&t?aJVxf-~W+)GnQ^nCsce9)(b3X&cfl3l>wfh5@WE zlz|tv=(=x}>HL>!JwhJHV$wS9eL@BL}2`->!~rPea7Y@7>rz)FD;w=tZSje5qQ^G|;8EnN+wM-b1JGc!Gh8*7$)H{9p*=Byqy4zzmBB@;^c zXHFAIEPi)k4EBMfnJgRGXb~$%zx|<}fTg|;2!ZH(%^x+_A*o_zx^!i5D1*t@ZCQq z{lA@Z9bVpL6U$J-Ej4dbS{Iw2OQA8vJ6ckoSn((|$JXgeIV6^Lx<~OCb*WZUOGb|& zblF$aWB5Egi=!ueP)`WtQLk%K2e>=4n3*zg@e!jX=U^3oLdLX#@C9ygc9I!>Tf=Go z>2y&;36@BYTnf`5XJ*G1SESkH($^8#bS({e2r*;2OIOv5r`ANCar8G&9^1;;G>5XK}kcvvxb5d4gfrMGE|L8H2sUrBC~Tq3b~YRpImKZ|Klyevgd&(-S2oI!V!*I3 zaA{Ok+CX1n%0lRs#6A^rAl^Y3UtK-h+UQ>YzBEu2>Ym@7jBY_BO zNXyud#?`@w*WZB$EefMjs%Xcs;8)~sr6~@))mTj_XgM!_9H~`|Y8W>PEQeRKd$134wkvB1MqyImD=w(#aemG5v6bUbvf6$aPTT zKBF;%HT9Vk89hHaIQQIpl$Uhq!y$kKdENc_@$Bn=cR%pQy83uMWTyx`T?qukXfg04 zO}$fpJc&%9pI%)^7gsEmem}_Rjx-!(ci@PhPqY1fa9kHJ)29D@QIuGrXoNTAVC;GP zZPoEK$HcJCX8tFloNBp{AkOIlFGdAT`$h1Yr`Dt!1=e3jlJRE6meSfyRiXjx2M%9G3oq>(%XG>QdiVX0D4cNvQAjn>-%3V#VmNxaCEwQo;A`3Qu@q#DP{vpak^TN2dL((i1kh6ciB7Z zw(l=o;8g|2u*PubQIVcKId(GR#6BoJ!sa@B%UqW6B6480GSu;>uf*|4{E)I8tqz2q zK0Mw1Nh&1Nn*2PjPa_-6jl$#&;R%=0xZ{RZdlr&oZ3Uf2hHoz%0Q|#SbuKVge9Jh~_cU`Udgg9H;@Fd)|K7-CdB?{^-59S_lkx ziEsc~SX5EY;!tQ-_(CjbM`b+~fVy5&CnR=gBa>N4XRzgW;bcl-hP0iK*2aC<3M&Ox zeYb*4HLKM+G#EOC;r;eH3nd37=-;Xai^K`@!-PQ*w;b+6TwT3|31_K}H$1&tK*n8n zM&&VH#N)IJ*D6PbjVQdo=nu1{w-S=Mqc`%UZB64^eb=i)ftST$FDa8|!lteolE+acYTa4Hi!N zc7t^>=vLt9IqnQu;x^LRucMkGe@q%X?!1{j2vm;7)MWS+l`G5dnNadF-AOdwG{mHaQoHj)e*H|5prlW1{p%(r2cay_jwSjyRr#~IK%ci$6rmh-q@XX zYjV(so|$wm<1&OHJP@5pGa-o3DFaK~-i9d5iU^qc%$zM_KL-R4Zu+DqMQm@dF_WP| z3mdv+4~6HuI;B(Z1CF{D{sj7^0B)2-3CpJm}qK$(M;pZ=F*} zTV^N3rO1sM?u@EIpu)OjhL!1F_nm3@|E`_;BCmZ0SaW$#wE4@9{(8#ATZh#=dnT34 z_x4CQd#es>M+_sY$5l~hFm$K}9AXlD5Y1vCx%Q>DlKA;$EUB_v@v%@(fc;QoB}vu; zTTO?prMCR_mmm@^3HiQY^|F$NNAhPo8F7~h2nY;1kMp)kmm%^DBD#E43^-eWv}p^S zwAWEhi}C4FA03%=YwU7$I%lPc4-=&{@76smR>mXZ0q7eZcD+)CVeRZa=;b)Im znZe)ry3dcT-Br^*Y;d!)ZcCAaf|Xet3oy*Lkw7=Kx<0|L2j1^1uzy*zumCV!$~upk zpFVFIJ|`oRjQku7(nO|B@%<7vVi zC9PrB+Dp=+%M!f8T6iCV|NKxZ^(@$pO7KcvOEqrmW;(QgUhCW1^rPE-!5HBBJU95W zfF<5GC%$yF0-&7W5hEb$$w@+_X#N^NAlc8}eJp+HKI3nnOc|b;aKMA)08MJqTw%^k z0@tjCzZndj+4H`w`~GvO&x>QA74376)c3xn|JP)pS(7nJGW^$8t>Ej^Slu4oXh{?N zkJ0*6co7au|LUsNU7cZGMVh$2Vod;l_AF*s&zFdsr_C}+W-|2k7{iS&_J#f}3=GQi ztRKHOqGq!++b~itdAyw_bw))`g$s!nCt+LU;*u7)U>OJ}t4KCgt$!KBOz+#Cwu}=YRb=pca8LtB``qtwe0N*>n-~k$c7QdK2=88}#{r!G zlg5fI&(D1Q??J4+yPZ8*`>t!f{I6|yd~TMR2S(oRM|#fu+ETQiqQfSR9{Voz>e^5W zkptH^9+sfZ1E1_7vR;frzr=AU+YH+7B!@sj87vIxh8@lOJltL$7fNhmp2&Bs+co<< zC~#7bR>%h9w<&T%&W<*Ew!lq@&S|)QL$*ytwvW{cKwAb@oFbl=(-B*VMQ4~(=Q|~g z91b^Ga=Z22Cl_uPODdoxzLj!U4>XXHbbJp;&hokSQQ~8@!>{f;3c4VesfCS|1%VC$ zJt5RIFcf{m?nXX%94qbL{;|r-OoHt!hr_aBCFsi?8uy*C| zVefe#9LlOc^PjyYI`i^wE&X18YjhGPs6=goMy{gn=H7!x1eeClsOh0^NjS%6LAs4E zXOmv^uwa>LPF+4@=>0B~oQRG)B=Hc{@D6Vt&WjH5kYm%+YEEi0?^D)QrJmYh+@`M? z_3fTtGjhk0hL|C_bIju!rGsWLq|4%=+lx+4kRXedrW=wF)7I<#&M@Gc9-UreJ@n34 zwme324O;)$^WCG}y*pjYI9R5HOL@xbCUq)YeR_W%Jrn$XaS+F2cfI#Un^ zU}5C?HmQ5t)Bo)2^@8tZNHEf}F39Gp1+C!E^m1#UnX|oFzb2`(%WC+ML@qiaip3GW zMC0Brp@w0GAg0Z}F*ga^lIwqz+8kun%lcgnSv_<@MvJtjL=@+Su98Wlz0W?dmX@Bi z7)4v?c&oY)!4E}?^e!xC&#$lFwz!jp6G=_t=%`D>NTjQ|;NvC?3mP!gt#ot&AP0SE zDF(_EL082dMMzAF2NmOB1^lAs_e`#fZ;X``E>hB9PFV&lnIA$<(o-kH=a3fSVin&< zms)LJ(&zBFUYs!czm6s)toFz$ssNsi*Ur zsc~J}u$B~KO`X-aq^bTHXBxBhtwfbiWtFMaGSoFv0Dp!3%LR=Yd{2={5gJ2kpe+lO z!_+qq3I0THNP>Z8qDT+z`aIq|%E!|W_O^($n4|yAhM+@+r-MR?2qP*2?h#cyo}vOO z;1ni*gJ|J+WF0k@nxQ2vVHb1H=ete-%emtFqHZj>@Z$a$>xXz zgmi}FaPI{`5P%2oL3#FOEMV2q*Nx`Jc89FlF$;yoTjD#9-CY>^`0dN{U|L3SKD0|Q z3B^@Pe=NOO?wAi|r}S$GBvzL`cAB|a&bw@LUP5_WA2`mbakA+J6wa}FzKe|jBjfj> zs&gVhWrLw4fQWKLV`}Ne+RpCf5HN1ClA?JKoziL``(S+r{BQrs_ce$Seqiv>A5J_( zSv^WzQVMKvNO*7naRfXbr=SRO{oC-x{MF>t!JtJ@aw%UJ(*ioXBVzYSMq4TZh7>6* zE*zO`S9r>*snor=*;2VZ&AiS)+VEQQ#MBb)@S{QdzBr@D0jJ*(=QIX_=ZBoaR3qd_ z$c=n48^~xyO*9wp>cx#s$*7ToOYD!p0erjic%f(K=`&gA9bF;QP~L(C^3uOJxwqOo z%`*L42kVEhBuR#aX~Qp25g|w=CC5vM@TatS4@U)S*q7f*<_jIi#GH5-!NLJ5wdj%P zN~r75?&$yx#A0I8{u`C;=-~q~NSMmZ{wGEgMHBS;6`~l}6-{nQ7xCE96b>;VJ!BP* zrqWXwWg%8%4e3gl3JVbToQL?b%}=z=+sLh{-e(&^jY(61lp#nK)|F-k3uIUjJcefM zy|v$uA(bsN4a!KpA}6Buy0J$DV$;y(>~~&9iKZ|&3;;=3sJKrakCr=g1k_r%tAbYP zqC+Y1B-%h0IKz&F$fYW8cl+Huv|A(nZXxNjS74KW=yWOM*&_szpI$@T)d+2o}_eER{GqAO>8f$!cwX1iQpMud5T$Csju4F94 z_h(`VNbF&`{Uu)lrVYnMU@)kPG1Jj5HdJQb}ULV}o7!GmMJlh!q4h4rYnjbKYs z$stv=Tm)#5BW0u_i5Ec1gqtyRMJ@SSH}&*!ue1!W2O2Zq&Z*!<4o5HXYHyVz?2(Tg z%gE-HYA`Puu>+5I76b-D@d6Dsc1jkY9!|jy;f~xll>yc=KUv5r@#!)ouMhNo38^g1#N`_Q$!o zlF=PYi!RfRC+gG^{3bXBe~x>gm+YX8+0sHJfU}*W!ukALjzR64FJitaK<9c9QdJVe z$PrssmY2qG#5l$6M?%ef?L1ro7dmJ@EzNS+3iIW1(eDmOImwcNTEynHT^u_ofE@W@ zzK+7?Y@VI|%751n7K?N=vtTSXoQq5zeXz#7-a!(An>_@t&?-zE3Zu4PGstZM^qLm4 zQIuuwC9V`|3f@4Qe#?4DkV4i$UOdqq4$in}F$Q4jN(iYX?n{GXWyQ2}`MT7ncfCBX zC+Yz`G6KRL(&}7>tOa**PGXBsR5fWVX;be&+IUuf;31Ha;*3z`R1Yxlm-q~+ap_3x zYhD?1xYlMO-Zn_%lHwPD7#F?#3^Ay-qQv!&`eDw|;`hL>lh}FgQ&vowCgXR>>3<0$ zh<*A7D+Ut6h9`9h>_gwagJFVVtZD#H@tB2&88vzk{K#ydZ15X2nL6+aT)P9v>4tL< z(8331@YmvMpDmIpF!d!Ym!N4H%%CIs8^T2q=*Hx0Hue46Uve9WEDFf0qkyY#9F8L# zwAyS}pxhr_95#!DQm{57p5pW2j01Ax2Ez|n(;#1g22prO%of3~Wmu5HQ?JYFdCD2C z7DH+;$mbmbwGb`ga4&mt<#(4m_QTNIA6H{SJxPu~CZPoG#_~T*gFicnY?YI#b{pDN zy~E|TXU{O{EWwZzA6L`XlOQJ%d8<4PkF<|w`%r~~ShoS=N$+C9OyFmg2NTBo^a?5y z-dcFhtIFMIRho)KED+U`8;K*9C8QGsySTQuZ!7c5-6lPtzrhOi+xkYMz@Pz>up`=b zcsn4>VB1P{GmYqnF)QSTfs&CY%u*O~5983O-sqW?B;0OIfMR2FQiv?bB098dF()_j z7O4nS_$kSz2v;3C)PWUw{aub!%!1#fo8SZS-#3)K-+v7Ps{{-7e$)f6EXZlVNY@AT z)h!T0gl=U`>N^$!6-|T;S?z>O23`)}jPIu}fO!_kU_T7Sp-FXZ;vh=*Xy7zZC(sRS zN9duw@APqgmjXljje#mx&L4_>E7y7xv$}Ah2B?dK`7^8riZ!c{HK7FLhLs^uILTtj zHT9L?F5QDWBo{v5Ub14?uL%=m<+P{FjJQCYvyq64piy7LqKZN~cL8**x>^hE>{7N4 zt8JmfGeVE7Eeg7$QZ*%F+1x7+ta{#)N$Z^64N!v4TyW_tpGGoFAc2JnUM za{k&cAzKdIj!Gv?RaDF?PGEEEK5mXHwqIaE^TSZ1YL7qy`Y`WrJ8*YLrIdh^W=}PA zGe+qy8DoV!W*jNXSSG2V2ABm@V}qXum4R(JQ9Up<{F?EhB@?ms1K%@ogeJ0|_0A{^ zcBiD93P3!%2+Y*?MNc8noK7ytSWt~_WR`hsg5Smr9`LWm$#6tY+8LSk-|r?!AG273 zZ5iNMQu0Or7BI>SVYkJ;@NfTKBl$n70Mg+uhuV7HR_Z?5_VE8~Cuu_)LcF^ge8;+f zZRGOOI;bX*)r`6KMsc+RJ+J0crpvbh`?L&&Ht!CuLsRHas1_+#{O^;Ls(!hToO8pIr zgS~P9s+CTx(Me9tX-TDN@Y(wfzJCf=mqQX}x-^iN)`G>m%eoIu47EdH$BmkS8(#~M6n9jw+6WXO14Yp30pMTE zR;Oj@{p7ow4+j@)a|=H8s# zSGS6>HwxBWx7Ma7nX0c6v}31`jL|6P9L0?I)us*$4IE9_0$vWG?=YA-vQufIAYr1! z8{0Uab}sv)ps#ayjK2>B5?Tv$55Ye9P7#&KwK5qUSZudBQgUl}Wd{$D z6|q14R{UXDpl#BK=cgSwgWm3^i-U(k(7+S~9j*p%8b)4DwQGY5TSi)%*0>s4(_jZU zC|{?W+JXv>2>$p*w8p&byggCd%H7_l8q{YNFb~vkHZDma+U5?PiC?Q}Z8tTI$LKIH z>km3Q`qamH5F2J+@Bh7wi7_m!>#HuJ5}r*n^yUn51~i=1(?r23{y`vt2G@YNoX*j` zl^l#AN2GX-pV5!)eD4|w+N01AyMZP4Q|JfO1_kQ!7Wph@gp6J@(J~0?gOaO#8}{9* zlbXDQHj*np3m1ARRtZaznVyJG08|ZM+?Z*k3gl^dIbztuVkOi*maRjP}tlHM^ihYticTm_9jW! zRW+u#Ef@>9#7a3{zpH>3`oHT!d5k2xiyd0tR6O)i0!;Jr~(B`?W^C-)EzVKGMReHdybpqkVKH#WJXsz zCT#wd{1ep2yZE0Bw_o!1))gKAjrge`@DQkYChnWcAUP*D$Aif*E~V2bpk55Bu>AhV zK5)xAb3&n*9%B?N|BdDNlH-s}Au}5#*t;m`?yQk;5hKl&`ZwezEYVn&ueVhX>GfN* zS|8YPA`@L*BS&O1Si3Oy4#Sl8c_g*P`uD8s{_6Yorjh>aB0A?F9dL<~C|{pOf#F%u z-H-JU9vmy+w$r`}8S*M1;)u1$s?cV;23ZaoYt%Ci&D}S zYwPldQPTeYbZXDC-R+&n3KArRLbY6n6!%R8thT_YDK(KL-@xI1MsVX3jnR>wl14_H z0l$z&-1}y{M6b28;GpCwVz9&__UXmfWx*L90eX44QV zD|AZe<${b9s3w%Z^Zs}p|2Z(3n-4$d6L!rg-uVnMB>lBMOOi9jd|gO2ILn~*8<#0u zr179LJMHnj@O=Df76k^|ae(S3H+3apWy`!%wu|!jAwp%Bm`)Fob{u8WjK#jx4?10Yh@4Pn`r(;E~da^D0 zD@6?9l*xdUc%POo>8KXV`fFrBIEl=b(arXWjRK;0F2P4v>;x+$(CK>m&l zbQwRyF%z0AE1Ywcuw9q$j&ta8?HuYWy-u)s@dbqZ^CACg*3 z{+c~nTp|U|@udt`Nwe6tF`F5L7a=AaJC!d9EL+>9JXN+L+1b6AqEaWeD`q>+om_{n za*Etk4JH-}e#W%??EbQW+KC%ml=u>}cVVQIdi(h?{PW7{`s>wCqCGC2M`G3ByYbJ$ z*y5az`pdr+UP~=0fIeAF0beY_`Eg^hNW{wJwqdCIrZrGdOVg1iD_*K}09rZI`na)I zS721DiiYv%>u2{_KNQuTWoM}%O4;bvzFT!~zVpfJBG!dTml!6611^ULommv^%qmy4 zi<><0M=g6mxCK33-VNgHTxmW&0x8N+B5#e!AeKo(-4A-o4JUAq7uua^G&ds)$~9AV z8?YUWG=1DTg6(w~8+{#)t=as~$CCKI)2cKmxS5F zAD_3_pH=<~-0p#|BWw<-E`RY1u_>>@mhQhyZ0l9WCXK=ihj&`ReasNq z`r3+gDc^?6WbZHJVn2?@!Jq)|YEkgSq_9%Jo~%%Y&e;Rtbg2i=qBFGLb0gDW)l8RaE(! z=PsbAs_~a<2~k?Pjn^+A0~E3%o~HPvtMI0#DXbH&do>a;fw$eD-VRQSoxK9_keEZ& z!=og4$G%dv_Hr|vUT+MYspMdu98u`R5SB{AuDUuY-Tax6u&bFB$3p4Uh8O56{(7=w z%#u02Xoq-t#$WRiF8GK2GnB!8PqY{W-URMTO;}SS*n?7|v-!J1azFT9&}3=LT;i6=5JGCy%iqIqg`49c~dCj?tyy za~V#JshzKu27aWp>#FTe)nq+#AO}|HYP_wjU}NrCn5zmgO(m@X3=dw%)DSA&@M&7l zC)f9SRbNqGy(#blfTnp6bE$qnBaFHAH=#(w&Dy~WI#Cgq{dUMWrSj$T&$&+D{}aL; zJ>s2TdPL@hzjVoscPwyPS>ucinUY%b^#`hlK5N!5;J$%TY@?2)8Jv3(;o>i=rVhor zrM_~yWISe32Rp-XY6I@7(nKEY-uE;nBw{#4*#kr)Y|3GlQsoG?|9F>1Q6dE(${25m zWNMI0r^rTvFy(OT$Rac}uF=VoOHwt{oH=ax87V<1xf*Zm>O`Yj^6p9;Wz)Q^zs?Dxo+3b;f8X$!f{AIKIM$qN)T(NTgAou+@&wd{4$Nw zkSrRJQ9Y74ra|C9Tu|%vuFcnRq90Fj(?eH!k$Kf`=Fao^23;J7yZIKFNx?ChPgo>G zrjngmv00UtH8VY|w@pJ%o2Zr$y{t8};qKA!iyNC;lhS%#88WL34(*fC3}mrefz|eg5uxxCI=c(hT?_n7mO`)|rYCP0Ec>?*ivwFNZgj zB}6Vm0K{1^&9*rb=fnG+iV`L&hfS&gw;iW9^TGyJKqQ194Dd6+M?ql?gt%0ef3bb( z(dl&NcwvdbEdoHI83>Yf0Q|DiB)>2k&1U(t_Ah?)2cEyWxPbev;(qs*U>@Tdu>PsA zHP3HhuDcm;1#x8%#p36GdE*Mvp8=NQ2>ZB-BCZQrPC{+4vRKdP_@ZCG z$4$32i$l{-ibIY-X*ti$B;*$yF&@VTg3OAj95m&ll3*Mp9G8A+D~hpP9VhFejXYmX zCJt^fVqLp$t#@($bW zk{fPpcFu{y>~c`v;vkKQ0P&NyBVe-<=%%9S2vhC+fX8u^3>z4U3iT$fvydEf++x+H zTp++(#9&`E<%WmUk}gh+6pmHOhe_?WOAu{}H$&rM9L5$dJ9l|j0E{YwTk`@yMpfYq zE<;l8cPv?9G6~qXdUkibu~j_hz~CdV_=<&oHz1~v8c~`FezhvBtC6uDH;Io+t~tc8 z+BYmkLcQ_VMqmF*b6vly;JN9G541k^iWefP=ECvHyJM8ls})vP zqbvLeI3o>Vh5105Mc}O;f7__u9DMfU`QlnKSTHe&aW8=`ih{+Q`9hb3#R-lx^D`XV zsS*fKIEzE{EE7~Fte%GIJc)1eIEhP9wSZ+?IEx18CS*|zlDyJ&CXzFCJ}h;@BOY)b z-vrQ8nN1%a_8J^xpGJnbTx*D|*s5LILP5AReFo1MU99rE&hOr`(*DiweSUv10L9M( zx`V6nYJVy))<5uxkI$gS_I%p#mK1OJ(8deCE&bdl#s9_Ll|WZjo$E8+c}O60fDmK| z5E79=Z6DBAC<5XVT16D?@>O0fS`e14?Gn`bYOB6Zs7Rrx)u)UtpnXg-2vk5B!VC$4 zK<1F)Cb_xuJ@=gRzJ2!1$ss}PL%UW9cW14WefK$MpFMp0|Nn2Fef}Nv3pR(sYi?*H z;@Vw~g?T9`gj%KMTGrpdN-c88!-TwY>t&{`jEh!roS8M*rEndY-V#J;N!FCgu$qrk zm2A42B$!2Q7afV?8oYidXSVTTL{Vy@!Rm0ZB^tXNQ|e=CeK=a~YxBUI0-|K%tP~a) z)Tb!$77Ouky61xL&Yt}C+1~)FBqb&&I7wXGFx?{D@DfWQF0YrQg zd9FG2)Dd>n?YwFtv!I-yh{Rj08VO2XAJ0To8}XSZ2V00EWLEqB9dbqt$xf#Lr4*=Q zZ2eV8EYZb8c!hYnVZr#^#P0}fGtSfM3jx(4>x%?iiBAX~Qi~B{jiG2bEZJggBoYjU zRXcCxVJ>mRB|S)_h2iXiu&1tZm@BgR`*$bzbg7!7AO3E+b!rm=x+b1zyVtVNMw^2ln`s{~ura2p$K zU}G&1XhNh_k(y&M4->2ef>_bXSbFfpr!nvqvzbIQ!&im;O;RKjCA-hJ$&8m_8)C6~ zMZO%9eZ+w+*kD*zqJ(Tlm0%#C$}t;RzRs10lw2Y5zthL{N=YYcL0Ofq^J2-22Gc#n zRd-N@ooBh2xZ@#Wd?{+G-Q76%wZ?V7N;~&)glA&aHL+lba|;qrTmp*3F^nw3aN=57 ziDgX^OSUBsF^rv;V6&@g=rj|~7$uSGr8XbIrmB~^U;*QN9j+xB%NK_o_R$lq`?Ww6fW5g}w4bA*+CSb)^ z1;!~m;!0|gyJgnGhP4V;ywhY7?Cva;i>hiwg>_|y=wXQSWtBK8<;nW0NYoS~eoG@! z)@)Xp7TI@FaO5$3Pgba5IMr=(LSvouHhCpE!ZQ9?w3U;6oE##16cV42c3A=8B%T07 zb5K&FEN^j$BBMy5kf_Laq>4+%4eQaPhe}-N^2A?2Hx1oRVzv87qm!uk1=A?W?)J_2 zb)e;OhvaK(x-3U3?OYol_Hoewr-noxVk;7hg@`{FP7?SQ@G}+aPS&Q9{H2QjDCfwF zguKlmZ<;x)#OEn)X<}qi6%@0;q(yl*E9CM#M|?-HHr7mxIaal?tWz|(Euu@3vlym- z4|lrA_pn;*t|a2Kl!0m`)_(VxT#guTO`^>6rV9roRWnq*Nzz@sRYO~Dd1c-fH}CZFguc?MeScjaW|FnqSf zVoi1%k)y4jjw$iQh;+w0_U1&^O)s%DAMPwGXs@%iT_{PUV>=2ok3SMqq#)1ueVoar zm|TLHwVHK-r^fwBieS-Ji;o{aK79CabeN*hkH`LhuZ`&|d^AW=QPG466V9DG zH+k~puUOiP7cZ7wy!h$5Q-uhAx?D~itv1^Ys_gZVWYemEnwmtBo*Fl9+`RcuRg_mOT(pQ`u5$bNjlQ7suAt*5{vp{@r)q)pHi~3NcrHJJo4~ z(^Js*V38@QDRzg$MEoGIima4ZR$#pLOzDXffw<_A%gf6x7IV*(6tmfajLOQ&s;jG$ zl9LJx3Tci=fmvfVn_)Z>KidYoPgdj;Cr$=B(^2tHpvulolpAG6coW z%gehaqh#q2rmJ*1sfUu{;#edKORKP;pt`Es?sV8~Hj~MO#yoxc^pGJ#va+&tkB2BN z$b=-vP};$R@^qCNiA2yrNeDfX(Q&-y5n3+>vcg$dijZeuIhr<8=>^)ixAK`YXM8>% z;%J%V+8dzFfZ_&5qFYA#zC7Qkiij+8pd~^qP+Z}S+j->8&-C) zjNaJN((z#Mrra~M2{l=0vd-v(H@xzS=4jcgUf{Qqz&?TL0CJ$m$(EnCP(ZydK{#}4p5^q|9LFDWj0 z`st@Jm}x#B2dE~@$^ioh9@w{^EM#mi#3@`A_Kv{~dSSft2GXPUuYP&+om9ltqgc>DRpe`s+xUHhub$q9Zf~&4HAO zcTEJ&XbJ`~Qs&Q}uiy3PqmLrx(BVU57l~*zD?5Aam@)cUNGt%fSMT2c^TGR+$04j- zy$ZLy@x~jJpk0I6oh?2Ksb#g>Hhj1df(L!@%rnpYVD@82j~_E$_Kk0T6B(j?5ic$- zMtu5rzl-?LVfjv%GZ-Qq4PzSV3l=Qs$o%YC!Uq2RTOFnKwYl7`KD~Rt|Ni^6wY4;H z)hbfjH(mvmk_V2ti;8)jT+IJ6;jOh>z51EPc(#4qetiV?Mto5 z4ujuBSe40a(iMuR@hqX8ZRs@AVzrF8Z3Iop%*>$brm!%s5S>mZ>JQFO?Nd!;N`!|x zT{O?ZLk54ke;-D?uGApEt81zurRfwd0xceGR*cjyF?SRdMf%2_cjo8kqYqwv_0{yW zwA*eS{(@mcA*aTI^M~eBF*#=Jn3)gGq_$;xMh3Mt@$?=&dhFi4yTf?kI*6xki$d2_ zR#gogFfcPSlP2b9rQN^(fYI={Mt~+wO-+Re!ST80o?EeE1!R>zd1iHxtyT+$4Wo+U z)?06dfJFRz-}_$w{{5#srMLg|nP-;&=}-Ul;)~FRQ|_KZO%NOh3?TbW!UX*L-oMiu zcYi`)WY+ov@&j6X=#Zfuic9H=5>|>zy?XaDR+-ktq>W7K+3VVNw8>;1I&>&+=n?H3 zk9b>0B#9FQ3=$0ocS0v30t*`AT&JkCPhlj%t>ap3CW%YqeT&O>=9@sx_(*fZDdj$8|`zH`Km%ocTlJe14)X-&?frGXPNjX9c24EMkP$d zpePWiQnown9Sx*q=X4Q0P*qh)fyJm-Q2g`fO374NPR`)GJeY$3O5eVHXFW8F*OWkM z$+>7K0;x&I6)oY&c3pH;etLx}Y;PR(%6TlMlia2$a{K&>e%5#mjq5tD>k#Q6qihF8 zSFc?I6X*2lGvmjPpEYY%W_kwfLDf(!RddP^Z{>EO`6YaqOvI6EWR^-?h^K>apv7%=8sV0pF^p8&mqe|e(q9EGsajA~DBE=%1kns`J zxcQ>dLyZ`t2XE*WUh~R9A--hEo1Vs|C!c)su89+`5Z70B`FU;Dqu(w4=ugmlvUM*n z=oeXN?Ti#h5Mq!U(I~@qne|t`eD<tA_jTyKl_cv1?YZ4r$Fx8x6JIxpODY~UieI~Ct=_7L zY}&M`uC7k6zAh#~W4V3%_TgWRcDk{t@!0WWN41x=^fb)p`ufXc2~A_eX9qt&R&*5c zU%vFqtlrr#zw!z)J$e+E7fqQ=tdk2D%V2T){r-y=FP4;)kp3vUfJihNt*EFts1diO zrY0~raEgY8hFv>%S!^~SYy0-?xMu1-Q~TuhUApX#A8+4&^2CYi>gst<&1-3HUcY`l zKvq*zvwi0d(PCl+0ks7hkQ?|jC1q>J-I#*8tofJb3U(QIW}F1{*qh>}Xk8 z87jW`4~sW%-n8V+B?zQ!4ULBn9S#M9h<|qAv*O}ny|-q}n1SOjUVQQRiQ~u$?C;)b z)6iC%w`{4csi~@}LT;SE`vZa9d-n!|K~Iwhg#>+OwJ9aoWatbuLXp{i){M-(UN2!P?e;#J5v>6#V|Nl-eYW^4m46g=KYjWqum1Kozy00s z(fAFGji2uObi>9CAAb1ZLLcHEPbBITtQmK+o>qzkl!Ez0ms< zLy*>gT)uqmy0ssD^bwwpLati13W{aK2x4hvWo11!d-kd0C$@dO4IPJSvWE^G(q;;X ze_O6p2dVV94cg3>i9yue>5yBO9M zIpyW$L81cqR+|k?3|R=`0AzTYJr0Kx0E&jg1%-vk8J9t$!}RgD`9P1s;hQ|3b?eqb z%M=t8j2SZqN@vyT)pfPCQ>RXKyIdE`%N;H!M3m3#r85pFp+DevI-M{eK*0tL8ic}k z1r|VDT3TwcS~ZTXM#5om2)f8=`0(MVAQc7x*7*zPEp{73BbX7MP8gYHViN=Q{Q318 z*25ObADTaQ>{u9oZ@=>n#L_)?Po=A-oNgDP-+{obg@qVh81Am5B=noNrDedtfwZ(f zpU>$+BS?@mg9i^r^}Cj~QVUj_6*3-33I)i_85$Yo(HQ`#(fLxR(*?9?CfkhH=&IkrA5Z$u z#DB)K5=)c2KbUlT+^Bh}cynuW(FtHB!gXScvT0brqi-Mm*Ny9SDwEqUHvz0f_^PXV zV3mWNG&gxPVtewDM;^&YOaCW5l>dd{HCZBbS5(m>cvXX^skx;k7z#Ffn*Z>--&?Gf ff6{aRPk;dctWJ$v&=T(_00000NkvXXu0mjfGo0V3 literal 0 HcmV?d00001 diff --git a/doc/sphinxext/gh_substitutions.py b/doc/sphinxext/gh_substitutions.py new file mode 100644 index 0000000000..e5540b1866 --- /dev/null +++ b/doc/sphinxext/gh_substitutions.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- + +from docutils.nodes import reference +from docutils.parsers.rst.roles import set_classes + + +# adapted from +# https://github.com/mne-tools/mne-python/blob/main/doc/sphinxext/gh_substitutions.py + + +def _gh_role(name, rawtext, text, lineno, inliner, options={}, content=[]): + """Link to a GitHub issue.""" + try: + # issue/PR mode (issues/PR-num will redirect to pull/PR-num) + int(text) + except ValueError: + # direct link mode + slug = text + else: + slug = 'issues/' + text + text = '#' + text + ref = 'https://github.com/nilearn/nilearn/' + slug + set_classes(options) + node = reference(rawtext, text, refuri=ref, **options) + return [node], [] + + +def setup(app): + app.add_role('gh', _gh_role) + return diff --git a/doc/themes/nilearn/layout.html b/doc/themes/nilearn/layout.html index a6531cafc0..50eff0d8af 100644 --- a/doc/themes/nilearn/layout.html +++ b/doc/themes/nilearn/layout.html @@ -274,16 +274,16 @@

Statistics for NeuroImaging in Python

News

diff --git a/doc/whats_new.rst b/doc/whats_new.rst deleted file mode 100644 index 748004baf5..0000000000 --- a/doc/whats_new.rst +++ /dev/null @@ -1,2408 +0,0 @@ -0.8.2.dev -========= - -NEW ---- - -- **Support for Python 3.6 is deprecated and will be removed in release 0.10.** - Users with a Python 3.6 environment will be warned at their first Nilearn - import and encouraged to update to more recent versions of Python. -- Masker objects like :class:`~nilearn.maskers.NiftiMasker` now belong to the - new module :mod:`nilearn.maskers`. The old import style, through the module - ``input_data``, still works but has been deprecated. - (See PR `#3065 `_). -- New module :mod:`nilearn.interfaces` to implement loading and saving utilities - with various interfaces (fmriprep, bids...). - (See PR `#3061 `_). -- New submodule :mod:`nilearn.interfaces.fmriprep` to implement loading utilities - for :term:`fMRIPrep`. - (See PR `#3061 `_). -- New function :func:`nilearn.interfaces.fmriprep.load_confounds` to load confound - variables easily from :term:`fMRIPrep` outputs. - (See PR `#2946 `_). -- New function :func:`nilearn.interfaces.fmriprep.load_confounds_strategy` to load - confound variables from :term:`fMRIPrep` outputs using four preset strategies: - ``simple``, ``scrubbing``, ``compcor``, and ``ica_aroma``. - (See PR `#3016 `_). -- New submodule :mod:`nilearn.interfaces.bids` to implement loading utilities - for :term:`BIDS` datasets. - (See PR `#3126 `_). -- New function :func:`nilearn.interfaces.bids.get_bids_files` to select files - easily from :term:`BIDS` datasets. - (See PR `#3126 `_). -- New function :func:`nilearn.interfaces.bids.parse_bids_filename` to identify - subparts of :term:`BIDS` filenames. - (See PR `#3126 `_). -- New submodule :mod:`nilearn.interfaces.fsl` to implement loading utilities - for FSL outputs. - (See PR `#3126 `_). -- New function :func:`nilearn.interfaces.fsl.get_design_from_fslmat` to load - design matrices from FSL files. - (See PR `#3126 `_). -- Surface plotting functions like :func:`nilearn.plotting.plot_surf_stat_map` - now have an `engine` parameter, defaulting to "matplotlib", but which can be - set to "plotly". If plotly and kaleido are installed, this will generate an - interactive plot of the surface map using plotly instead of matplotlib. - Note that this functionality is still experimental, and that some capabilities - supported by our matplotlib engine are not yet supported by the plotly engine. - (See PR `#2902 `_). -- When using the `plotly` engine, surface plotting functions derived from - :func:`~nilearn.plotting.plot_surf` return a new display object, a - :class:`~nilearn.plotting.displays.PlotlySurfaceFigure`, which provides a - similar interface to the :class:`~matplotlib.figure.Figure` returned with the - `matplotlib` engine. - (See PR `#3036 `_). -- :class:`~nilearn.maskers.NiftiMapsMasker` can now generate HTML reports in the same - way as :class:`~nilearn.maskers.NiftiMasker` and - :class:`~nilearn.maskers.NiftiLabelsMasker`. The report enables the users to browse - through the spatial maps with a previous and next button. The users can filter the maps - they wish to display by passing an integer, or a list of integers to - :meth:`~nilearn.maskers.NiftiMapsMasker.generate_report`. -- New class :class:`nilearn.regions.HierarchicalKMeans` which yields more - balanced clusters than `KMeans`. It is also callable through - :class:`nilearn.regions.Parcellations` using `method`=`hierarchical_kmeans` - - -Fixes ------ - -- When a label image with non integer values was provided to the - :class:`nilearn.maskers.NiftiLabelsMasker`, its `generate_report` - method was raising an ``IndexError``. - (See issue `#3007 `_ and - fix `#3009 `_). -- :func:`nilearn.plotting.plot_markers` did not work when the `display_mode` - parameter included `l` and `r` and the parameter `node_size` was provided - as an array. - (See issue `#3012 `_) and fix - `#3013 `_). -- :meth:`nilearn.glm.first_level.FirstLevelModel.generate_report` threw a `TypeError` - when `FirstLevelModel` was instantiated with `mask_img` - being a :class:`~nilearn.maskers.NiftiMasker`. - :func:`nilearn.reporting.make_glm_report` was fixed accordingly. - (See issue `#3034 `_) and fix - `#3035 `_). -- Function :func:`~nilearn.plotting.find_parcellation_cut_coords` now returns - coordinates and labels having the same order as the one of the input labels - index (See PR `#3078 `_). -- Convert reference in `nilearn/regions/region_extractor.py` to use footcite / footbibliography. - (See issue `#2787 `_ and PR `#3111 `_). -- Fixed Hommel value computation in `nilearn/glm/thresholding.py` used in the - `cluster_level_inference` function. See PR `#3109 `_ -- Computation of Benjamini-Hocheberg threshold fixed in `nilearn/glm/thresholding.py` function (see issue `#2879 `_ and PR `#3137 `_) -- Attribute `scaling_axis` of :class:`~nilearn.glm.first_level.FirstLevelModel` has - been deprecated and will be removed in 0.11.0. When scaling is performed, the - attribute `signal_scaling` is used to define the axis instead. - (See issue `#3134 `_ and PR - `#3135 `_). - -Enhancements ------------- - -- :func:`nilearn.image.threshold_img` accepts new parameters `cluster_threshold` - and `two_sided`. - `cluster_threshold` applies a cluster-size threshold (in voxels). - `two_sided`, which is `True` by default, separately thresholds both positive - and negative values in the map, as was done previously. - When `two_sided` is `False`, only values greater than or equal to the threshold - are retained. -- :func:`nilearn.signal.clean` raises a warning when the user sets - parameters `detrend` and `standardize_confound` to False. - The user is suggested to set one of - those options to `True`, or standardize/demean the confounds before using the - function. -- The :doc:`contributing documentation` and - :doc:`maintenance` pages were improved, especially towards ways - of contributing to the project which do not require to write code. - The roles of the :ref:`triage` were defined more clearly with sections on issue - :ref:`issue_labels` and issue :ref:`closing_policy`. - (See PR `#3010 `_). -- It is now possible to provide custom :term:`HRF` models to - :class:`nilearn.glm.first_level.FirstLevelModel`. The custom model should be - defined as a function, or a list of functions, implementing the same API as - Nilearn's usual models (see :func:`nilearn.glm.first_level.spm_hrf` for - example). The example - :ref:`sphx_glr_auto_examples_04_glm_first_level_plot_hrf.py` was - also modified to demo how to define custom :term:`HRF` models. - (See issue `#2940 `_). -- :class:`nilearn.maskers.NiftiLabelsMasker` now gives a warning when some - labels are removed from the label image at transform time due to resampling - of the label image to the data image. -- Function :func:`~nilearn.glm.second_level.non_parametric_inference` now accepts - :class:`~pandas.DataFrame` as possible values for its ``second_level_input`` - parameter. Note that a new parameter ``first_level_contrast`` has been added - to this function to enable this feature. - (See PR `#3042 `_). -- Tests from `nilearn/plotting/tests/test_img_plotting.py` have been refactored - and reorganized in separate files in new folder - `nilearn/plotting/tests/test_img_plotting/`. - (See PR `#3015 `_) -- Once a :class:`~nilearn.glm.second_level.SecondLevelModel` has been fitted and - contrasts have been computed, it is now possible to access the ``residuals``, - ``predicted``, and ``r_square`` model attributes like it was already possible - for :class:`~nilearn.glm.first_level.FirstLevelModel`. - (See FR `#3027 `_ - and PR `#3033 `_) -- Importing :mod:`nilearn.plotting` will now raise a warning if the matplotlib - backend has been changed from its original value, instead of silently modifying - it. -- Function :func:`~nilearn.plotting.plot_img` and deriving functions like - :func:`~nilearn.plotting.plot_anat`, :func:`~nilearn.plotting.plot_stat_map`, or - :func:`~nilearn.plotting.plot_epi` now accept an optional argument - ``cbar_tick_format`` to specify how numbers should be displayed on the colorbar. - This is consistent with the API of surface plotting functions (see release 0.7.1). - The default format is scientific notation. - -Changes -------- - -- Nibabel 2.x is no longer supported. Please consider upgrading to Nibabel >= 3.0. - (See PR `#3106 `_). -- Deprecated function ``nilearn.datasets.fetch_cobre`` has been removed. - (See PR `#3081 `_). -- Deprecated function ``nilearn.plotting.plot_connectome_strength`` has been removed. - (See PR `#3082 `_). -- Deprecated function ``nilearn.masking.compute_gray_matter_mask`` has been removed. - (See PR `#3090 `_). -- Deprecated parameter ``sessions`` of function :func:`~nilearn.signal.clean` - has been removed. Use ``runs`` instead. - (See PR `#3093 `_). -- Deprecated parameters ``sessions`` and ``sample_mask`` of - :class:`~nilearn.maskers.NiftiMasker` have been removed. Please use ``runs`` instead of - ``sessions``, and provide a ``sample_mask`` through - :meth:`~nilearn.maskers.NiftiMasker.transform`. - (See PR `#3133 `_). -- :func:`nilearn.glm.first_level.compute_regressor` will now raise an exception if - parameter `cond_id` is not a string which could be used to name a python variable. - For instance, number strings (ex: "1") will no longer be accepted as valid condition names. - In particular, this will also impact - :func:`nilearn.glm.first_level.make_first_level_design_matrix` and - :class:`nilearn.glm.first_level.FirstLevelModel`, for which proper condition names - will also be needed (see PR `#3025 `_). -- Replace parameter `sessions` with `runs` in :func:`nilearn.image.clean_img` as this - replacement was already made for :func:`nilearn.signal.clean` in - `#2821 `_ in order to match BIDS - semantics. The use of `sessions` in :func:`nilearn.image.clean_img` is deprecated and - will be removed in 0.10.0. -- Display objects have been reorganized. For example, Slicers (like the - :class:`~nilearn.plotting.displays.OrthoSlicer`) are all in file - `nilearn/plotting/displays/_slicers.py`, and Projectors (like the - :class:`~nilearn.plotting.displays.OrthoProjector`) are all in file - `nilearn/plotting/displays/_projectors.py`. All display objects have been added to - the public API, and examples have been improved to show how to use these objects - to customize figures obtained with plotting functions. - (See PR `#3073 `_). -- Descriptions of datasets retrieved with fetchers from :mod:`nilearn.datasets` are - now python strings rather than `bytes`. Therefore, decoding the descriptions is no - longer necessary. - -.. _v0.8.1: - -0.8.1 -===== -**Released September 2021** - -HIGHLIGHTS ----------- - -- New atlas fetcher - :func:`nilearn.datasets.fetch_atlas_juelich` to download Juelich atlas from FSL. -- New grey and white-matter template and mask loading functions: - :func:`nilearn.datasets.load_mni152_gm_template`, - :func:`nilearn.datasets.load_mni152_wm_template`, - :func:`nilearn.datasets.load_mni152_gm_mask`, and - :func:`nilearn.datasets.load_mni152_wm_mask` -- :ref:`development_process` has been reworked. It now provides insights on - nilearn organization as a project as well as more explicit - :ref:`contribution_guidelines`. -- :func:`nilearn.image.binarize_img` binarizes images into 0 and 1. - -NEW ---- -- New atlas fetcher - :func:`nilearn.datasets.fetch_atlas_juelich` to download Juelich atlas from FSL. -- :ref:`development_process` has been reworked. It now provides insights on - nilearn organization as a project as well as more explicit - :ref:`contribution_guidelines`. -- :func:`nilearn.datasets.load_mni152_gm_template` takes the skullstripped - 1mm-resolution version of the grey-matter MNI152 template and re-samples it - using a different resolution, if specified. -- :func:`nilearn.datasets.load_mni152_wm_template` takes the skullstripped - 1mm-resolution version of the white-matter MNI152 template and re-samples it - using a different resolution, if specified. -- :func:`nilearn.datasets.load_mni152_gm_mask` loads mask from the grey-matter - MNI152 template. -- :func:`nilearn.datasets.load_mni152_wm_mask` loads mask from the white-matter - MNI152 template. -- :func:`nilearn.image.binarize_img` binarizes images into 0 and 1. -- :class:`nilearn.maskers.NiftiMasker`, - :class:`nilearn.maskers.MultiNiftiMasker`, and objects relying on such maskers - (:class:`nilearn.decoding.Decoder` or :class:`nilearn.decomposition.CanICA` - for example) can now use new options for the argument `mask_strategy`: - `whole-brain-template` for whole-brain template (same as previous option - `template`), `gm-template` for grey-matter template, and `wm-template` - for white-matter template. - -Fixes ------ - -- :func:`nilearn.masking.compute_multi_brain_mask` has replaced - nilearn.masking.compute_multi_grey_matter_mask. A mask parameter has been added; - it accepts three types of masks---i.e. whole-brain, grey-matter and - white-matter---following the enhancements made in the function - :func:`nilearn.masking.compute_brain_mask` in this release. -- Fix colorbar of :func:`nilearn.plotting.view_img` which was not visible for some - combinations of `black_bg` and `bg_img` parameters. - (See issue `#2874 `_). -- Fix missing title with :func:`nilearn.plotting.plot_surf` and - deriving functions. - (See issue `#2941 `_). - -Enhancements ------------- - -- :func:`nilearn.datasets.load_mni152_template` resamples now the template to - a preset resolution different from the resolution of the original template, - i.e. 1mm. The default resolution is 2mm, which means that the new template is - resampled to the resolution of the old template. Nevertheless, the shape of - the template changed from (91, 109, 91) to (99, 117, 95); the affine also - changed from array([[-2., 0., 0., 90.], [0., 2., 0., -126.], - [0., 0., 2., -72.], [0., 0., 0., 1.]]) to array([[1., 0., 0., -98.], - [0., 1., 0., -134.], [0., 0., 1., -72.], [0., 0., 0., 1.]]). Additionally, - the new template has also been rescaled; whereas the old one varied between - 0 and 8339, the new one varies between 0 and 255. -- :func:`nilearn.datasets.load_mni152_brain_mask` accepts now the parameter - resolution, which will set the resolution of the template used for the - masking. -- :func:`nilearn.masking.compute_brain_mask` accepts now as input the - whole-brain, 1mm-resolution, MNI152 T1 template instead of the averaged, - whole-brain, 2mm-resolution MNI152 T1 template; it also accepts as input the - grey-matter and white-matter ICBM152 1mm-resolution templates dated from 2009. -- Common parts of docstrings across Nilearn can now be filled automatically using - the decorator `nilearn._utils.fill_doc`. This can be applied to common function - parameters or common lists of options for example. The standard parts are defined - in a single location (`nilearn._utils.docs.py`) which makes them easier to - maintain and update. (See `#2875 `_) -- The `data_dir` argument can now be either a `pathlib.Path` or a string. This - extension affects datasets and atlas fetchers. - -Changes -------- - -- The version of the script `jquery.min.js` was bumped from 3.3.1 to 3.6.0 due - to potential vulnerability issues with versions < 3.5.0. - -.. _v0.8.0: - -0.8.0 -===== - -**Released June 2021** - -HIGHLIGHTS ----------- - -.. warning:: - - | **Python 3.5 is no longer supported. We recommend upgrading to Python 3.8.** - | - | **Support for Nibabel 2.x is deprecated and will be removed in the 0.9 release.** - | Users with a version of Nibabel < 3.0 will be warned at their first Nilearn import. - | - | **Minimum supported versions of packages have been bumped up:** - | - Numpy -- v1.16 - | - SciPy -- v1.2 - | - Scikit-learn -- v0.21 - | - Nibabel -- v2.5 - | - Pandas -- v0.24 - -- :class:`nilearn.maskers.NiftiLabelsMasker` can now generate HTML reports in the same - way as :class:`nilearn.maskers.NiftiMasker`. -- :func:`nilearn.signal.clean` accepts new parameter `sample_mask`. - shape: (number of scans - number of volumes removed, ) -- All inherent classes of `nilearn.maskers.BaseMasker` can use parameter `sample_mask` - for sub-sample masking. -- Fetcher :func:`nilearn.datasets.fetch_surf_fsaverage` now accepts `fsaverage3`, - `fsaverage4` and `fsaverage6` as values for parameter `mesh`, so that - all resolutions of fsaverage from 3 to 7 are now available. -- Fetcher :func:`nilearn.datasets.fetch_surf_fsaverage` now provides attributes - `{area, curv, sphere, thick}_{left, right}` for all fsaverage resolutions. -- :class:`nilearn.glm.first_level.run_glm` now allows auto regressive noise - models of order greater than one. - -NEW ---- - -- :func:`nilearn.signal.clean` accepts new parameter `sample_mask`. - shape: (number of scans - number of volumes removed, ) - Masks the niimgs along time/fourth dimension to perform scrubbing (remove - volumes with high motion) and/or non-steady-state volumes. Masking is applied - before signal cleaning. -- All inherent classes of `nilearn.maskers.BaseMasker` can use - parameter `sample_mask` for sub-sample masking. -- :class:`nilearn.maskers.NiftiLabelsMasker` can now generate HTML reports in the same - way as :class:`nilearn.maskers.NiftiMasker`. The report shows the regions defined by - the provided label image and provide summary statistics on each region (name, volume...). - If a functional image was provided to fit, the middle image is plotted with the regions - overlaid as contours. Finally, if a mask is provided, its contours are shown in green. - -Fixes ------ - -- Convert references in signal.py, atlas.py, func.py, neurovault.py, and struct.py - to use footcite / footbibliography. -- Fix detrending and temporal filtering order for confounders - in :func:`nilearn.signal.clean`, so that these operations are applied - in the same order as for the signals, i.e., first detrending and - then temporal filtering (https://github.com/nilearn/nilearn/issues/2730). -- Fix number of attributes returned by the - `nilearn.glm.first_level.FirstLevelModel._get_voxelwise_model_attribute` method - in the first level model. It used to return only the first attribute, and now returns - as many attributes as design matrices. -- Plotting functions that show a stack of slices from a 3D image (e.g. - :func:`nilearn.plotting.plot_stat_map`) will now plot the slices in the user - specified order, rather than automatically sorting into ascending order - (https://github.com/nilearn/nilearn/issues/1155). -- Fix the axes zoom on plot_img_on_surf function so brain would not be cutoff, and - edited function so less white space surrounds brain views & smaller colorbar using - gridspec (https://github.com/nilearn/nilearn/pull/2798). -- Fix inconsistency in prediction values of Dummy Classifier for Decoder - object (https://github.com/nilearn/nilearn/issues/2767). - -Enhancements ------------- - -- :func:`nilearn.plotting.view_markers` now accepts an optional argument `marker_labels` - to provide labels to each marker. -- :func:`nilearn.plotting.plot_surf` now accepts new values for `avg_method` argument, - such as `min`, `max`, or even a custom python function to compute the value displayed - for each face of the plotted mesh. -- :func:`nilearn.plotting.view_img_on_surf` can now optionally pass through - parameters to :func:`nilearn.surface.vol_to_surf` using the - `vol_to_surf_kwargs` argument. One application is better HTML visualization of atlases. - (https://nilearn.github.io/auto_examples/01_plotting/plot_3d_map_to_surface_projection.html) -- :func:`nilearn.plotting.view_connectome` now accepts an optional argument `node_color` - to provide a single color for all nodes, or one color per node. - It defaults to `auto` which colors markers according to the viridis colormap. -- Refactor :func:`nilearn.signal.clean` to clarify the data flow. - Replace `sessions` with `runs` to matching BIDS semantics and deprecate `sessions` in 0.9.0. - Add argument `filter` and allow a selection of signal filtering strategies: - * "butterwoth" (butterworth filter) - * "cosine" (discrete cosine transformation) - * `False` (no filtering) -- Change the default strategy for Dummy Classifier from 'prior' to - 'stratified' (https://github.com/nilearn/nilearn/pull/2826/). -- :class:`nilearn.glm.first_level.run_glm` now allows auto regressive noise - models of order greater than one. -- Moves parameter `sample_mask` from :class:`nilearn.maskers.NiftiMasker` - to method `transform` in base class `nilearn.maskers.BaseMasker`. -- Fetcher :func:`nilearn.datasets.fetch_surf_fsaverage` now accepts - `fsaverage3`, `fsaverage4` and `fsaverage6` as values for parameter `mesh`, so that - all resolutions of fsaverage from 3 to 7 are now available. -- Fetcher :func:`nilearn.datasets.fetch_surf_fsaverage` now provides - attributes `{area, curv, sphere, thick}_{left, right}` for all fsaverage - resolutions. - -Changes -------- - -- Python 3.5 is no longer supported. We recommend upgrading to Python 3.7. -- Support for Nibabel 2.x is now deprecated and will be removed - in the 0.9 release. Users with a version of Nibabel < 3.0 will - be warned at their first Nilearn import. -- Minimum supported versions of packages have been bumped up: - - * Numpy -- v1.16 - * SciPy -- v1.2 - * Scikit-learn -- v0.21 - * Nibabel -- v2.5 - * Pandas -- v0.24 - -- Function sym_to_vec from :mod:`nilearn.connectome` was deprecated since release 0.4 and - has been removed. -- Fetcher `nilearn.datasets.fetch_nyu_rest` is deprecated since release 0.6.2 and - has been removed. -- :class:`nilearn.maskers.NiftiMasker` replaces `sessions` with `runs` and - deprecates attribute `sessions` in 0.9.0. Match the relevant change in - :func:`nilearn.signal.clean`. - -.. _v0.7.1: - -0.7.1 -===== - -**Released March 2021** - -HIGHLIGHTS ----------- - -- New atlas fetcher - :func:`nilearn.datasets.fetch_atlas_difumo` to download *Dictionaries of Functional Modes*, - or “DiFuMo”, that can serve as atlases to extract functional signals with different - dimensionalities (64, 128, 256, 512, and 1024). These modes are optimized to represent well - raw BOLD timeseries, over a with range of experimental conditions. - -- :class:`nilearn.decoding.Decoder` and :class:`nilearn.decoding.DecoderRegressor` - is now implemented with random predictions to estimate a chance level. - -- The functions :func:`nilearn.plotting.plot_epi`, :func:`nilearn.plotting.plot_roi`, - :func:`nilearn.plotting.plot_stat_map`, :func:`nilearn.plotting.plot_prob_atlas` - is now implemented with new display mode Mosaic. That implies plotting 3D maps - in multiple columns and rows in a single axes. - -- :func:`nilearn.plotting.plot_carpet` now supports discrete atlases. - When an atlas is used, a colorbar is added to the figure, - optionally with labels corresponding to the different values in the atlas. - -NEW ---- - -- New atlas fetcher - :func:`nilearn.datasets.fetch_atlas_difumo` to download *Dictionaries of Functional Modes*, - or “DiFuMo”, that can serve as atlases to extract functional signals with different - dimensionalities (64, 128, 256, 512, and 1024). These modes are optimized to represent well - raw BOLD timeseries, over a with range of experimental conditions. - -- :func:`nilearn.glm.Contrast.one_minus_pvalue` was added to ensure numerical - stability of p-value estimation. It computes 1 - p-value using the Cumulative - Distribution Function in the same way as `nilearn.glm.Contrast.p_value` - computes the p-value using the Survival Function. - -Fixes ------ - -- Fix altered, non-zero baseline in design matrices where multiple events in the same condition - end at the same time (https://github.com/nilearn/nilearn/issues/2674). - -- Fix testing issues on ARM machine. - -Enhancements ------------- - -- :class:`nilearn.decoding.Decoder` and :class:`nilearn.decoding.DecoderRegressor` - is now implemented with random predictions to estimate a chance level. - -- :class:`nilearn.decoding.Decoder`, :class:`nilearn.decoding.DecoderRegressor`, - :class:`nilearn.decoding.FREMRegressor`, and :class:`nilearn.decoding.FREMClassifier` - now override the `score` method to use whatever scoring strategy was defined through - the `scoring` attribute instead of the sklearn default. - If the `scoring` attribute of the decoder is set to None, the scoring strategy - will default to accuracy for classifiers and to r2 score for regressors. - -- :func:`nilearn.plotting.plot_surf` and deriving functions like :func:`nilearn.plotting.plot_surf_roi` - now accept an optional argument `cbar_tick_format` to specify how numbers should be displayed on the - colorbar of surface plots. The default format is scientific notation except for :func:`nilearn.plotting.plot_surf_roi` - for which it is set as integers. - -- :func:`nilearn.plotting.plot_carpet` now supports discrete atlases. - When an atlas is used, a colorbar is added to the figure, - optionally with labels corresponding to the different values in the atlas. - -- :class:`nilearn.maskers.NiftiMasker`, :class:`nilearn.maskers.NiftiLabelsMasker`, - :class:`nilearn.maskers.MultiNiftiMasker`, :class:`nilearn.maskers.NiftiMapsMasker`, - and :class:`nilearn.maskers.NiftiSpheresMasker` can now compute high variance confounds - on the images provided to `transform` and regress them out automatically. This behaviour is - controlled through the `high_variance_confounds` boolean parameter of these maskers which - default to False. - -- :class:`nilearn.maskers.NiftiLabelsMasker` now automatically replaces NaNs in input data - with zeros, to match the behavior of other maskers. - -- :func:`nilearn.datasets.fetch_neurovault` now implements a `resample` boolean argument to either - perform a fixed resampling during download or keep original images. This can be handy to reduce disk usage. - By default, the downloaded images are not resampled. - -- The functions :func:`nilearn.plotting.plot_epi`, :func:`nilearn.plotting.plot_roi`, - :func:`nilearn.plotting.plot_stat_map`, :func:`nilearn.plotting.plot_prob_atlas` - is now implemented with new display mode Mosaic. That implies plotting 3D maps - in multiple columns and rows in a single axes. - -- `psc` standardization option of :func:`nilearn.signal.clean` now allows time series with negative mean values. - -- :func:`nilearn.reporting.make_glm_report` and - :func:`nilearn.reporting.get_clusters_table` have a new argument, - "two_sided", which allows for two-sided thresholding, which is disabled by default. - -.. _v0.7.0: - -0.7.0 -===== - -**Released November 2020** - -HIGHLIGHTS ----------- - -- Nilearn now includes the functionality of `Nistats `_ as :mod:`nilearn.glm`. This module is experimental, hence subject to change in any future release. - :ref:`Here's a guide to replacing Nistats imports to work in Nilearn. ` -- New decoder object - :class:`nilearn.decoding.Decoder` (for classification) and - :class:`nilearn.decoding.DecoderRegressor` (for regression) implement a model - selection scheme that averages the best models within a cross validation loop. -- New FREM object - :class:`nilearn.decoding.FREMClassifier` (for classification) and - :class:`nilearn.decoding.FREMRegressor` (for regression) extend the decoder - object with one fast clustering step at the beginning and aggregates a high number of estimators trained on various splits of the training set. - -- New plotting functions: - - * :func:`nilearn.plotting.plot_event` to visualize events file. - * :func:`nilearn.plotting.plot_roi` can now plot ROIs in contours with `view_type` argument. - * :func:`nilearn.plotting.plot_carpet` generates a "carpet plot" (also known - as a "Power plot" or a "grayplot") - * :func:`nilearn.plotting.plot_img_on_surf` generates multiple views of - :func:`nilearn.plotting.plot_surf_stat_map` in a single figure. - * :func:`nilearn.plotting.plot_markers` shows network nodes (markers) on a glass - brain template - * :func:`nilearn.plotting.plot_surf_contours` plots the contours of regions of - interest on the surface - -.. warning:: - - Minimum required version of Joblib is now 0.12. - - -NEW ---- -- Nilearn now includes the functionality of `Nistats `_. - :ref:`Here's a guide to replacing Nistats imports to work in Nilearn. ` -- New decoder object - :class:`nilearn.decoding.Decoder` (for classification) and - :class:`nilearn.decoding.DecoderRegressor` (for regression) implement a model - selection scheme that averages the best models within a cross validation loop. - The resulting average model is the one used as a classifier or a regressor. - These two objects also leverage the `NiftiMaskers` to provide a direct - interface with the Nifti files on disk. -- New FREM object - :class:`nilearn.decoding.FREMClassifier` (for classification) and - :class:`nilearn.decoding.FREMRegressor` (for regression) extend the decoder - object pipeline with one fast clustering step at the beginning (yielding an - implicit spatial regularization) and aggregates a high number of estimators - trained on various splits of the training set. This returns a state-of-the-art - decoding pipeline at a low computational cost. - These two objects also leverage the `NiftiMaskers` to provide a direct - interface with the Nifti files on disk. -- Plot events file - Use :func:`nilearn.plotting.plot_event` to visualize events file. - The function accepts the :term:`BIDS` events file read using `pandas` - utilities. -- Plotting function :func:`nilearn.plotting.plot_roi` can now plot ROIs - in contours with `view_type` argument. -- New plotting function - :func:`nilearn.plotting.plot_carpet` generates a "carpet plot" (also known - as a "Power plot" or a "grayplot"), for visualizing global patterns in - 4D functional data over time. -- New plotting function - :func:`nilearn.plotting.plot_img_on_surf` generates multiple views of - :func:`nilearn.plotting.plot_surf_stat_map` in a single figure. -- :func:`nilearn.plotting.plot_markers` shows network nodes (markers) on a glass - brain template and color code them according to provided nodal measure (i.e. - connection strength). This function will replace function - ``nilearn.plotting.plot_connectome_strength``. -- New plotting function - :func:`nilearn.plotting.plot_surf_contours` plots the contours of regions of - interest on the surface, optionally overlaid on top of a statistical map. -- The position annotation on the plot methods now implements the `decimals` option - to enable annotation of a slice coordinate position with the float. -- New example in - :ref:`sphx_glr_auto_examples_02_decoding_plot_haxby_searchlight_surface.py` - to demo how to do cortical surface-based searchlight decoding with Nilearn. -- confounds or additional regressors for design matrix can be specified as - numpy arrays or pandas DataFrames interchangeably -- The decomposition estimators will now accept argument `per_component` - with `score` method to explain the variance for each component. - - -Fixes ------ - -- :class:`nilearn.maskers.NiftiLabelsMasker` no longer ignores its `mask_img` -- :func:`nilearn.masking.compute_brain_mask` has replaced - nilearn.masking.compute_gray_matter_mask. Features remained the same but - some corrections regarding its description were made in the docstring. -- the default background (MNI template) in plotting functions now has the - correct orientation; before left and right were inverted. -- first level modelling can deal with regressors - having multiple events which share onsets or offsets. - Previously, such cases could lead to an erroneous baseline shift. -- :func:`nilearn.mass_univariate.permuted_ols` no longer returns transposed - t-statistic arrays when no permutations are performed. -- Fix decomposition estimators returning explained variance score as 0. - based on all components i.e., when per_component=False. -- Fix readme file of the Destrieux 2009 atlas. - - -Changes -------- - -- Function ``nilearn.datasets.fetch_cobre`` has been deprecated and will be - removed in release 0.9 . -- Function ``nilearn.plotting.plot_connectome_strength`` has been deprecated and will - be removed in release 0.9 . - -- :class:`nilearn.connectome.ConnectivityMeasure` can now remove - confounds in its transform step. -- :func:`nilearn.surface.vol_to_surf` can now sample between two nested surfaces - (eg white matter and pial surfaces) at specific cortical depths -- :func:`nilearn.datasets.fetch_surf_fsaverage` now also downloads white matter - surfaces. - - -.. _v0.6.2: - -0.6.2 -====== - -ENHANCEMENTS ------------- - -- Generated documentation now includes Binder links to launch examples interactively - in the browser -- :class:`nilearn.maskers.NiftiSpheresMasker` now has an inverse transform, - projecting spheres to the corresponding mask_img. - -Fixes ------ - -- More robust matplotlib backend selection -- Typo in example fixed - -Changes -------- - -- Atlas `nilearn.datasets.fetch_nyu_rest` has been deprecated and will be removed in Nilearn 0.8.0 . - -Contributors ------------- - -The following people contributed to this release:: - - Elizabeth DuPre - Franz Liem - Gael Varoquaux - Jon Haitz Legarreta Gorroño - Joshua Teves - Kshitij Chawla (kchawla-pi) - Zvi Baratz - Simon R. Steinkamp - - -.. _v0.6.1: - -0.6.1 -===== - -ENHANCEMENTS ------------- - -- html pages use the user-provided plot title, if any, as their title - -Fixes ------ - -- Fetchers for developmental_fmri and localizer datasets resolve URLs correctly. - -Contributors ------------- - -The following people contributed to this release:: - - Elizabeth DuPre - Jerome Dockes - Kshitij Chawla (kchawla-pi) - -0.6.0 -===== - -**Released December 2019** - -HIGHLIGHTS ----------- - -.. warning:: - - | **Python2 and 3.4 are no longer supported. We recommend upgrading to Python 3.6 minimum.** - | - | **Support for Python3.5 will be removed in the 0.7.x release.** - | Users with a Python3.5 environment will be warned at their first Nilearn import. - | - | **joblib is now a dependency** - | - | **Minimum supported versions of packages have been bumped up.** - | - Matplotlib -- v2.0 - | - Scikit-learn -- v0.19 - | - Scipy -- v0.19 - -NEW ---- - -- A new method for :class:`nilearn.maskers.NiftiMasker` instances - for generating reports viewable in a web browser, Jupyter Notebook, or VSCode. - -- A new function :func:`nilearn.image.get_data` to replace the deprecated - nibabel method `Nifti1Image.get_data`. Now use `nilearn.image.get_data(img)` - rather than `img.get_data()`. This is because Nibabel is removing the - `get_data` method. You may also consider using the Nibabel - `Nifti1Image.get_fdata`, which returns the data cast to floating-point. - See https://github.com/nipy/nibabel/wiki/BIAP8 . - As a benefit, the `get_data` function works on niimg-like objects such as - filenames (see http://nilearn.github.io/manipulating_images/input_output.html ). - -- Parcellation method ReNA: Fast agglomerative clustering based on recursive - nearest neighbor grouping. - Yields very fast & accurate models, without creation of giant - clusters. - :class:`nilearn.regions.ReNA` -- Plot connectome strength - Use function ``nilearn.plotting.plot_connectome_strength`` to plot the strength of a - connectome on a glass brain. Strength is absolute sum of the edges at a node. -- Optimization to image resampling -- New brain development fMRI dataset fetcher - :func:`nilearn.datasets.fetch_development_fmri` can be used to download - movie-watching data in children and adults. A light-weight dataset - implemented for teaching and usage in the examples. All the connectivity examples - are changed from ADHD to brain development fmri dataset. - -ENHANCEMENTS ------------- - -- :func:`nilearn.plotting.view_img_on_surf`, :func:`nilearn.plotting.view_surf` - and :func:`nilearn.plotting.view_connectome` can display a title, and allow - disabling the colorbar, and setting its height and the fontsize of its ticklabels. - -- Rework of the standardize-options of :func:`nilearn.signal.clean` and the various Maskers - in `nilearn.maskers`. You can now set `standardize` to `zscore` or `psc`. `psc` stands - for `Percent Signal Change`, which can be a meaningful metric for BOLD. - -- Class :class:`nilearn.maskers.NiftiLabelsMasker` now accepts an optional - `strategy` parameter which allows it to change the function used to reduce - values within each labelled ROI. Available functions include mean, median, - minimum, maximum, standard_deviation and variance. - This change is also introduced in :func:`nilearn.regions.img_to_signals_labels`. - -- :func:`nilearn.plotting.view_surf` now accepts surface data provided as a file - path. - -CHANGES -------- - -- :func:`nilearn.plotting.plot_img` now has explicit keyword arguments `bg_img`, - `vmin` and `vmax` to control the background image and the bounds of the - colormap. These arguments were already accepted in `kwargs` but not documented - before. - -FIXES ------ - -- :class:`nilearn.maskers.NiftiLabelsMasker` no longer truncates region means to their integral part - when input images are of integer type. -- The arg `version='det'` in :func:`nilearn.datasets.fetch_atlas_pauli_2017` now works as expected. -- `pip install nilearn` now installs the necessary dependencies. - -**Lots of other fixes in documentation and examples.** More detailed change list follows: - -0.6.0rc -NEW ---- -.. warning:: - - - :func:`nilearn.plotting.view_connectome` no longer accepts old parameter names. - Instead of `coords`, `threshold`, `cmap`, and `marker_size`, - use `node_coords`, `edge_threshold`, `edge_cmap`, `node_size` respectively. - - - :func:`nilearn.plotting.view_markers` no longer accepts old parameter names. - Instead of `coord` and `color`, use `marker_coords` and `marker_color` respectively. - - -- **Support for Python3.5 will be removed in the 0.7.x release.** - Users with a Python3.5 environment will be warned - at their first Nilearn import. - -Changes -------- - -- Add a warning to :class:`nilearn.regions.Parcellations` - if the generated number of parcels does not match the requested number - of parcels. -- Class :class:`nilearn.maskers.NiftiLabelsMasker` now accepts an optional - `strategy` parameter which allows it to change the function used to reduce - values within each labelled ROI. Available functions include mean, median, - minimum, maximum, standard_deviation and variance. - This change is also introduced in :func:`nilearn.regions.img_to_signals_labels`. - -Fixes ------ - -- :class:`nilearn.maskers.NiftiLabelsMasker` no longer truncates region means to their integral part - when input images are of integer type. -- :func: `nilearn.image.smooth_image` no longer fails if `fwhm` is a `numpy.ndarray`. -- `pip install nilearn` now installs the necessary dependencies. -- :func:`nilearn.image.new_img_like` no longer attempts to copy non-iterable headers. (PR #2212) -- Nilearn no longer raises ImportError for nose when Matplotlib is not installed. -- The arg `version='det'` in :func:`nilearn.datasets.fetch_atlas_pauli_2017` now works as expected. -- :func:`nilearn.maskers.NiftiLabelsMasker.inverse_transform` now works without the need to call - transform first. - -Contributors ------------- - -The following people contributed to this release (in alphabetical order):: - - Chris Markiewicz - Dan Gale - Daniel Gomez - Derek Pisner - Elizabeth DuPre - Eric Larson - Gael Varoquaux - Jerome Dockes - JohannesWiesner - Kshitij Chawla (kchawla-pi) - Paula Sanz-Leon - ltetrel - ryanhammonds - - -0.6.0b0 -======= - -**Released November 2019** - - -.. warning:: - - | **Python2 and 3.4 are no longer supported. Pip will raise an error in these environments.** - | **Minimum supported version of Python is now 3.5 .** - | **We recommend upgrading to Python 3.6 .** - - -NEW ---- - -- A new function :func:`nilearn.image.get_data` to replace the deprecated - nibabel method `Nifti1Image.get_data`. Now use `nilearn.image.get_data(img)` - rather than `img.get_data()`. This is because Nibabel is removing the - `get_data` method. You may also consider using the Nibabel - `Nifti1Image.get_fdata`, which returns the data cast to floating-point. - See https://github.com/nipy/nibabel/wiki/BIAP8 . - As a benefit, the `get_data` function works on niimg-like objects such as - filenames (see http://nilearn.github.io/manipulating_images/input_output.html ). - -Changes -------- - -- All functions and examples now use `nilearn.image.get_data` rather than the - deprecated method `nibabel.Nifti1Image.get_data`. - -- :func:`nilearn.datasets.fetch_neurovault` now does not filter out images that - have their metadata field `is_valid` cleared by default. - -- Users can now specify fetching data for adults, children, or both from - :func:`nilearn.datasets.fetch_development_fmri` . - - -Fixes ------ - -- :func:`nilearn.plotting.plot_connectome` now correctly displays marker size on 'l' - and 'r' orientations, if an array or a list is passed to the function. - -Contributors ------------- - -The following people contributed to this release (in alphabetical order):: - - Jake Vogel - Jerome Dockes - Kshitij Chawla (kchawla-pi) - Roberto Guidotti - -0.6.0a0 -======= - -**Released October 2019** - -NEW ---- - -.. warning:: - - | **Python2 and 3.4 are no longer supported. We recommend upgrading to Python 3.6 minimum.** - | - | **Minimum supported versions of packages have been bumped up.** - | - Matplotlib -- v2.0 - | - Scikit-learn -- v0.19 - | - Scipy -- v0.19 - -- A new method for :class:`nilearn.maskers.NiftiMasker` instances - for generating reports viewable in a web browser, Jupyter Notebook, or VSCode. - -- joblib is now a dependency - -- Parcellation method ReNA: Fast agglomerative clustering based on recursive - nearest neighbor grouping. - Yields very fast & accurate models, without creation of giant - clusters. - :class:`nilearn.regions.ReNA` -- Plot connectome strength - Use function ``nilearn.plotting.plot_connectome_strength`` to plot the strength of a - connectome on a glass brain. Strength is absolute sum of the edges at a node. -- Optimization to image resampling - :func:`nilearn.image.resample_img` has been optimized to pad rather than - resample images in the special case when there is only a translation - between two spaces. This is a common case in :class:`nilearn.maskers.NiftiMasker` - when using the `mask_strategy="template"` option for brains in MNI space. -- New brain development fMRI dataset fetcher - :func:`nilearn.datasets.fetch_development_fmri` can be used to download - movie-watching data in children and adults; a light-weight dataset - implemented for teaching and usage in the examples. -- New example in `examples/05_advanced/plot_age_group_prediction_cross_val.py` - to compare methods for classifying subjects into age groups based on - functional connectivity. Similar example in - `examples/03_connectivity/plot_group_level_connectivity.py` simplified. - -- Merged `examples/03_connectivity/plot_adhd_spheres.py` and - `examples/03_connectivity/plot_sphere_based_connectome.py` to remove - duplication across examples. The improved - `examples/03_connectivity/plot_sphere_based_connectome.py` contains - concepts previously reviewed in both examples. -- Merged `examples/03_connectivity/plot_compare_decomposition.py` - and `examples/03_connectivity/plot_canica_analysis.py` into an improved - `examples/03_connectivity/plot_compare_decomposition.py`. - -- The Localizer dataset now follows the :term:`BIDS` organization. - -Changes -------- - -- All the connectivity examples are changed from ADHD to brain development - fmri dataset. -- Examples plot_decoding_tutorial, plot_haxby_decoder, - plot_haxby_different_estimators, plot_haxby_full_analysis, plot_oasis_vbm now - use :class:`nilearn.decoding.Decoder` and :class:`nilearn.decoding.DecoderRegressor` - instead of sklearn SVC and SVR. - -- :func:`nilearn.plotting.view_img_on_surf`, :func:`nilearn.plotting.view_surf` - and :func:`nilearn.plotting.view_connectome` now allow disabling the colorbar, - and setting its height and the fontsize of its ticklabels. - -- :func:`nilearn.plotting.view_img_on_surf`, :func:`nilearn.plotting.view_surf` - and :func:`nilearn.plotting.view_connectome` can now display a title. - -- Rework of the standardize-options of :func:`nilearn.signal.clean` and the various Maskers - in `nilearn.maskers`. You can now set `standardize` to `zscore` or `psc`. `psc` stands - for `Percent Signal Change`, which can be a meaningful metric for BOLD. - -- :func:`nilearn.plotting.plot_img` now has explicit keyword arguments `bg_img`, - `vmin` and `vmax` to control the background image and the bounds of the - colormap. These arguments were already accepted in `kwargs` but not documented - before. - -- :func:`nilearn.plotting.view_connectome` now converts NaNs in the adjacency - matrix to 0. - -- Removed the plotting connectomes example which used the Seitzman atlas - from `examples/03_connectivity/plot_sphere_based_connectome.py`. - The atlas data is unsuitable for the method & the example is redundant. - -Fixes ------ - -- :func:`nilearn.plotting.plot_glass_brain` with colorbar=True does not crash when - images have NaNs. -- add_contours now accepts `threshold` argument for filled=False. Now - `threshold` is equally applied when asked for fillings in the contours. -- :func:`nilearn.plotting.plot_surf` and - :func:`nilearn.plotting.plot_surf_stat_map` no longer threshold zero values - when no threshold is given. -- When :func:`nilearn.plotting.plot_surf_stat_map` is used with a thresholded map - but without a background map, the surface mesh is displayed in - half-transparent grey to maintain a 3D perception. -- :func:`nilearn.plotting.view_surf` now accepts surface data provided as a file - path. -- :func:`nilearn.plotting.plot_glass_brain` now correctly displays the left 'l' orientation even when - the given images are completely masked (empty images). -- :func:`nilearn.plotting.plot_matrix` providing labels=None, False, or an empty list now correctly disables labels. -- :func:`nilearn.plotting.plot_surf_roi` now takes vmin, vmax parameters -- :func:`nilearn.datasets.fetch_surf_nki_enhanced` is now downloading the correct - left and right functional surface data for each subject -- :func:`nilearn.datasets.fetch_atlas_schaefer_2018` now downloads from release - version 0.14.3 (instead of 0.8.1) by default, which includes corrected region label - names along with 700 and 900 region parcelations. -- Colormap creation functions have been updated to avoid matplotlib deprecation warnings - about colormap reversal. -- Neurovault fetcher no longer fails if unable to update dataset metadata file due to faulty permissions. - -Contributors ------------- - -The following people contributed to this release (in alphabetical order):: - - Alexandre Abraham - Alexandre Gramfort - Ana Luisa - Ana Luisa Pinho - Andrés Hoyos Idrobo - Antoine Grigis - BAZEILLE Thomas - Bertrand Thirion - Colin Reininger - Céline Delettre - Dan Gale - Daniel Gomez - Elizabeth DuPre - Eric Larson - Franz Liem - Gael Varoquaux - Gilles de Hollander - Greg Kiar - Guillaume Lemaitre - Ian Abenes - Jake Vogel - Jerome Dockes - Jerome-Alexis Chevalier - Julia Huntenburg - Kamalakar Daddy - Kshitij Chawla (kchawla-pi) - Mehdi Rahim - Moritz Boos - Sylvain Takerkart - -0.5.2 -===== - -**Released April 2019** - -NEW ---- - -.. warning:: - - | This is the **last** release supporting Python2 and 3.4 . - | The lowest Python version supported is now Python3.5. - | We recommend switching to Python3.6 . - -Fixes ------ - -- Plotting ``.mgz`` files in MNE broke in ``0.5.1`` and has been fixed. - -Contributors ------------- - -The following people contributed to this release:: - - 11 Kshitij Chawla (kchawla-pi) - 3 Gael Varoquaux - 2 Alexandre Gramfort - -0.5.1 -===== - -**Released April 2019** - -NEW ---- -- **Support for Python2 & Python3.4 will be removed in the next release.** - We recommend Python 3.6 and up. - Users with a Python2 or Python3.4 environment will be warned - at their first Nilearn import. - -- Calculate image data dtype from header information -- New display mode 'tiled' which allows 2x2 plot arrangement when plotting three cuts - (see :ref:`plotting`). -- NiftiLabelsMasker now consumes less memory when extracting the signal from a 3D/4D - image. This is especially noteworthy when extracting signals from large 4D images. -- New function :func:`nilearn.datasets.fetch_atlas_schaefer_2018` -- New function :func:`nilearn.datasets.fetch_coords_seitzman_2018` - -Changes -------- - -- Lighting used for interactive surface plots changed; plots may look a bit - different. -- :func:`nilearn.plotting.view_connectome` default colormap is `bwr`, consistent with plot_connectome. -- :func:`nilearn.plotting.view_connectome` parameter names are consistent with plot_connectome: - - - coords is now node_coord - - marker_size is now node_size - - cmap is now edge_cmap - - threshold is now edge_threshold - -- :func:`nilearn.plotting.view_markers` and :func:`nilearn.plotting.view_connectome` can accept different marker - sizes for each node / marker. - -- :func:`nilearn.plotting.view_markers()` default marker color is now 'red', consistent with add_markers(). -- :func:`nilearn.plotting.view_markers` parameter names are consistent with add_markers(): - - - coords is now marker_coords - - colors is now marker_color - -- :func:`nilearn.plotting.view_img_on_surf` now accepts a `symmetric_cmap` - argument to control whether the colormap is centered around 0 and a `vmin` - argument. - -- Users can now control the size and fontsize of colorbars in interactive - surface and connectome plots, or disable the colorbar. - -Fixes ------ - -- Example plot_seed_to_voxel_correlation now really saves z-transformed maps. -- region_extractor.connected_regions and regions.RegionExtractor now correctly - use the provided mask_img. -- load_niimg no longer drops header if dtype is changed. -- NiftiSpheresMasker no longer silently ignores voxels if no `mask_img` is specified. -- Interactive brainsprites generated from `view_img` are correctly rendered in Jupyter Book. - -Known Issues -------------------- - -- On Python2, :func:`nilearn.plotting.view_connectome()` & - :func:`nilearn.plotting.view_markers()` - do not show parameters names in function signature - when using help() and similar features. - Please refer to their docstrings for this information. -- Plotting ``.mgz`` files in MNE is broken. - -Contributors ------------- - -The following people contributed to this release:: - - 2 Bertrand Thirion - 90 Kshitij Chawla (kchawla-pi) - 22 fliem - 16 Jerome Dockes - 11 Gael Varoquaux - 8 Salma Bougacha - 7 himanshupathak21061998 - 2 Elizabeth DuPre - 1 Eric Larson - 1 Pierre Bellec - -0.5.0 -===== - -**Released November 2018** - -NEW ---- - - :ref:`interactive plotting functions `, - eg for use in a notebook. - -- New functions :func:`nilearn.plotting.view_surf` and - :func:`nilearn.plotting.view_img_on_surf` for interactive visualization of - maps on the cortical surface in a web browser. - -- New functions :func:`nilearn.plotting.view_connectome` and - :func:`nilearn.plotting.view_markers` for interactive visualization of - connectomes and seed locations in 3D - -- New function :func:`nilearn.plotting.view_img` for interactive - visualization of volumes with 3 orthogonal cuts. - -:Note: :func:`nilearn.plotting.view_img` was `nilearn.plotting.view_stat_map` in alpha and beta releases. - -- :func:`nilearn.plotting.find_parcellation_cut_coords` for - extraction of coordinates on brain parcellations denoted as labels. - -- Added :func:`nilearn.plotting.find_probabilistic_atlas_cut_coords` for - extraction of coordinates on brain probabilistic maps. - - -**Minimum supported versions of packages have been bumped up.** - - scikit-learn -- v0.18 - - scipy -- v0.17 - - pandas -- v0.18 - - numpy -- v1.11 - - matplotlib -- v1.5.1 - -**Nilearn Python2 support is being removed in the near future.** - Users with a Python2 environment will be warned - at their first Nilearn import. - -**Additional dataset downloaders for examples and tutorials.** - -- :func:`nilearn.datasets.fetch_surf_fsaverage` -- :func:`nilearn.datasets.fetch_atlas_pauli_2017` -- :func:`nilearn.datasets.fetch_neurovault_auditory_computation_task` -- :func:`nilearn.datasets.fetch_neurovault_motor_task` - - -ENHANCEMENTS ------------- - - :func:`nilearn.image.clean_img` now accepts a mask to restrict - the cleaning of the image, reducing memory load and computation time. - - NiftiMaskers now have a `dtype` parameter, by default keeping the same data type as the input data. - - Displays by plotting functions can now add a scale bar (see :ref:`plotting`) - - -IMPROVEMENTS ------------- - - - Lots of other fixes in documentation and examples. - - A cleaner layout and improved navigation for the website, with a better introduction. - - Dataset fetchers are now more reliable, less verbose. - - Searchlight().fit() now accepts 4D niimgs. - - Anaconda link in the installation documentation updated. - - Scipy is listed as a dependency for Nilearn installation. - -Notable Changes ---------------- - - Default value of `t_r` in :func:`nilearn.signal.clean` and - :func:`nilearn.image.clean_img` is None - and cannot be None if `low_pass` or `high_pass` is specified. - -Lots of changes and improvements. Detailed change list for each release follows. - -0.5.0 rc -======== - -Highlights ----------- - -:func:`nilearn.plotting.view_img` (formerly `nilearn.plotting.view_stat_map` in -Nilearn 0.5.0 pre-release versions) generates significantly smaller notebooks -and HTML pages while getting a more consistent look and feel with Nilearn's -plotting functions. Huge shout out to Pierre Bellec (pbellec) for -making a great feature awesome and for sportingly accommodating all our feedback. - -:func:`nilearn.image.clean_img` now accepts a mask to restrict the cleaning of - the image. This approach can help to reduce the memory load and computation time. - Big thanks to Michael Notter (miykael). - -Enhancements ------------- - -- :func:`nilearn.plotting.view_img` is now using the brainsprite.js library, - which results in much smaller notebooks or html pages. The interactive viewer - also looks more similar to the plots generated by - :func:`nilearn.plotting.plot_stat_map`, and most parameters found in - `plot_stat_map` are now supported in `view_img`. -- :func:`nilearn.image.clean_img` now accepts a mask to restrict the cleaning of - the image. This approach can help to reduce the memory load and computation time. -- :func:`nilearn.decoding.SpaceNetRegressor.fit` raises a meaningful error in regression tasks - if the target Y contains all 1s. - -Changes -------- - -- Default value of `t_r` in :func:`nilearn.signal.clean` and - :func:`nilearn.image.clean_img` is changed from 2.5 to None. If `low_pass` or - `high_pass` is specified, then `t_r` needs to be specified as well otherwise - it will raise an error. -- Order of filters in :func:`nilearn.signal.clean` and :func:`nilearn.image.clean_img` - has changed to detrend, low- and high-pass filter, remove confounds and - standardize. To ensure orthogonality between temporal filter and confound - removal, an additional temporal filter will be applied on the confounds before - removing them. This is according to Lindquist et al. (2018). -- :func:`nilearn.image.clean_img` now accepts a mask to restrict the cleaning of - the image. This approach can help to reduce the memory load and computation time. -- :func:`nilearn.plotting.view_img` is now using the brainsprite.js library, - which results in much smaller notebooks or html pages. The interactive viewer - also looks more similar to the plots generated by - :func:`nilearn.plotting.plot_stat_map`, and most parameters found in - `plot_stat_map` are now supported in `view_img`. - - -Contributors -------------- - -The following people contributed to this release:: - - 15 Gael Varoquaux - 114 Pierre Bellec - 30 Michael Notter - 28 Kshitij Chawla (kchawla-pi) - 4 Kamalakar Daddy - 4 himanshupathak21061998 - 1 Horea Christian - 7 Jerome Dockes - -0.5.0 beta -========== - -Highlights ----------- - -**Nilearn Python2 support is being removed in the near future. -Users with a Python2 environment will be warned at their first Nilearn import.** - -Enhancements ------------- - -Displays created by plotting functions can now add a scale bar - to indicate the size in mm or cm (see :ref:`plotting`), - contributed by Oscar Esteban - -Colorbars in plotting functions now have a middle gray background - suitable for use with custom colormaps with a non-unity alpha channel. - Contributed by Eric Larson (larsoner) - -Loads of fixes and quality of life improvements - -- A cleaner layout and improved navigation for the website, with a better introduction. -- Less warnings and verbosity while using certain functions and during dataset downloads. -- Improved backend for the dataset fetchers means more reliable dataset downloads. -- Some datasets, such as the ICBM, are now compressed to take up less disk space. - - -Fixes ------ - -- Searchlight().fit() now accepts 4D niimgs. Contributed by Dan Gale (danjgale). -- plotting.view_markers.open_in_browser() in js_plotting_utils fixed -- Brainomics dataset has been replaced in several examples. -- Lots of other fixes in documentation and examples. - - -Changes -------- - -- In nilearn.regions.img_to_signals_labels, the See Also section in documentation now also points to NiftiLabelsMasker and NiftiMapsMasker -- Scipy is listed as a dependency for Nilearn installation. -- Anaconda link in the installation documentation updated. - -Contributors -------------- - -The following people contributed to this release:: - - 58 Gael Varoquaux - 115 Kshitij Chawla (kchawla-pi) - 15 Jerome Dockes - 14 oesteban - 10 Eric Larson - 6 Kamalakar Daddy - 3 Bertrand Thirion - 5 Alexandre Abadie - 4 Sourav Singh - 3 Alex Rothberg - 3 AnaLu - 3 Demian Wassermann - 3 Horea Christian - 3 Jason Gors - 3 Jean Remi King - 3 MADHYASTHA Meghana - 3 SRSteinkamp - 3 Simon Steinkamp - 3 jerome-alexis_chevalier - 3 salma - 3 sfvnMAC - 2 Akshay - 2 Daniel Gomez - 2 Guillaume Lemaitre - 2 Pierre Bellec - 2 arokem - 2 erramuzpe - 2 foucault - 2 jehane - 1 Sylvain LANNUZEL - 1 Aki Nikolaidis - 1 Christophe Bedetti - 1 Dan Gale - 1 Dillon Plunkett - 1 Dimitri Papadopoulos Orfanos - 1 Greg Operto - 1 Ivan Gonzalez - 1 Yaroslav Halchenko - 1 dtyulman - -0.5.0 alpha -=========== - -This is an alpha release: to download it, you need to explicitly ask for -the version number:: - - pip install nilearn==0.5.0a0 - -Highlights ----------- - - - **Minimum supported versions of packages have been bumped up.** - - scikit-learn -- v0.18 - - scipy -- v0.17 - - pandas -- v0.18 - - numpy -- v1.11 - - matplotlib -- v1.5.1 - - - New :ref:`interactive plotting functions `, - eg for use in a notebook. - -Enhancements ------------- - - - All NiftiMaskers now have a `dtype` argument. For now the default behaviour - is to keep the same data type as the input data. - - - Displays created by plotting functions can now add a scale bar to - indicate the size in mm or cm (see :ref:`plotting`), contributed by - Oscar Esteban - - - New functions :func:`nilearn.plotting.view_surf` and - :func:`nilearn.plotting.view_surf` and - :func:`nilearn.plotting.view_img_on_surf` for interactive visualization of - maps on the cortical surface in a web browser. - - - New functions :func:`nilearn.plotting.view_connectome` and - :func:`nilearn.plotting.view_markers` to visualize connectomes and - seed locations in 3D - - - New function `nilearn.plotting.view_stat_map` (renamed to - :func:`nilearn.plotting.view_img` in stable release) for interactive - visualization of volumes with 3 orthogonal cuts. - - - Add :func:`nilearn.datasets.fetch_surf_fsaverage` to download either - fsaverage or fsaverage 5 (Freesurfer cortical meshes). - - - Added :func:`nilearn.datasets.fetch_atlas_pauli_2017` to download a - recent subcortical neuroimaging atlas. - - - Added :func:`nilearn.plotting.find_parcellation_cut_coords` for - extraction of coordinates on brain parcellations denoted as labels. - - - Added :func:`nilearn.plotting.find_probabilistic_atlas_cut_coords` for - extraction of coordinates on brain probabilistic maps. - - - Added :func:`nilearn.datasets.fetch_neurovault_auditory_computation_task` - and :func:`nilearn.datasets.fetch_neurovault_motor_task` for simple example data. - -Changes -------- - - - `nilearn.datasets.fetch_surf_fsaverage5` is deprecated and will be - removed in a future release. Use :func:`nilearn.datasets.fetch_surf_fsaverage`, - with the parameter mesh="fsaverage5" (the default) instead. - - - fsaverage5 surface data files are now shipped directly with Nilearn. - Look to issue #1705 for discussion. - - - `sklearn.cross_validation` and `sklearn.grid_search` have been - replaced by `sklearn.model_selection` in all the examples. - - - Colorbars in plotting functions now have a middle gray background - suitable for use with custom colormaps with a non-unity alpha channel. - - -Contributors ------------- - -The following people contributed to this release:: - - 49 Gael Varoquaux - 180 Jerome Dockes - 57 Kshitij Chawla (kchawla-pi) - 38 SylvainLan - 36 Kamalakar Daddy - 10 Gilles de Hollander - 4 Bertrand Thirion - 4 MENUET Romuald - 3 Moritz Boos - 1 Peer Herholz - 1 Pierre Bellec - -0.4.2 -===== -Few important bugs fix release for OHBM conference. - -Changes -------- - - Default colormaps for surface plotting functions have changed to be more - consistent with slice plotting. - :func:`nilearn.plotting.plot_surf_stat_map` now uses "cold_hot", as - :func:`nilearn.plotting.plot_stat_map` does, and - :func:`nilearn.plotting.plot_surf_roi` now uses "gist_ncar", as - :func:`nilearn.plotting.plot_roi` does. - - - Improve 3D surface plotting: lock the aspect ratio of the plots and - reduce the whitespace around the plots. - -Bug fixes ---------- - - - Fix bug with input repetition time (TR) which had no effect in signal - cleaning. Fixed by Pradeep Raamana. - - - Fix issues with signal extraction on list of 3D images in - :class:`nilearn.regions.Parcellations`. - - - Fix issues with raising AttributeError rather than HTTPError in datasets - fetching utilities. By Jerome Dockes. - - - Fix issues in datasets testing function uncompression of files. By Pierre Glaser. - -0.4.1 -===== - -This bug fix release is focused on few bug fixes and minor developments. - -Enhancements ------------- - - - :class:`nilearn.decomposition.CanICA` and - :class:`nilearn.decomposition.DictLearning` has new attribute - `components_img_` providing directly the components learned as - a Nifti image. This avoids the step of unmasking the attribute - `components_` which is true for older versions. - - - New object :class:`nilearn.regions.Parcellations` for learning brain - parcellations on fmri data. - - - Add optional reordering of the matrix using a argument `reorder` - with :func:`nilearn.plotting.plot_matrix`. - - .. note:: - This feature is usable only if SciPy version is >= 1.0.0 - -Changes -------- - - - Using output attribute `components_` which is an extracted components - in :class:`nilearn.decomposition.CanICA` and - :class:`nilearn.decomposition.DictLearning` is deprecated and will - be removed in next two releases. Use `components_img_` instead. - -Bug fixes ---------- - - - Fix issues using :func:`nilearn.plotting.plot_connectome` when string is - passed in `node_color` with display modes left and right hemispheric cuts - in the glass brain. - - - Fix bug while plotting only coordinates using add_markers on glass brain. - See issue #1595 - - - Fix issues with estimators in decomposition module when input images are - given in glob patterns. - - - Fix bug loading Nifti2Images. - - - Fix bug while adjusting contrast of the background template while using - :func:`nilearn.plotting.plot_prob_atlas` - - - Fix colormap bug with recent matplotlib 2.2.0 - -0.4.0 -===== - -**Highlights**: - - - :func:`nilearn.surface.vol_to_surf` to project volume data to the - surface. - - - :func:`nilearn.plotting.plot_matrix` to display matrices, eg connectomes - -Enhancements -------------- - - - New function :func:`nilearn.surface.vol_to_surf` to project a 3d or - 4d brain volume on the cortical surface. - - - New matrix plotting function, eg to display connectome matrices: - :func:`nilearn.plotting.plot_matrix` - - - Expose :func:`nilearn.image.coord_transform` for end users. Useful - to transform coordinates (x, y, z) from one image space to - another space. - - - :func:`nilearn.image.resample_img` now takes a linear resampling - option (implemented by Joe Necus) - - - :func:`nilearn.datasets.fetch_atlas_talairach` to fetch the Talairach - atlas (http://talairach.org) - - - Enhancing new surface plotting functions, added new parameters - "axes" and "figure" to accept user-specified instances in - :func:`nilearn.plotting.plot_surf` and - :func:`nilearn.plotting.plot_surf_stat_map` and - :func:`nilearn.plotting.plot_surf_roi` - - - :class:`nilearn.decoding.SearchLight` has new parameter "groups" to - do LeaveOneGroupOut type cv with new scikit-learn module model selection. - - - Enhancing the glass brain plotting in back view 'y' direction. - - - New parameter "resampling_interpolation" is added in most used - plotting functions to have user control for faster visualizations. - - - Upgraded to Sphinx-Gallery 0.1.11 - -Bug fixes ----------- - - - Dimming factor applied to background image in plotting - functions with "dim" parameter will no longer accepts as - string ('-1'). An error will be raised. - - - Fixed issues with matplotlib 2.1.0. - - - Fixed issues with SciPy 1.0.0. - -Changes ---------- - - - **Backward incompatible change**: :func:`nilearn.plotting.find_xyz_cut_coords` - now takes a `mask_img` argument which is a niimg, rather than a `mask` - argument, which used to be a numpy array. - - - The minimum required version for scipy is now 0.14 - - - Dropped support for Nibabel older than 2.0.2. - - - :func:`nilearn.image.smooth_img` no longer accepts smoothing - parameter fwhm as 0. Behavior is changed in according to the - issues with recent SciPy version 1.0.0. - - - "dim" factor range is slightly increased to -2 to 2 from -1 to 1. - Range exceeding -1 meaning more increase in contrast should be - cautiously set. - - - New 'anterior' and 'posterior' view added to the plot_surf family views - - - Using argument `anat_img` for placing background image in - :func:`nilearn.plotting.plot_prob_atlas` is deprecated. Use argument - `bg_img` instead. - - - The examples now use pandas for the behavioral information. - -Contributors -------------- - -The following people contributed to this release:: - - 127 Jerome Dockes - 62 Gael Varoquaux - 36 Kamalakar Daddy - 11 Jeff Chiang - 9 Elizabeth DuPre - 9 Jona Sassenhagen - 7 Sylvain Lan - 6 J Necus - 5 Pierre-Olivier Quirion - 3 AnaLu - 3 Jean Remi King - 3 MADHYASTHA Meghana - 3 Salma Bougacha - 3 sfvnMAC - 2 Eric Larson - 2 Horea Christian - 2 Moritz Boos - 1 Alex Rothberg - 1 Bertrand Thirion - 1 Christophe Bedetti - 1 John Griffiths - 1 Mehdi Rahim - 1 Sylvain LANNUZEL - 1 Yaroslav Halchenko - 1 clfs - - -0.3.1 -===== - -This is a minor release for BrainHack. - -Highlights ----------- - -* **Dropped support for scikit-learn older than 0.14.1** Minimum supported version - is now 0.15. - -Changelog ---------- - - - The function sym_to_vec is deprecated and will be removed in - release 0.4. Use :func:`nilearn.connectome.sym_matrix_to_vec` instead. - - - Added argument `smoothing_fwhm` to - :class:`nilearn.regions.RegionExtractor` to control smoothing according - to the resolution of atlas images. - -Bug fix -------- - - - The helper function `largest_connected_component` should now work with - inputs of non-native data dtypes. - - - Fix plotting issues when non-finite values are present in background - anatomical image. - - - A workaround to handle non-native endianness in the Nifti images passed - to resampling the image. - -Enhancements -------------- - - New data fetcher functions :func:`nilearn.datasets.fetch_neurovault` and - :func:`nilearn.datasets.fetch_neurovault_ids` help you download - statistical maps from the Neurovault (http://neurovault.org) platform. - - - New function :func:`nilearn.connectome.vec_to_sym_matrix` reshapes - vectors to symmetric matrices. It acts as the reverse of function - :func:`nilearn.connectome.sym_matrix_to_vec`. - - - Add an option allowing to vectorize connectivity matrices returned by the - "transform" method of :class:`nilearn.connectome.ConnectivityMeasure`. - - - :class:`nilearn.connectome.ConnectivityMeasure` now exposes an - "inverse_transform" method, useful for going back from vectorized - connectivity coefficients to connectivity matrices. Also, it allows to - recover the covariance matrices for the "tangent" kind. - - - Reworking and renaming of connectivity measures example. Renamed from - plot_connectivity_measures to plot_group_level_connectivity. - - - Tighter bounding boxes when using add_contours for plotting. - - - Function :func:`nilearn.image.largest_connected_component_img` to - directly extract the largest connected component from Nifti images. - - - Improvements in plotting, decoding and functional connectivity examples. - -0.3.0 -====== - -In addition, more details of this release are listed below. Please checkout -in **0.3.0 beta** release section for minimum version support of dependencies, -latest updates, highlights, changelog and enhancements. - -Changelog ---------- - - - Function :func:`nilearn.plotting.find_cut_slices` now supports to accept - Nifti1Image as an input for argument `img`. - - - Helper functions `_get_mask_volume` and `_adjust_screening_percentile` - are now moved to param_validation file in utilities module to be used in - common with Decoder object. - -Bug fix --------- - - - Fix bug uncompressing tar files with datasets fetcher. - - - Fixed bunch of CircleCI documentation build failures. - - - Fixed deprecations `set_axis_bgcolor` related to matplotlib in - plotting functions. - - - Fixed bug related to not accepting a list of arrays as an input to - unmask, in masking module. - -Enhancements -------------- - - - ANOVA SVM example on Haxby datasets `plot_haxby_anova_svm` in Decoding section - now uses `SelectPercentile` to select voxels rather than `SelectKBest`. - - - New function `fast_svd` implementation in base decomposition module to - Automatically switch between randomized and lapack SVD (heuristic - of scikit-learn). - -0.3.0 beta -=========== - -To install the beta version, use:: - - pip install --upgrade --pre nilearn - -Highlights ----------- - -* Simple surface plotting - -* A function to break a parcellation into its connected components - -* **Dropped support for scikit-learn older than 0.14.1** Minimum supported version - is now 0.14.1. - -* **Dropped support for Python 2.6** - -* Minimum required version of NiBabel is now 1.2.0, to support loading annotated - data with freesurfer. - -Changelog ---------- - - - A helper function _safe_get_data as a nilearn utility now safely - removes NAN values in the images with argument ensure_finite=True. - - - Connectome functions :func:`nilearn.connectome.cov_to_corr` and - :func:`nilearn.connectome.prec_to_partial` can now be used. - -Bug fix --------- - - - Fix colormap issue with colorbar=True when using qualitative colormaps - Fixed in according with changes of matplotlib 2.0 fixes. - - - Fix plotting functions to work with NAN values in the images. - - - Fix bug related get dtype of the images with nibabel get_data(). - - - Fix bug in nilearn clean_img - -Enhancements -............ - - - A new function :func:`nilearn.regions.connected_label_regions` to - extract the connected components represented as same label to regions - apart with each region labelled as unique label. - - - New plotting modules for surface plotting visualization. Matplotlib with - version higher 1.3.1 is required for plotting surface data using these - functions. - - - Function :func:`nilearn.plotting.plot_surf` can be used for plotting - surfaces mesh data with optional background. - - - A function :func:`nilearn.plotting.plot_surf_stat_map` can be used for - plotting statistical maps on a brain surface with optional background. - - - A function :func:`nilearn.plotting.plot_surf_roi` can be used for - plotting statistical maps rois onto brain surface. - - - A function `nilearn.datasets.fetch_surf_fsaverage5` can be used - for surface data object to be as background map for the above plotting - functions. - - - A new data fetcher function - :func:`nilearn.datasets.fetch_atlas_surf_destrieux` - can give you Destrieux et. al 2010 cortical atlas in fsaverage5 - surface space. - - - A new functional data fetcher function - :func:`nilearn.datasets.fetch_surf_nki_enhanced` gives you resting state - data preprocessed and projected to fsaverage5 surface space. - - - Two good examples in plotting gallery shows how to fetch atlas and NKI - data and used for plotting on brain surface. - - - Helper function `load_surf_mesh` in surf_plotting module for loading - surface mesh data into two arrays, containing (x, y, z) coordinates - for mesh vertices and indices of mesh faces. - - - Helper function `load_surf_data` in surf_plotting module for loading - data of numpy array to represented on a surface mesh. - - - Add fetcher for Allen et al. 2011 RSN atlas in - :func:`nilearn.datasets.fetch_atlas_allen_2011`. - - - A function ``nilearn.datasets.fetch_cobre`` is now updated to new - light release of COBRE data (schizophrenia) - - - A new example to show how to extract regions on labels image in example - section manipulating images. - - - coveralls is replaces with codecov - - - Upgraded to Sphinx version 0.1.7 - - - Extensive plotting example shows how to use contours and filled contours - on glass brain. - -0.2.6 -===== - -Changelog ---------- - -This release enhances usage of several functions by fine tuning their -parameters. It allows to select which Haxby subject to fetch. It also refactors -documentation to make it easier to understand. -Sphinx-gallery has been updated and nilearn is ready for new nibabel 2.1 version. -Several bugs related to masks in Searchlight and ABIDE fetching have been -resolved. - -Bug fix -........ - - - Change default dtype in :func:`nilearn.image.concat_imgs` to be the - original type of the data (see #1238). - - - Fix SearchLight that did not run without process_mask or with one voxel - mask. - - - Fix flipping of left hemisphere when plotting glass brain. - - - Fix bug when downloading ABIDE timeseries - -Enhancements -............ - - - Sphinx-gallery updated to version 0.1.3. - - - Refactoring of examples and documentation. - - - Better ordering of regions in - :func:`nilearn.datasets.fetch_coords_dosenbach_2010`. - - - Remove outdated power atlas example. - - -API changes summary -................... - - - The parameter 'n_subjects' is deprecated and will be removed in future - release. Use 'subjects' instead in :func:`nilearn.datasets.fetch_haxby`. - - - The function :func:`nilearn.datasets.fetch_haxby` will now fetch the - data accepting input given in 'subjects' as a list than integer. - - - Replace `get_affine` by `affine` with recent versions of nibabel. - -0.2.5.1 -======= - -Changelog ---------- - -This is a bugfix release. -The new minimum required version of scikit-learn is 0.14.1 - -API changes summary -................... - - - default option for `dim` argument in plotting functions which uses MNI - template as a background image is now changed to 'auto' mode. Meaning - that an automatic contrast setting on background image is applied by - default. - - - Scikit-learn validation tools have been imported and are now used to check - consistency of input data, in SpaceNet for example. - -New features -............ - - - Add an option to select only off-diagonal elements in sym_to_vec. Also, - the scaling of matrices is modified: we divide the diagonal by sqrt(2) - instead of multiplying the off-diagonal elements. - - - Connectivity examples rely on - :class:`nilearn.connectome.ConnectivityMeasure` - -Bug fix -........ - - - Scipy 0.18 introduces a bug in a corner-case of resampling. Nilearn - 0.2.5 can give wrong results with scipy 0.18, but this is fixed in - 0.2.6. - - - Broken links and references fixed in docs - -0.2.5 -===== - -Changelog ---------- - -The 0.2.5 release includes plotting for connectomes and glass brain with -hemisphere-specific projection, as well as more didactic examples and -improved documentation. - -New features -............ - - - New display_mode options in :func:`nilearn.plotting.plot_glass_brain` - and :func:`nilearn.plotting.plot_connectome`. It - is possible to plot right and left hemisphere projections separately. - - - A function to load canonical brain mask image in MNI template space, - :func:`nilearn.datasets.load_mni152_brain_mask` - - - A function to load brain grey matter mask image, - :func:`nilearn.datasets.fetch_icbm152_brain_gm_mask` - - - New function :func:`nilearn.image.load_img` loads data from a filename or a - list of filenames. - - - New function :func:`nilearn.image.clean_img` applies the cleaning function - :func:`nilearn.signal.clean` on all voxels. - - - New simple data downloader - :func:`nilearn.datasets.fetch_localizer_button_task` to simplify - some examples. - - - The dataset function - :func:`nilearn.datasets.fetch_localizer_contrasts` can now download - a specific list of subjects rather than a range of subjects. - - - New function :func:`nilearn.datasets.get_data_dirs` to check where - nilearn downloads data. - -Contributors -------------- - -Contributors (from ``git shortlog -ns 0.2.4..0.2.5``):: - - 55 Gael Varoquaux - 39 Alexandre Abraham - 26 Martin Perez-Guevara - 20 Kamalakar Daddy - 8 amadeuskanaan - 3 Alexandre Abadie - 3 Arthur Mensch - 3 Elvis Dohmatob - 3 Loïc Estève - 2 Jerome Dockes - 1 Alexandre M. S - 1 Bertrand Thirion - 1 Ivan Gonzalez - 1 robbisg - -0.2.4 -===== - -Changelog ---------- - -The 0.2.4 is a small release focused on documentation for teaching. - -New features -............ - - The path given to the "memory" argument of object now have their - "~" expanded to the homedir - - - Display object created by plotting now uniformly expose an - "add_markers" method. - - - plotting plot_connectome with colorbar is now implemented in function - :func:`nilearn.plotting.plot_connectome` - - - New function :func:`nilearn.image.resample_to_img` to resample one - img on another one (just resampling / interpolation, no - coregistration) - -API changes summary -................... - - Atlas fetcher :func:`nilearn.datasets.fetch_atlas_msdl` now returns directly - labels of the regions in output variable 'labels' and its coordinates - in output variable 'region_coords' and its type of network in 'networks'. - - The output variable name 'regions' is now changed to 'maps' in AAL atlas - fetcher in :func:`nilearn.datasets.fetch_atlas_aal`. - - AAL atlas now returns directly its labels in variable 'labels' and its - index values in variable 'indices'. - -0.2.3 -===== - -Changelog ---------- - -The 0.2.3 is a small feature release for BrainHack 2016. - -New features -............ - - Mathematical formulas based on numpy functions can be applied on an - image or a list of images using :func:`nilearn.image.math_img`. - - Downloader for COBRE datasets of 146 rest fMRI subjects with - function ``nilearn.datasets.fetch_cobre``. - - Downloader for Dosenbach atlas - :func:`nilearn.datasets.fetch_coords_dosenbach_2010` - - Fetcher for multiscale functional brain parcellations (BASC) - :func:`nilearn.datasets.fetch_atlas_basc_multiscale_2015` - -Bug fixes -......... - - Better dimming on white background for plotting - -0.2.2 -====== - -Changelog ---------- - -The 0.2.2 is a bugfix + dependency update release (for sphinx gallery). It -aims at preparing a renewal of the tutorials. - -New features -............ - - Fetcher for Megatrawl Netmats dataset. - -Enhancements -............ - - Flake8 is now run on pull requests. - - Reworking of the documentation organization. - - Sphinx-gallery updated to version 0.1.1 - - The default n_subjects=None in :func:`nilearn.datasets.fetch_adhd` is now - changed to n_subjects=30. - -Bug fixes -......... - - Fix `symmetric_split` behavior in - :func:`nilearn.datasets.fetch_atlas_harvard_oxford` - - Fix casting errors when providing integer data to - :func:`nilearn.image.high_variance_confounds` - - Fix matplotlib 1.5.0 compatibility in - :func:`nilearn.plotting.plot_prob_atlas` - - Fix matplotlib backend choice on Mac OS X. - - :func:`nilearn.plotting.find_xyz_cut_coords` raises a meaningful error - when 4D data is provided instead of 3D. - - :class:`nilearn.maskers.NiftiSpheresMasker` handles radius smaller than - the size of a voxel - - :class:`nilearn.regions.RegionExtractor` handles data containing Nans. - - Confound regression does not force systematically the normalization of - the confounds. - - Force time series normalization in - :class:`nilearn.connectome.ConnectivityMeasure` - and check dimensionality of the input. - - `nilearn._utils.numpy_conversions.csv_to_array` could consider - valid CSV files as invalid. - -API changes summary -................... - - Deprecated dataset downloading function have been removed. - - Download progression message refreshing rate has been lowered to sparsify - CircleCI logs. - -Contributors -............. - -Contributors (from ``git shortlog -ns 0.2.1..0.2.2``):: - - 39 Kamalakar Daddy - 22 Alexandre Abraham - 21 Loïc Estève - 19 Gael Varoquaux - 12 Alexandre Abadie - 7 Salma - 3 Danilo Bzdok - 1 Arthur Mensch - 1 Ben Cipollini - 1 Elvis Dohmatob - 1 Óscar Nájera - -0.2.1 -====== - -Changelog ---------- - -Small bugfix for more flexible input types (targetter in particular at -making code easier in nistats). - -0.2 -=== - -Changelog ---------- - -The new minimum required version of scikit-learn is 0.13 - -New features -............ - - The new module :mod:`nilearn.connectome` now has class - :class:`nilearn.connectome.ConnectivityMeasure` can be useful for - computing functional connectivity matrices. - - The function nilearn.connectome.sym_to_vec in same module - :mod:`nilearn.connectome` is also implemented as a helper function to - :class:`nilearn.connectome.ConnectivityMeasure`. - - The class :class:`nilearn.decomposition.DictLearning` in - :mod:`nilearn.decomposition` is a decomposition method similar to ICA - that imposes sparsity on components instead of independence between them. - - Integrating back references template from sphinx-gallery of 0.0.11 - version release. - - Globbing expressions can now be used in all nilearn functions expecting a - list of files. - - The new module :mod:`nilearn.regions` now has class - :class:`nilearn.regions.RegionExtractor` which can be used for post - processing brain regions of interest extraction. - - The function :func:`nilearn.regions.connected_regions` in - :mod:`nilearn.regions` is also implemented as a helper function to - :class:`nilearn.regions.RegionExtractor`. - - The function :func:`nilearn.image.threshold_img` in :mod:`nilearn.image` - is implemented to use it for thresholding statistical maps. - -Enhancements -............ - - Making website a bit elaborated & modernise by using sphinx-gallery. - - Documentation enhancement by integrating sphinx-gallery notebook style - examples. - - Documentation about :class:`nilearn.maskers.NiftiSpheresMasker`. - -Bug fixes -......... - - Fixed bug to control the behaviour when cut_coords=0. in function - :func:`nilearn.plotting.plot_stat_map` in :mod:`nilearn.plotting`. - See issue # 784. - - Fixed bug in :func:`nilearn.image.copy_img` occurred while caching - the Nifti images. See issue # 793. - - Fixed bug causing an IndexError in fast_abs_percentile. See issue # 875 - -API changes summary -................... - - The utilities in function group_sparse_covariance has been moved - into :mod:`nilearn.connectome`. - - The default value for number of cuts (n_cuts) in function - :func:`nilearn.plotting.find_cut_slices` in :mod:`nilearn.plotting` has - been changed from 12 to 7 i.e. n_cuts=7. - -Contributors -............. - -Contributors (from ``git shortlog -ns 0.1.4..0.2.0``):: - - 822 Elvis Dohmatob - 142 Gael Varoquaux - 119 Alexandre Abraham - 90 Loïc Estève - 85 Kamalakar Daddy - 65 Alexandre Abadie - 43 Chris Filo Gorgolewski - 39 Salma BOUGACHA - 29 Danilo Bzdok - 20 Martin Perez-Guevara - 19 Mehdi Rahim - 19 Óscar Nájera - 17 martin - 8 Arthur Mensch - 8 Ben Cipollini - 4 ainafp - 4 juhuntenburg - 2 Martin_Perez_Guevara - 2 Michael Hanke - 2 arokem - 1 Bertrand Thirion - 1 Dimitri Papadopoulos Orfanos - - -0.1.4 -===== - -Changelog ---------- - -Highlights: - -- NiftiSpheresMasker: extract signals from balls specified by their - coordinates -- Obey Debian packaging rules -- Add the Destrieux 2009 and Power 2011 atlas -- Better caching in maskers - - -Contributors (from ``git shortlog -ns 0.1.3..0.1.4``):: - - 141 Alexandre Abraham - 15 Gael Varoquaux - 10 Loïc Estève - 2 Arthur Mensch - 2 Danilo Bzdok - 2 Michael Hanke - 1 Mehdi Rahim - - -0.1.3 -===== - -Changelog ---------- - -The 0.1.3 release is a bugfix release that fixes a lot of minor bugs. It -also includes a full rewamp of the documentation, and support for Python -3. - -Minimum version of supported packages are now: - -- numpy 1.6.1 -- scipy 0.9.0 -- scikit-learn 0.12.1 -- Matplotlib 1.1.1 (optional) - -A non exhaustive list of issues fixed: - -- Dealing with NaNs in plot_connectome -- Fix extreme values in colorbar were sometimes brok -- Fix confounds removal with single confounds -- Fix frequency filtering -- Keep header information in images -- add_overlay finds vmin and vmax automatically -- vmin and vmax support in plot_connectome -- detrending 3D images no longer puts them to zero - - -Contributors (from ``git shortlog -ns 0.1.2..0.1.3``):: - - 129 Alexandre Abraham - 67 Loïc Estève - 57 Gael Varoquaux - 44 Ben Cipollini - 37 Danilo Bzdok - 20 Elvis Dohmatob - 14 Óscar Nájera - 9 Salma BOUGACHA - 8 Alexandre Gramfort - 7 Kamalakar Daddy - 3 Demian Wassermann - 1 Bertrand Thirion - -0.1.2 -===== - -Changelog ---------- - -The 0.1.2 release is a bugfix release, specifically to fix the -NiftiMapsMasker. - -0.1.1 -===== - -Changelog ---------- - -The main change compared to 0.1 is the addition of connectome plotting -via the nilearn.plotting.plot_connectome function. See the -`plotting documentation `_ -for more details. - -Contributors (from ``git shortlog -ns 0.1..0.1.1``):: - - 81 Loïc Estève - 18 Alexandre Abraham - 18 Danilo Bzdok - 14 Ben Cipollini - 2 Gaël Varoquaux - - -0.1 -=== - -Changelog ---------- -First release of nilearn. - -Contributors (from ``git shortlog -ns 0.1``):: - - 600 Gaël Varoquaux - 483 Alexandre Abraham - 302 Loïc Estève - 254 Philippe Gervais - 122 Virgile Fritsch - 83 Michael Eickenberg - 59 Jean Kossaifi - 57 Jaques Grobler - 46 Danilo Bzdok - 35 Chris Filo Gorgolewski - 28 Ronald Phlypo - 25 Ben Cipollini - 15 Bertrand Thirion - 13 Alexandre Gramfort - 12 Fabian Pedregosa - 11 Yannick Schwartz - 9 Mehdi Rahim - 7 Óscar Nájera - 6 Elvis Dohmatob - 4 Konstantin Shmelkov - 3 Jason Gors - 3 Salma Bougacha - 1 Alexandre Savio - 1 Jan Margeta - 1 Matthias Ekman - 1 Michael Waskom - 1 Vincent Michel From 26e92ff3daa53184096f9e58265148056757b658 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Thu, 27 Jan 2022 10:18:59 +0100 Subject: [PATCH 36/44] [circle full] fix whats_new bug --- doc/changes/latest.rst | 6 + doc/whats_new.rst | 2376 ---------------------------------------- 2 files changed, 6 insertions(+), 2376 deletions(-) delete mode 100644 doc/whats_new.rst diff --git a/doc/changes/latest.rst b/doc/changes/latest.rst index a1945f644d..747c38806f 100644 --- a/doc/changes/latest.rst +++ b/doc/changes/latest.rst @@ -200,3 +200,9 @@ Changes - Descriptions of datasets retrieved with fetchers from :mod:`nilearn.datasets` are now python strings rather than `bytes`. Therefore, decoding the descriptions is no longer necessary. +- Dataset fetchers returning a :class:`numpy.recarray` can now return a + :class:`pandas.DataFrame` instead. These fetchers now have a ``legacy_format`` optional + argument defaulting to ``True`` for backward compatibility. Users will be warned that + this parameter will default to ``False`` in release 0.11.0, making + :class:`pandas.DataFrame` the default return type instead or :class:`numpy.recarray`. + (See PR `#2829 `_). diff --git a/doc/whats_new.rst b/doc/whats_new.rst deleted file mode 100644 index e5dd6f01c3..0000000000 --- a/doc/whats_new.rst +++ /dev/null @@ -1,2376 +0,0 @@ -0.8.2.dev -========= - -NEW ---- - -- **Support for Python 3.6 is deprecated and will be removed in release 0.10.** - Users with a Python 3.6 environment will be warned at their first Nilearn - import and encouraged to update to more recent versions of Python. -- Masker objects like :class:`~nilearn.maskers.NiftiMasker` now belong to the - new module :mod:`nilearn.maskers`. The old import style, through the module - ``input_data``, still works but has been deprecated. - (See PR `#3065 `_). -- New module :mod:`nilearn.interfaces` to implement loading and saving utilities - with various interfaces (fmriprep, bids...). - (See PR `#3061 `_). -- New submodule :mod:`nilearn.interfaces.fmriprep` to implement loading utilities - for :term:`fMRIPrep`. - (See PR `#3061 `_). -- New function :func:`nilearn.interfaces.fmriprep.load_confounds` to load confound - variables easily from :term:`fMRIPrep` outputs. - (See PR `#2946 `_). -- New function :func:`nilearn.interfaces.fmriprep.load_confounds_strategy` to load - confound variables from :term:`fMRIPrep` outputs using four preset strategies: - ``simple``, ``scrubbing``, ``compcor``, and ``ica_aroma``. - (See PR `#3016 `_). -- Surface plotting functions like :func:`nilearn.plotting.plot_surf_stat_map` - now have an `engine` parameter, defaulting to "matplotlib", but which can be - set to "plotly". If plotly and kaleido are installed, this will generate an - interactive plot of the surface map using plotly instead of matplotlib. - Note that this functionality is still experimental, and that some capabilities - supported by our matplotlib engine are not yet supported by the plotly engine. - (See PR `#2902 `_). -- When using the `plotly` engine, surface plotting functions derived from - :func:`~nilearn.plotting.plot_surf` return a new display object, a - :class:`~nilearn.plotting.displays.PlotlySurfaceFigure`, which provides a - similar interface to the :class:`~matplotlib.figure.Figure` returned with the - `matplotlib` engine. - (See PR `#3036 `_). -- :class:`~nilearn.maskers.NiftiMapsMasker` can now generate HTML reports in the same - way as :class:`~nilearn.maskers.NiftiMasker` and - :class:`~nilearn.maskers.NiftiLabelsMasker`. The report enables the users to browse - through the spatial maps with a previous and next button. The users can filter the maps - they wish to display by passing an integer, or a list of integers to - :meth:`~nilearn.maskers.NiftiMapsMasker.generate_report`. - -Fixes ------ - -- When a label image with non integer values was provided to the - :class:`nilearn.maskers.NiftiLabelsMasker`, its `generate_report` - method was raising an ``IndexError``. - (See issue `#3007 `_ and - fix `#3009 `_). -- :func:`nilearn.plotting.plot_markers` did not work when the `display_mode` - parameter included `l` and `r` and the parameter `node_size` was provided - as an array. - (See issue `#3012 `_) and fix - `#3013 `_). -- :meth:`nilearn.glm.first_level.FirstLevelModel.generate_report` threw a `TypeError` - when `FirstLevelModel` was instantiated with `mask_img` - being a :class:`~nilearn.maskers.NiftiMasker`. - :func:`nilearn.reporting.make_glm_report` was fixed accordingly. - (See issue `#3034 `_) and fix - `#3035 `_). -- Function :func:`~nilearn.plotting.find_parcellation_cut_coords` now returns - coordinates and labels having the same order as the one of the input labels - index (See PR `#3078 `_). -- Convert reference in `nilearn/regions/region_extractor.py` to use footcite / footbibliography. - (See issue `#2787 `_ and PR `#3111 `_). - -Enhancements ------------- - -- :func:`nilearn.image.threshold_img` accepts new parameters `cluster_threshold` - and `two_sided`. - `cluster_threshold` applies a cluster-size threshold (in voxels). - `two_sided`, which is `True` by default, separately thresholds both positive - and negative values in the map, as was done previously. - When `two_sided` is `False`, only values greater than or equal to the threshold - are retained. -- :func:`nilearn.signal.clean` raises a warning when the user sets - parameters `detrend` and `standardize_confound` to False. - The user is suggested to set one of - those options to `True`, or standardize/demean the confounds before using the - function. -- The :doc:`contributing documentation` and - :doc:`maintenance` pages were improved, especially towards ways - of contributing to the project which do not require to write code. - The roles of the :ref:`triage` were defined more clearly with sections on issue - :ref:`issue_labels` and issue :ref:`closing_policy`. - (See PR `#3010 `_). -- It is now possible to provide custom :term:`HRF` models to - :class:`nilearn.glm.first_level.FirstLevelModel`. The custom model should be - defined as a function, or a list of functions, implementing the same API as - Nilearn's usual models (see :func:`nilearn.glm.first_level.spm_hrf` for - example). The example - :ref:`sphx_glr_auto_examples_04_glm_first_level_plot_hrf.py` was - also modified to demo how to define custom :term:`HRF` models. - (See issue `#2940 `_). -- :class:`nilearn.maskers.NiftiLabelsMasker` now gives a warning when some - labels are removed from the label image at transform time due to resampling - of the label image to the data image. -- Function :func:`~nilearn.glm.second_level.non_parametric_inference` now accepts - :class:`~pandas.DataFrame` as possible values for its ``second_level_input`` - parameter. Note that a new parameter ``first_level_contrast`` has been added - to this function to enable this feature. - (See PR `#3042 `_). -- Tests from `nilearn/plotting/tests/test_img_plotting.py` have been refactored - and reorganized in separate files in new folder - `nilearn/plotting/tests/test_img_plotting/`. - (See PR `#3015 `_) -- Once a :class:`~nilearn.glm.second_level.SecondLevelModel` has been fitted and - contrasts have been computed, it is now possible to access the ``residuals``, - ``predicted``, and ``r_square`` model attributes like it was already possible - for :class:`~nilearn.glm.first_level.FirstLevelModel`. - (See FR `#3027 `_ - and PR `#3033 `_) -- Importing :mod:`nilearn.plotting` will now raise a warning if the matplotlib - backend has been changed from its original value, instead of silently modifying - it. - -Changes -------- - -- Nibabel 2.x is no longer supported. Please consider upgrading to Nibabel >= 3.0. - (See PR `#3106 `_). -- Deprecated function ``nilearn.datasets.fetch_cobre`` has been removed. - (See PR `#3081 `_). -- Deprecated function ``nilearn.plotting.plot_connectome_strength`` has been removed. - (See PR `#3082 `_). -- Deprecated function ``nilearn.masking.compute_gray_matter_mask`` has been removed. - (See PR `#3090 `_). -- Deprecated parameter ``sessions`` of function :func:`~nilearn.signal.clean` - has been removed. Use ``runs`` instead. - (See PR `#3093 `_). -- :func:`nilearn.glm.first_level.compute_regressor` will now raise an exception if - parameter `cond_id` is not a string which could be used to name a python variable. - For instance, number strings (ex: "1") will no longer be accepted as valid condition names. - In particular, this will also impact - :func:`nilearn.glm.first_level.make_first_level_design_matrix` and - :class:`nilearn.glm.first_level.FirstLevelModel`, for which proper condition names - will also be needed (see PR `#3025 `_). -- Replace parameter `sessions` with `runs` in :func:`nilearn.image.clean_img` as this - replacement was already made for :func:`nilearn.signal.clean` in - `#2821 `_ in order to match BIDS - semantics. The use of `sessions` in :func:`nilearn.image.clean_img` is deprecated and - will be removed in 0.10.0. -- Display objects have been reorganized. For example, Slicers (like the - :class:`~nilearn.plotting.displays.OrthoSlicer`) are all in file - `nilearn/plotting/displays/_slicers.py`, and Projectors (like the - :class:`~nilearn.plotting.displays.OrthoProjector`) are all in file - `nilearn/plotting/displays/_projectors.py`. All display objects have been added to - the public API, and examples have been improved to show how to use these objects - to customize figures obtained with plotting functions. - (See PR `#3073 `_). -- Descriptions of datasets retrieved with fetchers from :mod:`nilearn.datasets` are - now python strings rather than `bytes`. Therefore, decoding the descriptions is no - longer necessary. -- Dataset fetchers returning a :class:`numpy.recarray` can now return a - :class:`pandas.DataFrame` instead. These fetchers now have a ``legacy_format`` optional - argument defaulting to ``True`` for backward compatibility. Users will be warned that - this parameter will default to ``False`` in release 0.11.0, making - :class:`pandas.DataFrame` the default return type instead or :class:`numpy.recarray`. - (See PR `#2829 `_). - -.. _v0.8.1: - -0.8.1 -===== -**Released September 2021** - -HIGHLIGHTS ----------- - -- New atlas fetcher - :func:`nilearn.datasets.fetch_atlas_juelich` to download Juelich atlas from FSL. -- New grey and white-matter template and mask loading functions: - :func:`nilearn.datasets.load_mni152_gm_template`, - :func:`nilearn.datasets.load_mni152_wm_template`, - :func:`nilearn.datasets.load_mni152_gm_mask`, and - :func:`nilearn.datasets.load_mni152_wm_mask` -- :ref:`development_process` has been reworked. It now provides insights on - nilearn organization as a project as well as more explicit - :ref:`contribution_guidelines`. -- :func:`nilearn.image.binarize_img` binarizes images into 0 and 1. - -NEW ---- -- New atlas fetcher - :func:`nilearn.datasets.fetch_atlas_juelich` to download Juelich atlas from FSL. -- :ref:`development_process` has been reworked. It now provides insights on - nilearn organization as a project as well as more explicit - :ref:`contribution_guidelines`. -- :func:`nilearn.datasets.load_mni152_gm_template` takes the skullstripped - 1mm-resolution version of the grey-matter MNI152 template and re-samples it - using a different resolution, if specified. -- :func:`nilearn.datasets.load_mni152_wm_template` takes the skullstripped - 1mm-resolution version of the white-matter MNI152 template and re-samples it - using a different resolution, if specified. -- :func:`nilearn.datasets.load_mni152_gm_mask` loads mask from the grey-matter - MNI152 template. -- :func:`nilearn.datasets.load_mni152_wm_mask` loads mask from the white-matter - MNI152 template. -- :func:`nilearn.image.binarize_img` binarizes images into 0 and 1. -- :class:`nilearn.maskers.NiftiMasker`, - :class:`nilearn.maskers.MultiNiftiMasker`, and objects relying on such maskers - (:class:`nilearn.decoding.Decoder` or :class:`nilearn.decomposition.CanICA` - for example) can now use new options for the argument `mask_strategy`: - `whole-brain-template` for whole-brain template (same as previous option - `template`), `gm-template` for grey-matter template, and `wm-template` - for white-matter template. - -Fixes ------ - -- :func:`nilearn.masking.compute_multi_brain_mask` has replaced - nilearn.masking.compute_multi_grey_matter_mask. A mask parameter has been added; - it accepts three types of masks---i.e. whole-brain, grey-matter and - white-matter---following the enhancements made in the function - :func:`nilearn.masking.compute_brain_mask` in this release. -- Fix colorbar of :func:`nilearn.plotting.view_img` which was not visible for some - combinations of `black_bg` and `bg_img` parameters. - (See issue `#2874 `_). -- Fix missing title with :func:`nilearn.plotting.plot_surf` and - deriving functions. - (See issue `#2941 `_). - -Enhancements ------------- - -- :func:`nilearn.datasets.load_mni152_template` resamples now the template to - a preset resolution different from the resolution of the original template, - i.e. 1mm. The default resolution is 2mm, which means that the new template is - resampled to the resolution of the old template. Nevertheless, the shape of - the template changed from (91, 109, 91) to (99, 117, 95); the affine also - changed from array([[-2., 0., 0., 90.], [0., 2., 0., -126.], - [0., 0., 2., -72.], [0., 0., 0., 1.]]) to array([[1., 0., 0., -98.], - [0., 1., 0., -134.], [0., 0., 1., -72.], [0., 0., 0., 1.]]). Additionally, - the new template has also been rescaled; whereas the old one varied between - 0 and 8339, the new one varies between 0 and 255. -- :func:`nilearn.datasets.load_mni152_brain_mask` accepts now the parameter - resolution, which will set the resolution of the template used for the - masking. -- :func:`nilearn.masking.compute_brain_mask` accepts now as input the - whole-brain, 1mm-resolution, MNI152 T1 template instead of the averaged, - whole-brain, 2mm-resolution MNI152 T1 template; it also accepts as input the - grey-matter and white-matter ICBM152 1mm-resolution templates dated from 2009. -- Common parts of docstrings across Nilearn can now be filled automatically using - the decorator `nilearn._utils.fill_doc`. This can be applied to common function - parameters or common lists of options for example. The standard parts are defined - in a single location (`nilearn._utils.docs.py`) which makes them easier to - maintain and update. (See `#2875 `_) -- The `data_dir` argument can now be either a `pathlib.Path` or a string. This - extension affects datasets and atlas fetchers. - -Changes -------- - -- The version of the script `jquery.min.js` was bumped from 3.3.1 to 3.6.0 due - to potential vulnerability issues with versions < 3.5.0. - -.. _v0.8.0: - -0.8.0 -===== - -**Released June 2021** - -HIGHLIGHTS ----------- - -.. warning:: - - | **Python 3.5 is no longer supported. We recommend upgrading to Python 3.8.** - | - | **Support for Nibabel 2.x is deprecated and will be removed in the 0.9 release.** - | Users with a version of Nibabel < 3.0 will be warned at their first Nilearn import. - | - | **Minimum supported versions of packages have been bumped up:** - | - Numpy -- v1.16 - | - SciPy -- v1.2 - | - Scikit-learn -- v0.21 - | - Nibabel -- v2.5 - | - Pandas -- v0.24 - -- :class:`nilearn.maskers.NiftiLabelsMasker` can now generate HTML reports in the same - way as :class:`nilearn.maskers.NiftiMasker`. -- :func:`nilearn.signal.clean` accepts new parameter `sample_mask`. - shape: (number of scans - number of volumes removed, ) -- All inherent classes of `nilearn.maskers.BaseMasker` can use parameter `sample_mask` - for sub-sample masking. -- Fetcher :func:`nilearn.datasets.fetch_surf_fsaverage` now accepts `fsaverage3`, - `fsaverage4` and `fsaverage6` as values for parameter `mesh`, so that - all resolutions of fsaverage from 3 to 7 are now available. -- Fetcher :func:`nilearn.datasets.fetch_surf_fsaverage` now provides attributes - `{area, curv, sphere, thick}_{left, right}` for all fsaverage resolutions. -- :class:`nilearn.glm.first_level.run_glm` now allows auto regressive noise - models of order greater than one. - -NEW ---- - -- :func:`nilearn.signal.clean` accepts new parameter `sample_mask`. - shape: (number of scans - number of volumes removed, ) - Masks the niimgs along time/fourth dimension to perform scrubbing (remove - volumes with high motion) and/or non-steady-state volumes. Masking is applied - before signal cleaning. -- All inherent classes of `nilearn.maskers.BaseMasker` can use - parameter `sample_mask` for sub-sample masking. -- :class:`nilearn.maskers.NiftiLabelsMasker` can now generate HTML reports in the same - way as :class:`nilearn.maskers.NiftiMasker`. The report shows the regions defined by - the provided label image and provide summary statistics on each region (name, volume...). - If a functional image was provided to fit, the middle image is plotted with the regions - overlaid as contours. Finally, if a mask is provided, its contours are shown in green. - -Fixes ------ - -- Convert references in signal.py, atlas.py, func.py, neurovault.py, and struct.py - to use footcite / footbibliography. -- Fix detrending and temporal filtering order for confounders - in :func:`nilearn.signal.clean`, so that these operations are applied - in the same order as for the signals, i.e., first detrending and - then temporal filtering (https://github.com/nilearn/nilearn/issues/2730). -- Fix number of attributes returned by the - `nilearn.glm.first_level.FirstLevelModel._get_voxelwise_model_attribute` method - in the first level model. It used to return only the first attribute, and now returns - as many attributes as design matrices. -- Plotting functions that show a stack of slices from a 3D image (e.g. - :func:`nilearn.plotting.plot_stat_map`) will now plot the slices in the user - specified order, rather than automatically sorting into ascending order - (https://github.com/nilearn/nilearn/issues/1155). -- Fix the axes zoom on plot_img_on_surf function so brain would not be cutoff, and - edited function so less white space surrounds brain views & smaller colorbar using - gridspec (https://github.com/nilearn/nilearn/pull/2798). -- Fix inconsistency in prediction values of Dummy Classifier for Decoder - object (https://github.com/nilearn/nilearn/issues/2767). - -Enhancements ------------- - -- :func:`nilearn.plotting.view_markers` now accepts an optional argument `marker_labels` - to provide labels to each marker. -- :func:`nilearn.plotting.plot_surf` now accepts new values for `avg_method` argument, - such as `min`, `max`, or even a custom python function to compute the value displayed - for each face of the plotted mesh. -- :func:`nilearn.plotting.view_img_on_surf` can now optionally pass through - parameters to :func:`nilearn.surface.vol_to_surf` using the - `vol_to_surf_kwargs` argument. One application is better HTML visualization of atlases. - (https://nilearn.github.io/auto_examples/01_plotting/plot_3d_map_to_surface_projection.html) -- :func:`nilearn.plotting.view_connectome` now accepts an optional argument `node_color` - to provide a single color for all nodes, or one color per node. - It defaults to `auto` which colors markers according to the viridis colormap. -- Refactor :func:`nilearn.signal.clean` to clarify the data flow. - Replace `sessions` with `runs` to matching BIDS semantics and deprecate `sessions` in 0.9.0. - Add argument `filter` and allow a selection of signal filtering strategies: - * "butterwoth" (butterworth filter) - * "cosine" (discrete cosine transformation) - * `False` (no filtering) -- Change the default strategy for Dummy Classifier from 'prior' to - 'stratified' (https://github.com/nilearn/nilearn/pull/2826/). -- :class:`nilearn.glm.first_level.run_glm` now allows auto regressive noise - models of order greater than one. -- Moves parameter `sample_mask` from :class:`nilearn.maskers.NiftiMasker` - to method `transform` in base class `nilearn.maskers.BaseMasker`. -- Fetcher :func:`nilearn.datasets.fetch_surf_fsaverage` now accepts - `fsaverage3`, `fsaverage4` and `fsaverage6` as values for parameter `mesh`, so that - all resolutions of fsaverage from 3 to 7 are now available. -- Fetcher :func:`nilearn.datasets.fetch_surf_fsaverage` now provides - attributes `{area, curv, sphere, thick}_{left, right}` for all fsaverage - resolutions. - -Changes -------- - -- Python 3.5 is no longer supported. We recommend upgrading to Python 3.7. -- Support for Nibabel 2.x is now deprecated and will be removed - in the 0.9 release. Users with a version of Nibabel < 3.0 will - be warned at their first Nilearn import. -- Minimum supported versions of packages have been bumped up: - - * Numpy -- v1.16 - * SciPy -- v1.2 - * Scikit-learn -- v0.21 - * Nibabel -- v2.5 - * Pandas -- v0.24 - -- Function sym_to_vec from :mod:`nilearn.connectome` was deprecated since release 0.4 and - has been removed. -- Fetcher `nilearn.datasets.fetch_nyu_rest` is deprecated since release 0.6.2 and - has been removed. -- :class:`nilearn.maskers.NiftiMasker` replaces `sessions` with `runs` and - deprecates attribute `sessions` in 0.9.0. Match the relevant change in - :func:`nilearn.signal.clean`. - -.. _v0.7.1: - -0.7.1 -===== - -**Released March 2021** - -HIGHLIGHTS ----------- - -- New atlas fetcher - :func:`nilearn.datasets.fetch_atlas_difumo` to download *Dictionaries of Functional Modes*, - or “DiFuMo”, that can serve as atlases to extract functional signals with different - dimensionalities (64, 128, 256, 512, and 1024). These modes are optimized to represent well - raw BOLD timeseries, over a with range of experimental conditions. - -- :class:`nilearn.decoding.Decoder` and :class:`nilearn.decoding.DecoderRegressor` - is now implemented with random predictions to estimate a chance level. - -- The functions :func:`nilearn.plotting.plot_epi`, :func:`nilearn.plotting.plot_roi`, - :func:`nilearn.plotting.plot_stat_map`, :func:`nilearn.plotting.plot_prob_atlas` - is now implemented with new display mode Mosaic. That implies plotting 3D maps - in multiple columns and rows in a single axes. - -- :func:`nilearn.plotting.plot_carpet` now supports discrete atlases. - When an atlas is used, a colorbar is added to the figure, - optionally with labels corresponding to the different values in the atlas. - -NEW ---- - -- New atlas fetcher - :func:`nilearn.datasets.fetch_atlas_difumo` to download *Dictionaries of Functional Modes*, - or “DiFuMo”, that can serve as atlases to extract functional signals with different - dimensionalities (64, 128, 256, 512, and 1024). These modes are optimized to represent well - raw BOLD timeseries, over a with range of experimental conditions. - -- :func:`nilearn.glm.Contrast.one_minus_pvalue` was added to ensure numerical - stability of p-value estimation. It computes 1 - p-value using the Cumulative - Distribution Function in the same way as `nilearn.glm.Contrast.p_value` - computes the p-value using the Survival Function. - -Fixes ------ - -- Fix altered, non-zero baseline in design matrices where multiple events in the same condition - end at the same time (https://github.com/nilearn/nilearn/issues/2674). - -- Fix testing issues on ARM machine. - -Enhancements ------------- - -- :class:`nilearn.decoding.Decoder` and :class:`nilearn.decoding.DecoderRegressor` - is now implemented with random predictions to estimate a chance level. - -- :class:`nilearn.decoding.Decoder`, :class:`nilearn.decoding.DecoderRegressor`, - :class:`nilearn.decoding.FREMRegressor`, and :class:`nilearn.decoding.FREMClassifier` - now override the `score` method to use whatever scoring strategy was defined through - the `scoring` attribute instead of the sklearn default. - If the `scoring` attribute of the decoder is set to None, the scoring strategy - will default to accuracy for classifiers and to r2 score for regressors. - -- :func:`nilearn.plotting.plot_surf` and deriving functions like :func:`nilearn.plotting.plot_surf_roi` - now accept an optional argument `cbar_tick_format` to specify how numbers should be displayed on the - colorbar of surface plots. The default format is scientific notation except for :func:`nilearn.plotting.plot_surf_roi` - for which it is set as integers. - -- :func:`nilearn.plotting.plot_carpet` now supports discrete atlases. - When an atlas is used, a colorbar is added to the figure, - optionally with labels corresponding to the different values in the atlas. - -- :class:`nilearn.maskers.NiftiMasker`, :class:`nilearn.maskers.NiftiLabelsMasker`, - :class:`nilearn.maskers.MultiNiftiMasker`, :class:`nilearn.maskers.NiftiMapsMasker`, - and :class:`nilearn.maskers.NiftiSpheresMasker` can now compute high variance confounds - on the images provided to `transform` and regress them out automatically. This behaviour is - controlled through the `high_variance_confounds` boolean parameter of these maskers which - default to False. - -- :class:`nilearn.maskers.NiftiLabelsMasker` now automatically replaces NaNs in input data - with zeros, to match the behavior of other maskers. - -- :func:`nilearn.datasets.fetch_neurovault` now implements a `resample` boolean argument to either - perform a fixed resampling during download or keep original images. This can be handy to reduce disk usage. - By default, the downloaded images are not resampled. - -- The functions :func:`nilearn.plotting.plot_epi`, :func:`nilearn.plotting.plot_roi`, - :func:`nilearn.plotting.plot_stat_map`, :func:`nilearn.plotting.plot_prob_atlas` - is now implemented with new display mode Mosaic. That implies plotting 3D maps - in multiple columns and rows in a single axes. - -- `psc` standardization option of :func:`nilearn.signal.clean` now allows time series with negative mean values. - -- :func:`nilearn.reporting.make_glm_report` and - :func:`nilearn.reporting.get_clusters_table` have a new argument, - "two_sided", which allows for two-sided thresholding, which is disabled by default. - -.. _v0.7.0: - -0.7.0 -===== - -**Released November 2020** - -HIGHLIGHTS ----------- - -- Nilearn now includes the functionality of `Nistats `_ as :mod:`nilearn.glm`. This module is experimental, hence subject to change in any future release. - :ref:`Here's a guide to replacing Nistats imports to work in Nilearn. ` -- New decoder object - :class:`nilearn.decoding.Decoder` (for classification) and - :class:`nilearn.decoding.DecoderRegressor` (for regression) implement a model - selection scheme that averages the best models within a cross validation loop. -- New FREM object - :class:`nilearn.decoding.FREMClassifier` (for classification) and - :class:`nilearn.decoding.FREMRegressor` (for regression) extend the decoder - object with one fast clustering step at the beginning and aggregates a high number of estimators trained on various splits of the training set. - -- New plotting functions: - - * :func:`nilearn.plotting.plot_event` to visualize events file. - * :func:`nilearn.plotting.plot_roi` can now plot ROIs in contours with `view_type` argument. - * :func:`nilearn.plotting.plot_carpet` generates a "carpet plot" (also known - as a "Power plot" or a "grayplot") - * :func:`nilearn.plotting.plot_img_on_surf` generates multiple views of - :func:`nilearn.plotting.plot_surf_stat_map` in a single figure. - * :func:`nilearn.plotting.plot_markers` shows network nodes (markers) on a glass - brain template - * :func:`nilearn.plotting.plot_surf_contours` plots the contours of regions of - interest on the surface - -.. warning:: - - Minimum required version of Joblib is now 0.12. - - -NEW ---- -- Nilearn now includes the functionality of `Nistats `_. - :ref:`Here's a guide to replacing Nistats imports to work in Nilearn. ` -- New decoder object - :class:`nilearn.decoding.Decoder` (for classification) and - :class:`nilearn.decoding.DecoderRegressor` (for regression) implement a model - selection scheme that averages the best models within a cross validation loop. - The resulting average model is the one used as a classifier or a regressor. - These two objects also leverage the `NiftiMaskers` to provide a direct - interface with the Nifti files on disk. -- New FREM object - :class:`nilearn.decoding.FREMClassifier` (for classification) and - :class:`nilearn.decoding.FREMRegressor` (for regression) extend the decoder - object pipeline with one fast clustering step at the beginning (yielding an - implicit spatial regularization) and aggregates a high number of estimators - trained on various splits of the training set. This returns a state-of-the-art - decoding pipeline at a low computational cost. - These two objects also leverage the `NiftiMaskers` to provide a direct - interface with the Nifti files on disk. -- Plot events file - Use :func:`nilearn.plotting.plot_event` to visualize events file. - The function accepts the :term:`BIDS` events file read using `pandas` - utilities. -- Plotting function :func:`nilearn.plotting.plot_roi` can now plot ROIs - in contours with `view_type` argument. -- New plotting function - :func:`nilearn.plotting.plot_carpet` generates a "carpet plot" (also known - as a "Power plot" or a "grayplot"), for visualizing global patterns in - 4D functional data over time. -- New plotting function - :func:`nilearn.plotting.plot_img_on_surf` generates multiple views of - :func:`nilearn.plotting.plot_surf_stat_map` in a single figure. -- :func:`nilearn.plotting.plot_markers` shows network nodes (markers) on a glass - brain template and color code them according to provided nodal measure (i.e. - connection strength). This function will replace function - ``nilearn.plotting.plot_connectome_strength``. -- New plotting function - :func:`nilearn.plotting.plot_surf_contours` plots the contours of regions of - interest on the surface, optionally overlaid on top of a statistical map. -- The position annotation on the plot methods now implements the `decimals` option - to enable annotation of a slice coordinate position with the float. -- New example in - :ref:`sphx_glr_auto_examples_02_decoding_plot_haxby_searchlight_surface.py` - to demo how to do cortical surface-based searchlight decoding with Nilearn. -- confounds or additional regressors for design matrix can be specified as - numpy arrays or pandas DataFrames interchangeably -- The decomposition estimators will now accept argument `per_component` - with `score` method to explain the variance for each component. - - -Fixes ------ - -- :class:`nilearn.maskers.NiftiLabelsMasker` no longer ignores its `mask_img` -- :func:`nilearn.masking.compute_brain_mask` has replaced - nilearn.masking.compute_gray_matter_mask. Features remained the same but - some corrections regarding its description were made in the docstring. -- the default background (MNI template) in plotting functions now has the - correct orientation; before left and right were inverted. -- first level modelling can deal with regressors - having multiple events which share onsets or offsets. - Previously, such cases could lead to an erroneous baseline shift. -- :func:`nilearn.mass_univariate.permuted_ols` no longer returns transposed - t-statistic arrays when no permutations are performed. -- Fix decomposition estimators returning explained variance score as 0. - based on all components i.e., when per_component=False. -- Fix readme file of the Destrieux 2009 atlas. - - -Changes -------- - -- Function ``nilearn.datasets.fetch_cobre`` has been deprecated and will be - removed in release 0.9 . -- Function ``nilearn.plotting.plot_connectome_strength`` has been deprecated and will - be removed in release 0.9 . - -- :class:`nilearn.connectome.ConnectivityMeasure` can now remove - confounds in its transform step. -- :func:`nilearn.surface.vol_to_surf` can now sample between two nested surfaces - (eg white matter and pial surfaces) at specific cortical depths -- :func:`nilearn.datasets.fetch_surf_fsaverage` now also downloads white matter - surfaces. - - -.. _v0.6.2: - -0.6.2 -====== - -ENHANCEMENTS ------------- - -- Generated documentation now includes Binder links to launch examples interactively - in the browser -- :class:`nilearn.maskers.NiftiSpheresMasker` now has an inverse transform, - projecting spheres to the corresponding mask_img. - -Fixes ------ - -- More robust matplotlib backend selection -- Typo in example fixed - -Changes -------- - -- Atlas `nilearn.datasets.fetch_nyu_rest` has been deprecated and will be removed in Nilearn 0.8.0 . - -Contributors ------------- - -The following people contributed to this release:: - - Elizabeth DuPre - Franz Liem - Gael Varoquaux - Jon Haitz Legarreta Gorroño - Joshua Teves - Kshitij Chawla (kchawla-pi) - Zvi Baratz - Simon R. Steinkamp - - -.. _v0.6.1: - -0.6.1 -===== - -ENHANCEMENTS ------------- - -- html pages use the user-provided plot title, if any, as their title - -Fixes ------ - -- Fetchers for developmental_fmri and localizer datasets resolve URLs correctly. - -Contributors ------------- - -The following people contributed to this release:: - - Elizabeth DuPre - Jerome Dockes - Kshitij Chawla (kchawla-pi) - -0.6.0 -===== - -**Released December 2019** - -HIGHLIGHTS ----------- - -.. warning:: - - | **Python2 and 3.4 are no longer supported. We recommend upgrading to Python 3.6 minimum.** - | - | **Support for Python3.5 will be removed in the 0.7.x release.** - | Users with a Python3.5 environment will be warned at their first Nilearn import. - | - | **joblib is now a dependency** - | - | **Minimum supported versions of packages have been bumped up.** - | - Matplotlib -- v2.0 - | - Scikit-learn -- v0.19 - | - Scipy -- v0.19 - -NEW ---- - -- A new method for :class:`nilearn.maskers.NiftiMasker` instances - for generating reports viewable in a web browser, Jupyter Notebook, or VSCode. - -- A new function :func:`nilearn.image.get_data` to replace the deprecated - nibabel method `Nifti1Image.get_data`. Now use `nilearn.image.get_data(img)` - rather than `img.get_data()`. This is because Nibabel is removing the - `get_data` method. You may also consider using the Nibabel - `Nifti1Image.get_fdata`, which returns the data cast to floating-point. - See https://github.com/nipy/nibabel/wiki/BIAP8 . - As a benefit, the `get_data` function works on niimg-like objects such as - filenames (see http://nilearn.github.io/manipulating_images/input_output.html ). - -- Parcellation method ReNA: Fast agglomerative clustering based on recursive - nearest neighbor grouping. - Yields very fast & accurate models, without creation of giant - clusters. - :class:`nilearn.regions.ReNA` -- Plot connectome strength - Use function ``nilearn.plotting.plot_connectome_strength`` to plot the strength of a - connectome on a glass brain. Strength is absolute sum of the edges at a node. -- Optimization to image resampling -- New brain development fMRI dataset fetcher - :func:`nilearn.datasets.fetch_development_fmri` can be used to download - movie-watching data in children and adults. A light-weight dataset - implemented for teaching and usage in the examples. All the connectivity examples - are changed from ADHD to brain development fmri dataset. - -ENHANCEMENTS ------------- - -- :func:`nilearn.plotting.view_img_on_surf`, :func:`nilearn.plotting.view_surf` - and :func:`nilearn.plotting.view_connectome` can display a title, and allow - disabling the colorbar, and setting its height and the fontsize of its ticklabels. - -- Rework of the standardize-options of :func:`nilearn.signal.clean` and the various Maskers - in `nilearn.maskers`. You can now set `standardize` to `zscore` or `psc`. `psc` stands - for `Percent Signal Change`, which can be a meaningful metric for BOLD. - -- Class :class:`nilearn.maskers.NiftiLabelsMasker` now accepts an optional - `strategy` parameter which allows it to change the function used to reduce - values within each labelled ROI. Available functions include mean, median, - minimum, maximum, standard_deviation and variance. - This change is also introduced in :func:`nilearn.regions.img_to_signals_labels`. - -- :func:`nilearn.plotting.view_surf` now accepts surface data provided as a file - path. - -CHANGES -------- - -- :func:`nilearn.plotting.plot_img` now has explicit keyword arguments `bg_img`, - `vmin` and `vmax` to control the background image and the bounds of the - colormap. These arguments were already accepted in `kwargs` but not documented - before. - -FIXES ------ - -- :class:`nilearn.maskers.NiftiLabelsMasker` no longer truncates region means to their integral part - when input images are of integer type. -- The arg `version='det'` in :func:`nilearn.datasets.fetch_atlas_pauli_2017` now works as expected. -- `pip install nilearn` now installs the necessary dependencies. - -**Lots of other fixes in documentation and examples.** More detailed change list follows: - -0.6.0rc -NEW ---- -.. warning:: - - - :func:`nilearn.plotting.view_connectome` no longer accepts old parameter names. - Instead of `coords`, `threshold`, `cmap`, and `marker_size`, - use `node_coords`, `edge_threshold`, `edge_cmap`, `node_size` respectively. - - - :func:`nilearn.plotting.view_markers` no longer accepts old parameter names. - Instead of `coord` and `color`, use `marker_coords` and `marker_color` respectively. - - -- **Support for Python3.5 will be removed in the 0.7.x release.** - Users with a Python3.5 environment will be warned - at their first Nilearn import. - -Changes -------- - -- Add a warning to :class:`nilearn.regions.Parcellations` - if the generated number of parcels does not match the requested number - of parcels. -- Class :class:`nilearn.maskers.NiftiLabelsMasker` now accepts an optional - `strategy` parameter which allows it to change the function used to reduce - values within each labelled ROI. Available functions include mean, median, - minimum, maximum, standard_deviation and variance. - This change is also introduced in :func:`nilearn.regions.img_to_signals_labels`. - -Fixes ------ - -- :class:`nilearn.maskers.NiftiLabelsMasker` no longer truncates region means to their integral part - when input images are of integer type. -- :func: `nilearn.image.smooth_image` no longer fails if `fwhm` is a `numpy.ndarray`. -- `pip install nilearn` now installs the necessary dependencies. -- :func:`nilearn.image.new_img_like` no longer attempts to copy non-iterable headers. (PR #2212) -- Nilearn no longer raises ImportError for nose when Matplotlib is not installed. -- The arg `version='det'` in :func:`nilearn.datasets.fetch_atlas_pauli_2017` now works as expected. -- :func:`nilearn.maskers.NiftiLabelsMasker.inverse_transform` now works without the need to call - transform first. - -Contributors ------------- - -The following people contributed to this release (in alphabetical order):: - - Chris Markiewicz - Dan Gale - Daniel Gomez - Derek Pisner - Elizabeth DuPre - Eric Larson - Gael Varoquaux - Jerome Dockes - JohannesWiesner - Kshitij Chawla (kchawla-pi) - Paula Sanz-Leon - ltetrel - ryanhammonds - - -0.6.0b0 -======= - -**Released November 2019** - - -.. warning:: - - | **Python2 and 3.4 are no longer supported. Pip will raise an error in these environments.** - | **Minimum supported version of Python is now 3.5 .** - | **We recommend upgrading to Python 3.6 .** - - -NEW ---- - -- A new function :func:`nilearn.image.get_data` to replace the deprecated - nibabel method `Nifti1Image.get_data`. Now use `nilearn.image.get_data(img)` - rather than `img.get_data()`. This is because Nibabel is removing the - `get_data` method. You may also consider using the Nibabel - `Nifti1Image.get_fdata`, which returns the data cast to floating-point. - See https://github.com/nipy/nibabel/wiki/BIAP8 . - As a benefit, the `get_data` function works on niimg-like objects such as - filenames (see http://nilearn.github.io/manipulating_images/input_output.html ). - -Changes -------- - -- All functions and examples now use `nilearn.image.get_data` rather than the - deprecated method `nibabel.Nifti1Image.get_data`. - -- :func:`nilearn.datasets.fetch_neurovault` now does not filter out images that - have their metadata field `is_valid` cleared by default. - -- Users can now specify fetching data for adults, children, or both from - :func:`nilearn.datasets.fetch_development_fmri` . - - -Fixes ------ - -- :func:`nilearn.plotting.plot_connectome` now correctly displays marker size on 'l' - and 'r' orientations, if an array or a list is passed to the function. - -Contributors ------------- - -The following people contributed to this release (in alphabetical order):: - - Jake Vogel - Jerome Dockes - Kshitij Chawla (kchawla-pi) - Roberto Guidotti - -0.6.0a0 -======= - -**Released October 2019** - -NEW ---- - -.. warning:: - - | **Python2 and 3.4 are no longer supported. We recommend upgrading to Python 3.6 minimum.** - | - | **Minimum supported versions of packages have been bumped up.** - | - Matplotlib -- v2.0 - | - Scikit-learn -- v0.19 - | - Scipy -- v0.19 - -- A new method for :class:`nilearn.maskers.NiftiMasker` instances - for generating reports viewable in a web browser, Jupyter Notebook, or VSCode. - -- joblib is now a dependency - -- Parcellation method ReNA: Fast agglomerative clustering based on recursive - nearest neighbor grouping. - Yields very fast & accurate models, without creation of giant - clusters. - :class:`nilearn.regions.ReNA` -- Plot connectome strength - Use function ``nilearn.plotting.plot_connectome_strength`` to plot the strength of a - connectome on a glass brain. Strength is absolute sum of the edges at a node. -- Optimization to image resampling - :func:`nilearn.image.resample_img` has been optimized to pad rather than - resample images in the special case when there is only a translation - between two spaces. This is a common case in :class:`nilearn.maskers.NiftiMasker` - when using the `mask_strategy="template"` option for brains in MNI space. -- New brain development fMRI dataset fetcher - :func:`nilearn.datasets.fetch_development_fmri` can be used to download - movie-watching data in children and adults; a light-weight dataset - implemented for teaching and usage in the examples. -- New example in `examples/05_advanced/plot_age_group_prediction_cross_val.py` - to compare methods for classifying subjects into age groups based on - functional connectivity. Similar example in - `examples/03_connectivity/plot_group_level_connectivity.py` simplified. - -- Merged `examples/03_connectivity/plot_adhd_spheres.py` and - `examples/03_connectivity/plot_sphere_based_connectome.py` to remove - duplication across examples. The improved - `examples/03_connectivity/plot_sphere_based_connectome.py` contains - concepts previously reviewed in both examples. -- Merged `examples/03_connectivity/plot_compare_decomposition.py` - and `examples/03_connectivity/plot_canica_analysis.py` into an improved - `examples/03_connectivity/plot_compare_decomposition.py`. - -- The Localizer dataset now follows the :term:`BIDS` organization. - -Changes -------- - -- All the connectivity examples are changed from ADHD to brain development - fmri dataset. -- Examples plot_decoding_tutorial, plot_haxby_decoder, - plot_haxby_different_estimators, plot_haxby_full_analysis, plot_oasis_vbm now - use :class:`nilearn.decoding.Decoder` and :class:`nilearn.decoding.DecoderRegressor` - instead of sklearn SVC and SVR. - -- :func:`nilearn.plotting.view_img_on_surf`, :func:`nilearn.plotting.view_surf` - and :func:`nilearn.plotting.view_connectome` now allow disabling the colorbar, - and setting its height and the fontsize of its ticklabels. - -- :func:`nilearn.plotting.view_img_on_surf`, :func:`nilearn.plotting.view_surf` - and :func:`nilearn.plotting.view_connectome` can now display a title. - -- Rework of the standardize-options of :func:`nilearn.signal.clean` and the various Maskers - in `nilearn.maskers`. You can now set `standardize` to `zscore` or `psc`. `psc` stands - for `Percent Signal Change`, which can be a meaningful metric for BOLD. - -- :func:`nilearn.plotting.plot_img` now has explicit keyword arguments `bg_img`, - `vmin` and `vmax` to control the background image and the bounds of the - colormap. These arguments were already accepted in `kwargs` but not documented - before. - -- :func:`nilearn.plotting.view_connectome` now converts NaNs in the adjacency - matrix to 0. - -- Removed the plotting connectomes example which used the Seitzman atlas - from `examples/03_connectivity/plot_sphere_based_connectome.py`. - The atlas data is unsuitable for the method & the example is redundant. - -Fixes ------ - -- :func:`nilearn.plotting.plot_glass_brain` with colorbar=True does not crash when - images have NaNs. -- add_contours now accepts `threshold` argument for filled=False. Now - `threshold` is equally applied when asked for fillings in the contours. -- :func:`nilearn.plotting.plot_surf` and - :func:`nilearn.plotting.plot_surf_stat_map` no longer threshold zero values - when no threshold is given. -- When :func:`nilearn.plotting.plot_surf_stat_map` is used with a thresholded map - but without a background map, the surface mesh is displayed in - half-transparent grey to maintain a 3D perception. -- :func:`nilearn.plotting.view_surf` now accepts surface data provided as a file - path. -- :func:`nilearn.plotting.plot_glass_brain` now correctly displays the left 'l' orientation even when - the given images are completely masked (empty images). -- :func:`nilearn.plotting.plot_matrix` providing labels=None, False, or an empty list now correctly disables labels. -- :func:`nilearn.plotting.plot_surf_roi` now takes vmin, vmax parameters -- :func:`nilearn.datasets.fetch_surf_nki_enhanced` is now downloading the correct - left and right functional surface data for each subject -- :func:`nilearn.datasets.fetch_atlas_schaefer_2018` now downloads from release - version 0.14.3 (instead of 0.8.1) by default, which includes corrected region label - names along with 700 and 900 region parcelations. -- Colormap creation functions have been updated to avoid matplotlib deprecation warnings - about colormap reversal. -- Neurovault fetcher no longer fails if unable to update dataset metadata file due to faulty permissions. - -Contributors ------------- - -The following people contributed to this release (in alphabetical order):: - - Alexandre Abraham - Alexandre Gramfort - Ana Luisa - Ana Luisa Pinho - Andrés Hoyos Idrobo - Antoine Grigis - BAZEILLE Thomas - Bertrand Thirion - Colin Reininger - Céline Delettre - Dan Gale - Daniel Gomez - Elizabeth DuPre - Eric Larson - Franz Liem - Gael Varoquaux - Gilles de Hollander - Greg Kiar - Guillaume Lemaitre - Ian Abenes - Jake Vogel - Jerome Dockes - Jerome-Alexis Chevalier - Julia Huntenburg - Kamalakar Daddy - Kshitij Chawla (kchawla-pi) - Mehdi Rahim - Moritz Boos - Sylvain Takerkart - -0.5.2 -===== - -**Released April 2019** - -NEW ---- - -.. warning:: - - | This is the **last** release supporting Python2 and 3.4 . - | The lowest Python version supported is now Python3.5. - | We recommend switching to Python3.6 . - -Fixes ------ - -- Plotting ``.mgz`` files in MNE broke in ``0.5.1`` and has been fixed. - -Contributors ------------- - -The following people contributed to this release:: - - 11 Kshitij Chawla (kchawla-pi) - 3 Gael Varoquaux - 2 Alexandre Gramfort - -0.5.1 -===== - -**Released April 2019** - -NEW ---- -- **Support for Python2 & Python3.4 will be removed in the next release.** - We recommend Python 3.6 and up. - Users with a Python2 or Python3.4 environment will be warned - at their first Nilearn import. - -- Calculate image data dtype from header information -- New display mode 'tiled' which allows 2x2 plot arrangement when plotting three cuts - (see :ref:`plotting`). -- NiftiLabelsMasker now consumes less memory when extracting the signal from a 3D/4D - image. This is especially noteworthy when extracting signals from large 4D images. -- New function :func:`nilearn.datasets.fetch_atlas_schaefer_2018` -- New function :func:`nilearn.datasets.fetch_coords_seitzman_2018` - -Changes -------- - -- Lighting used for interactive surface plots changed; plots may look a bit - different. -- :func:`nilearn.plotting.view_connectome` default colormap is `bwr`, consistent with plot_connectome. -- :func:`nilearn.plotting.view_connectome` parameter names are consistent with plot_connectome: - - - coords is now node_coord - - marker_size is now node_size - - cmap is now edge_cmap - - threshold is now edge_threshold - -- :func:`nilearn.plotting.view_markers` and :func:`nilearn.plotting.view_connectome` can accept different marker - sizes for each node / marker. - -- :func:`nilearn.plotting.view_markers()` default marker color is now 'red', consistent with add_markers(). -- :func:`nilearn.plotting.view_markers` parameter names are consistent with add_markers(): - - - coords is now marker_coords - - colors is now marker_color - -- :func:`nilearn.plotting.view_img_on_surf` now accepts a `symmetric_cmap` - argument to control whether the colormap is centered around 0 and a `vmin` - argument. - -- Users can now control the size and fontsize of colorbars in interactive - surface and connectome plots, or disable the colorbar. - -Fixes ------ - -- Example plot_seed_to_voxel_correlation now really saves z-transformed maps. -- region_extractor.connected_regions and regions.RegionExtractor now correctly - use the provided mask_img. -- load_niimg no longer drops header if dtype is changed. -- NiftiSpheresMasker no longer silently ignores voxels if no `mask_img` is specified. -- Interactive brainsprites generated from `view_img` are correctly rendered in Jupyter Book. - -Known Issues -------------------- - -- On Python2, :func:`nilearn.plotting.view_connectome()` & - :func:`nilearn.plotting.view_markers()` - do not show parameters names in function signature - when using help() and similar features. - Please refer to their docstrings for this information. -- Plotting ``.mgz`` files in MNE is broken. - -Contributors ------------- - -The following people contributed to this release:: - - 2 Bertrand Thirion - 90 Kshitij Chawla (kchawla-pi) - 22 fliem - 16 Jerome Dockes - 11 Gael Varoquaux - 8 Salma Bougacha - 7 himanshupathak21061998 - 2 Elizabeth DuPre - 1 Eric Larson - 1 Pierre Bellec - -0.5.0 -===== - -**Released November 2018** - -NEW ---- - - :ref:`interactive plotting functions `, - eg for use in a notebook. - -- New functions :func:`nilearn.plotting.view_surf` and - :func:`nilearn.plotting.view_img_on_surf` for interactive visualization of - maps on the cortical surface in a web browser. - -- New functions :func:`nilearn.plotting.view_connectome` and - :func:`nilearn.plotting.view_markers` for interactive visualization of - connectomes and seed locations in 3D - -- New function :func:`nilearn.plotting.view_img` for interactive - visualization of volumes with 3 orthogonal cuts. - -:Note: :func:`nilearn.plotting.view_img` was `nilearn.plotting.view_stat_map` in alpha and beta releases. - -- :func:`nilearn.plotting.find_parcellation_cut_coords` for - extraction of coordinates on brain parcellations denoted as labels. - -- Added :func:`nilearn.plotting.find_probabilistic_atlas_cut_coords` for - extraction of coordinates on brain probabilistic maps. - - -**Minimum supported versions of packages have been bumped up.** - - scikit-learn -- v0.18 - - scipy -- v0.17 - - pandas -- v0.18 - - numpy -- v1.11 - - matplotlib -- v1.5.1 - -**Nilearn Python2 support is being removed in the near future.** - Users with a Python2 environment will be warned - at their first Nilearn import. - -**Additional dataset downloaders for examples and tutorials.** - -- :func:`nilearn.datasets.fetch_surf_fsaverage` -- :func:`nilearn.datasets.fetch_atlas_pauli_2017` -- :func:`nilearn.datasets.fetch_neurovault_auditory_computation_task` -- :func:`nilearn.datasets.fetch_neurovault_motor_task` - - -ENHANCEMENTS ------------- - - :func:`nilearn.image.clean_img` now accepts a mask to restrict - the cleaning of the image, reducing memory load and computation time. - - NiftiMaskers now have a `dtype` parameter, by default keeping the same data type as the input data. - - Displays by plotting functions can now add a scale bar (see :ref:`plotting`) - - -IMPROVEMENTS ------------- - - - Lots of other fixes in documentation and examples. - - A cleaner layout and improved navigation for the website, with a better introduction. - - Dataset fetchers are now more reliable, less verbose. - - Searchlight().fit() now accepts 4D niimgs. - - Anaconda link in the installation documentation updated. - - Scipy is listed as a dependency for Nilearn installation. - -Notable Changes ---------------- - - Default value of `t_r` in :func:`nilearn.signal.clean` and - :func:`nilearn.image.clean_img` is None - and cannot be None if `low_pass` or `high_pass` is specified. - -Lots of changes and improvements. Detailed change list for each release follows. - -0.5.0 rc -======== - -Highlights ----------- - -:func:`nilearn.plotting.view_img` (formerly `nilearn.plotting.view_stat_map` in -Nilearn 0.5.0 pre-release versions) generates significantly smaller notebooks -and HTML pages while getting a more consistent look and feel with Nilearn's -plotting functions. Huge shout out to Pierre Bellec (pbellec) for -making a great feature awesome and for sportingly accommodating all our feedback. - -:func:`nilearn.image.clean_img` now accepts a mask to restrict the cleaning of - the image. This approach can help to reduce the memory load and computation time. - Big thanks to Michael Notter (miykael). - -Enhancements ------------- - -- :func:`nilearn.plotting.view_img` is now using the brainsprite.js library, - which results in much smaller notebooks or html pages. The interactive viewer - also looks more similar to the plots generated by - :func:`nilearn.plotting.plot_stat_map`, and most parameters found in - `plot_stat_map` are now supported in `view_img`. -- :func:`nilearn.image.clean_img` now accepts a mask to restrict the cleaning of - the image. This approach can help to reduce the memory load and computation time. -- :func:`nilearn.decoding.SpaceNetRegressor.fit` raises a meaningful error in regression tasks - if the target Y contains all 1s. - -Changes -------- - -- Default value of `t_r` in :func:`nilearn.signal.clean` and - :func:`nilearn.image.clean_img` is changed from 2.5 to None. If `low_pass` or - `high_pass` is specified, then `t_r` needs to be specified as well otherwise - it will raise an error. -- Order of filters in :func:`nilearn.signal.clean` and :func:`nilearn.image.clean_img` - has changed to detrend, low- and high-pass filter, remove confounds and - standardize. To ensure orthogonality between temporal filter and confound - removal, an additional temporal filter will be applied on the confounds before - removing them. This is according to Lindquist et al. (2018). -- :func:`nilearn.image.clean_img` now accepts a mask to restrict the cleaning of - the image. This approach can help to reduce the memory load and computation time. -- :func:`nilearn.plotting.view_img` is now using the brainsprite.js library, - which results in much smaller notebooks or html pages. The interactive viewer - also looks more similar to the plots generated by - :func:`nilearn.plotting.plot_stat_map`, and most parameters found in - `plot_stat_map` are now supported in `view_img`. - - -Contributors -------------- - -The following people contributed to this release:: - - 15 Gael Varoquaux - 114 Pierre Bellec - 30 Michael Notter - 28 Kshitij Chawla (kchawla-pi) - 4 Kamalakar Daddy - 4 himanshupathak21061998 - 1 Horea Christian - 7 Jerome Dockes - -0.5.0 beta -========== - -Highlights ----------- - -**Nilearn Python2 support is being removed in the near future. -Users with a Python2 environment will be warned at their first Nilearn import.** - -Enhancements ------------- - -Displays created by plotting functions can now add a scale bar - to indicate the size in mm or cm (see :ref:`plotting`), - contributed by Oscar Esteban - -Colorbars in plotting functions now have a middle gray background - suitable for use with custom colormaps with a non-unity alpha channel. - Contributed by Eric Larson (larsoner) - -Loads of fixes and quality of life improvements - -- A cleaner layout and improved navigation for the website, with a better introduction. -- Less warnings and verbosity while using certain functions and during dataset downloads. -- Improved backend for the dataset fetchers means more reliable dataset downloads. -- Some datasets, such as the ICBM, are now compressed to take up less disk space. - - -Fixes ------ - -- Searchlight().fit() now accepts 4D niimgs. Contributed by Dan Gale (danjgale). -- plotting.view_markers.open_in_browser() in js_plotting_utils fixed -- Brainomics dataset has been replaced in several examples. -- Lots of other fixes in documentation and examples. - - -Changes -------- - -- In nilearn.regions.img_to_signals_labels, the See Also section in documentation now also points to NiftiLabelsMasker and NiftiMapsMasker -- Scipy is listed as a dependency for Nilearn installation. -- Anaconda link in the installation documentation updated. - -Contributors -------------- - -The following people contributed to this release:: - - 58 Gael Varoquaux - 115 Kshitij Chawla (kchawla-pi) - 15 Jerome Dockes - 14 oesteban - 10 Eric Larson - 6 Kamalakar Daddy - 3 Bertrand Thirion - 5 Alexandre Abadie - 4 Sourav Singh - 3 Alex Rothberg - 3 AnaLu - 3 Demian Wassermann - 3 Horea Christian - 3 Jason Gors - 3 Jean Remi King - 3 MADHYASTHA Meghana - 3 SRSteinkamp - 3 Simon Steinkamp - 3 jerome-alexis_chevalier - 3 salma - 3 sfvnMAC - 2 Akshay - 2 Daniel Gomez - 2 Guillaume Lemaitre - 2 Pierre Bellec - 2 arokem - 2 erramuzpe - 2 foucault - 2 jehane - 1 Sylvain LANNUZEL - 1 Aki Nikolaidis - 1 Christophe Bedetti - 1 Dan Gale - 1 Dillon Plunkett - 1 Dimitri Papadopoulos Orfanos - 1 Greg Operto - 1 Ivan Gonzalez - 1 Yaroslav Halchenko - 1 dtyulman - -0.5.0 alpha -=========== - -This is an alpha release: to download it, you need to explicitly ask for -the version number:: - - pip install nilearn==0.5.0a0 - -Highlights ----------- - - - **Minimum supported versions of packages have been bumped up.** - - scikit-learn -- v0.18 - - scipy -- v0.17 - - pandas -- v0.18 - - numpy -- v1.11 - - matplotlib -- v1.5.1 - - - New :ref:`interactive plotting functions `, - eg for use in a notebook. - -Enhancements ------------- - - - All NiftiMaskers now have a `dtype` argument. For now the default behaviour - is to keep the same data type as the input data. - - - Displays created by plotting functions can now add a scale bar to - indicate the size in mm or cm (see :ref:`plotting`), contributed by - Oscar Esteban - - - New functions :func:`nilearn.plotting.view_surf` and - :func:`nilearn.plotting.view_surf` and - :func:`nilearn.plotting.view_img_on_surf` for interactive visualization of - maps on the cortical surface in a web browser. - - - New functions :func:`nilearn.plotting.view_connectome` and - :func:`nilearn.plotting.view_markers` to visualize connectomes and - seed locations in 3D - - - New function `nilearn.plotting.view_stat_map` (renamed to - :func:`nilearn.plotting.view_img` in stable release) for interactive - visualization of volumes with 3 orthogonal cuts. - - - Add :func:`nilearn.datasets.fetch_surf_fsaverage` to download either - fsaverage or fsaverage 5 (Freesurfer cortical meshes). - - - Added :func:`nilearn.datasets.fetch_atlas_pauli_2017` to download a - recent subcortical neuroimaging atlas. - - - Added :func:`nilearn.plotting.find_parcellation_cut_coords` for - extraction of coordinates on brain parcellations denoted as labels. - - - Added :func:`nilearn.plotting.find_probabilistic_atlas_cut_coords` for - extraction of coordinates on brain probabilistic maps. - - - Added :func:`nilearn.datasets.fetch_neurovault_auditory_computation_task` - and :func:`nilearn.datasets.fetch_neurovault_motor_task` for simple example data. - -Changes -------- - - - `nilearn.datasets.fetch_surf_fsaverage5` is deprecated and will be - removed in a future release. Use :func:`nilearn.datasets.fetch_surf_fsaverage`, - with the parameter mesh="fsaverage5" (the default) instead. - - - fsaverage5 surface data files are now shipped directly with Nilearn. - Look to issue #1705 for discussion. - - - `sklearn.cross_validation` and `sklearn.grid_search` have been - replaced by `sklearn.model_selection` in all the examples. - - - Colorbars in plotting functions now have a middle gray background - suitable for use with custom colormaps with a non-unity alpha channel. - - -Contributors ------------- - -The following people contributed to this release:: - - 49 Gael Varoquaux - 180 Jerome Dockes - 57 Kshitij Chawla (kchawla-pi) - 38 SylvainLan - 36 Kamalakar Daddy - 10 Gilles de Hollander - 4 Bertrand Thirion - 4 MENUET Romuald - 3 Moritz Boos - 1 Peer Herholz - 1 Pierre Bellec - -0.4.2 -===== -Few important bugs fix release for OHBM conference. - -Changes -------- - - Default colormaps for surface plotting functions have changed to be more - consistent with slice plotting. - :func:`nilearn.plotting.plot_surf_stat_map` now uses "cold_hot", as - :func:`nilearn.plotting.plot_stat_map` does, and - :func:`nilearn.plotting.plot_surf_roi` now uses "gist_ncar", as - :func:`nilearn.plotting.plot_roi` does. - - - Improve 3D surface plotting: lock the aspect ratio of the plots and - reduce the whitespace around the plots. - -Bug fixes ---------- - - - Fix bug with input repetition time (TR) which had no effect in signal - cleaning. Fixed by Pradeep Raamana. - - - Fix issues with signal extraction on list of 3D images in - :class:`nilearn.regions.Parcellations`. - - - Fix issues with raising AttributeError rather than HTTPError in datasets - fetching utilities. By Jerome Dockes. - - - Fix issues in datasets testing function uncompression of files. By Pierre Glaser. - -0.4.1 -===== - -This bug fix release is focused on few bug fixes and minor developments. - -Enhancements ------------- - - - :class:`nilearn.decomposition.CanICA` and - :class:`nilearn.decomposition.DictLearning` has new attribute - `components_img_` providing directly the components learned as - a Nifti image. This avoids the step of unmasking the attribute - `components_` which is true for older versions. - - - New object :class:`nilearn.regions.Parcellations` for learning brain - parcellations on fmri data. - - - Add optional reordering of the matrix using a argument `reorder` - with :func:`nilearn.plotting.plot_matrix`. - - .. note:: - This feature is usable only if SciPy version is >= 1.0.0 - -Changes -------- - - - Using output attribute `components_` which is an extracted components - in :class:`nilearn.decomposition.CanICA` and - :class:`nilearn.decomposition.DictLearning` is deprecated and will - be removed in next two releases. Use `components_img_` instead. - -Bug fixes ---------- - - - Fix issues using :func:`nilearn.plotting.plot_connectome` when string is - passed in `node_color` with display modes left and right hemispheric cuts - in the glass brain. - - - Fix bug while plotting only coordinates using add_markers on glass brain. - See issue #1595 - - - Fix issues with estimators in decomposition module when input images are - given in glob patterns. - - - Fix bug loading Nifti2Images. - - - Fix bug while adjusting contrast of the background template while using - :func:`nilearn.plotting.plot_prob_atlas` - - - Fix colormap bug with recent matplotlib 2.2.0 - -0.4.0 -===== - -**Highlights**: - - - :func:`nilearn.surface.vol_to_surf` to project volume data to the - surface. - - - :func:`nilearn.plotting.plot_matrix` to display matrices, eg connectomes - -Enhancements -------------- - - - New function :func:`nilearn.surface.vol_to_surf` to project a 3d or - 4d brain volume on the cortical surface. - - - New matrix plotting function, eg to display connectome matrices: - :func:`nilearn.plotting.plot_matrix` - - - Expose :func:`nilearn.image.coord_transform` for end users. Useful - to transform coordinates (x, y, z) from one image space to - another space. - - - :func:`nilearn.image.resample_img` now takes a linear resampling - option (implemented by Joe Necus) - - - :func:`nilearn.datasets.fetch_atlas_talairach` to fetch the Talairach - atlas (http://talairach.org) - - - Enhancing new surface plotting functions, added new parameters - "axes" and "figure" to accept user-specified instances in - :func:`nilearn.plotting.plot_surf` and - :func:`nilearn.plotting.plot_surf_stat_map` and - :func:`nilearn.plotting.plot_surf_roi` - - - :class:`nilearn.decoding.SearchLight` has new parameter "groups" to - do LeaveOneGroupOut type cv with new scikit-learn module model selection. - - - Enhancing the glass brain plotting in back view 'y' direction. - - - New parameter "resampling_interpolation" is added in most used - plotting functions to have user control for faster visualizations. - - - Upgraded to Sphinx-Gallery 0.1.11 - -Bug fixes ----------- - - - Dimming factor applied to background image in plotting - functions with "dim" parameter will no longer accepts as - string ('-1'). An error will be raised. - - - Fixed issues with matplotlib 2.1.0. - - - Fixed issues with SciPy 1.0.0. - -Changes ---------- - - - **Backward incompatible change**: :func:`nilearn.plotting.find_xyz_cut_coords` - now takes a `mask_img` argument which is a niimg, rather than a `mask` - argument, which used to be a numpy array. - - - The minimum required version for scipy is now 0.14 - - - Dropped support for Nibabel older than 2.0.2. - - - :func:`nilearn.image.smooth_img` no longer accepts smoothing - parameter fwhm as 0. Behavior is changed in according to the - issues with recent SciPy version 1.0.0. - - - "dim" factor range is slightly increased to -2 to 2 from -1 to 1. - Range exceeding -1 meaning more increase in contrast should be - cautiously set. - - - New 'anterior' and 'posterior' view added to the plot_surf family views - - - Using argument `anat_img` for placing background image in - :func:`nilearn.plotting.plot_prob_atlas` is deprecated. Use argument - `bg_img` instead. - - - The examples now use pandas for the behavioral information. - -Contributors -------------- - -The following people contributed to this release:: - - 127 Jerome Dockes - 62 Gael Varoquaux - 36 Kamalakar Daddy - 11 Jeff Chiang - 9 Elizabeth DuPre - 9 Jona Sassenhagen - 7 Sylvain Lan - 6 J Necus - 5 Pierre-Olivier Quirion - 3 AnaLu - 3 Jean Remi King - 3 MADHYASTHA Meghana - 3 Salma Bougacha - 3 sfvnMAC - 2 Eric Larson - 2 Horea Christian - 2 Moritz Boos - 1 Alex Rothberg - 1 Bertrand Thirion - 1 Christophe Bedetti - 1 John Griffiths - 1 Mehdi Rahim - 1 Sylvain LANNUZEL - 1 Yaroslav Halchenko - 1 clfs - - -0.3.1 -===== - -This is a minor release for BrainHack. - -Highlights ----------- - -* **Dropped support for scikit-learn older than 0.14.1** Minimum supported version - is now 0.15. - -Changelog ---------- - - - The function sym_to_vec is deprecated and will be removed in - release 0.4. Use :func:`nilearn.connectome.sym_matrix_to_vec` instead. - - - Added argument `smoothing_fwhm` to - :class:`nilearn.regions.RegionExtractor` to control smoothing according - to the resolution of atlas images. - -Bug fix -------- - - - The helper function `largest_connected_component` should now work with - inputs of non-native data dtypes. - - - Fix plotting issues when non-finite values are present in background - anatomical image. - - - A workaround to handle non-native endianness in the Nifti images passed - to resampling the image. - -Enhancements -------------- - - New data fetcher functions :func:`nilearn.datasets.fetch_neurovault` and - :func:`nilearn.datasets.fetch_neurovault_ids` help you download - statistical maps from the Neurovault (http://neurovault.org) platform. - - - New function :func:`nilearn.connectome.vec_to_sym_matrix` reshapes - vectors to symmetric matrices. It acts as the reverse of function - :func:`nilearn.connectome.sym_matrix_to_vec`. - - - Add an option allowing to vectorize connectivity matrices returned by the - "transform" method of :class:`nilearn.connectome.ConnectivityMeasure`. - - - :class:`nilearn.connectome.ConnectivityMeasure` now exposes an - "inverse_transform" method, useful for going back from vectorized - connectivity coefficients to connectivity matrices. Also, it allows to - recover the covariance matrices for the "tangent" kind. - - - Reworking and renaming of connectivity measures example. Renamed from - plot_connectivity_measures to plot_group_level_connectivity. - - - Tighter bounding boxes when using add_contours for plotting. - - - Function :func:`nilearn.image.largest_connected_component_img` to - directly extract the largest connected component from Nifti images. - - - Improvements in plotting, decoding and functional connectivity examples. - -0.3.0 -====== - -In addition, more details of this release are listed below. Please checkout -in **0.3.0 beta** release section for minimum version support of dependencies, -latest updates, highlights, changelog and enhancements. - -Changelog ---------- - - - Function :func:`nilearn.plotting.find_cut_slices` now supports to accept - Nifti1Image as an input for argument `img`. - - - Helper functions `_get_mask_volume` and `_adjust_screening_percentile` - are now moved to param_validation file in utilities module to be used in - common with Decoder object. - -Bug fix --------- - - - Fix bug uncompressing tar files with datasets fetcher. - - - Fixed bunch of CircleCI documentation build failures. - - - Fixed deprecations `set_axis_bgcolor` related to matplotlib in - plotting functions. - - - Fixed bug related to not accepting a list of arrays as an input to - unmask, in masking module. - -Enhancements -------------- - - - ANOVA SVM example on Haxby datasets `plot_haxby_anova_svm` in Decoding section - now uses `SelectPercentile` to select voxels rather than `SelectKBest`. - - - New function `fast_svd` implementation in base decomposition module to - Automatically switch between randomized and lapack SVD (heuristic - of scikit-learn). - -0.3.0 beta -=========== - -To install the beta version, use:: - - pip install --upgrade --pre nilearn - -Highlights ----------- - -* Simple surface plotting - -* A function to break a parcellation into its connected components - -* **Dropped support for scikit-learn older than 0.14.1** Minimum supported version - is now 0.14.1. - -* **Dropped support for Python 2.6** - -* Minimum required version of NiBabel is now 1.2.0, to support loading annotated - data with freesurfer. - -Changelog ---------- - - - A helper function _safe_get_data as a nilearn utility now safely - removes NAN values in the images with argument ensure_finite=True. - - - Connectome functions :func:`nilearn.connectome.cov_to_corr` and - :func:`nilearn.connectome.prec_to_partial` can now be used. - -Bug fix --------- - - - Fix colormap issue with colorbar=True when using qualitative colormaps - Fixed in according with changes of matplotlib 2.0 fixes. - - - Fix plotting functions to work with NAN values in the images. - - - Fix bug related get dtype of the images with nibabel get_data(). - - - Fix bug in nilearn clean_img - -Enhancements -............ - - - A new function :func:`nilearn.regions.connected_label_regions` to - extract the connected components represented as same label to regions - apart with each region labelled as unique label. - - - New plotting modules for surface plotting visualization. Matplotlib with - version higher 1.3.1 is required for plotting surface data using these - functions. - - - Function :func:`nilearn.plotting.plot_surf` can be used for plotting - surfaces mesh data with optional background. - - - A function :func:`nilearn.plotting.plot_surf_stat_map` can be used for - plotting statistical maps on a brain surface with optional background. - - - A function :func:`nilearn.plotting.plot_surf_roi` can be used for - plotting statistical maps rois onto brain surface. - - - A function `nilearn.datasets.fetch_surf_fsaverage5` can be used - for surface data object to be as background map for the above plotting - functions. - - - A new data fetcher function - :func:`nilearn.datasets.fetch_atlas_surf_destrieux` - can give you Destrieux et. al 2010 cortical atlas in fsaverage5 - surface space. - - - A new functional data fetcher function - :func:`nilearn.datasets.fetch_surf_nki_enhanced` gives you resting state - data preprocessed and projected to fsaverage5 surface space. - - - Two good examples in plotting gallery shows how to fetch atlas and NKI - data and used for plotting on brain surface. - - - Helper function `load_surf_mesh` in surf_plotting module for loading - surface mesh data into two arrays, containing (x, y, z) coordinates - for mesh vertices and indices of mesh faces. - - - Helper function `load_surf_data` in surf_plotting module for loading - data of numpy array to represented on a surface mesh. - - - Add fetcher for Allen et al. 2011 RSN atlas in - :func:`nilearn.datasets.fetch_atlas_allen_2011`. - - - A function ``nilearn.datasets.fetch_cobre`` is now updated to new - light release of COBRE data (schizophrenia) - - - A new example to show how to extract regions on labels image in example - section manipulating images. - - - coveralls is replaces with codecov - - - Upgraded to Sphinx version 0.1.7 - - - Extensive plotting example shows how to use contours and filled contours - on glass brain. - -0.2.6 -===== - -Changelog ---------- - -This release enhances usage of several functions by fine tuning their -parameters. It allows to select which Haxby subject to fetch. It also refactors -documentation to make it easier to understand. -Sphinx-gallery has been updated and nilearn is ready for new nibabel 2.1 version. -Several bugs related to masks in Searchlight and ABIDE fetching have been -resolved. - -Bug fix -........ - - - Change default dtype in :func:`nilearn.image.concat_imgs` to be the - original type of the data (see #1238). - - - Fix SearchLight that did not run without process_mask or with one voxel - mask. - - - Fix flipping of left hemisphere when plotting glass brain. - - - Fix bug when downloading ABIDE timeseries - -Enhancements -............ - - - Sphinx-gallery updated to version 0.1.3. - - - Refactoring of examples and documentation. - - - Better ordering of regions in - :func:`nilearn.datasets.fetch_coords_dosenbach_2010`. - - - Remove outdated power atlas example. - - -API changes summary -................... - - - The parameter 'n_subjects' is deprecated and will be removed in future - release. Use 'subjects' instead in :func:`nilearn.datasets.fetch_haxby`. - - - The function :func:`nilearn.datasets.fetch_haxby` will now fetch the - data accepting input given in 'subjects' as a list than integer. - - - Replace `get_affine` by `affine` with recent versions of nibabel. - -0.2.5.1 -======= - -Changelog ---------- - -This is a bugfix release. -The new minimum required version of scikit-learn is 0.14.1 - -API changes summary -................... - - - default option for `dim` argument in plotting functions which uses MNI - template as a background image is now changed to 'auto' mode. Meaning - that an automatic contrast setting on background image is applied by - default. - - - Scikit-learn validation tools have been imported and are now used to check - consistency of input data, in SpaceNet for example. - -New features -............ - - - Add an option to select only off-diagonal elements in sym_to_vec. Also, - the scaling of matrices is modified: we divide the diagonal by sqrt(2) - instead of multiplying the off-diagonal elements. - - - Connectivity examples rely on - :class:`nilearn.connectome.ConnectivityMeasure` - -Bug fix -........ - - - Scipy 0.18 introduces a bug in a corner-case of resampling. Nilearn - 0.2.5 can give wrong results with scipy 0.18, but this is fixed in - 0.2.6. - - - Broken links and references fixed in docs - -0.2.5 -===== - -Changelog ---------- - -The 0.2.5 release includes plotting for connectomes and glass brain with -hemisphere-specific projection, as well as more didactic examples and -improved documentation. - -New features -............ - - - New display_mode options in :func:`nilearn.plotting.plot_glass_brain` - and :func:`nilearn.plotting.plot_connectome`. It - is possible to plot right and left hemisphere projections separately. - - - A function to load canonical brain mask image in MNI template space, - :func:`nilearn.datasets.load_mni152_brain_mask` - - - A function to load brain grey matter mask image, - :func:`nilearn.datasets.fetch_icbm152_brain_gm_mask` - - - New function :func:`nilearn.image.load_img` loads data from a filename or a - list of filenames. - - - New function :func:`nilearn.image.clean_img` applies the cleaning function - :func:`nilearn.signal.clean` on all voxels. - - - New simple data downloader - :func:`nilearn.datasets.fetch_localizer_button_task` to simplify - some examples. - - - The dataset function - :func:`nilearn.datasets.fetch_localizer_contrasts` can now download - a specific list of subjects rather than a range of subjects. - - - New function :func:`nilearn.datasets.get_data_dirs` to check where - nilearn downloads data. - -Contributors -------------- - -Contributors (from ``git shortlog -ns 0.2.4..0.2.5``):: - - 55 Gael Varoquaux - 39 Alexandre Abraham - 26 Martin Perez-Guevara - 20 Kamalakar Daddy - 8 amadeuskanaan - 3 Alexandre Abadie - 3 Arthur Mensch - 3 Elvis Dohmatob - 3 Loïc Estève - 2 Jerome Dockes - 1 Alexandre M. S - 1 Bertrand Thirion - 1 Ivan Gonzalez - 1 robbisg - -0.2.4 -===== - -Changelog ---------- - -The 0.2.4 is a small release focused on documentation for teaching. - -New features -............ - - The path given to the "memory" argument of object now have their - "~" expanded to the homedir - - - Display object created by plotting now uniformly expose an - "add_markers" method. - - - plotting plot_connectome with colorbar is now implemented in function - :func:`nilearn.plotting.plot_connectome` - - - New function :func:`nilearn.image.resample_to_img` to resample one - img on another one (just resampling / interpolation, no - coregistration) - -API changes summary -................... - - Atlas fetcher :func:`nilearn.datasets.fetch_atlas_msdl` now returns directly - labels of the regions in output variable 'labels' and its coordinates - in output variable 'region_coords' and its type of network in 'networks'. - - The output variable name 'regions' is now changed to 'maps' in AAL atlas - fetcher in :func:`nilearn.datasets.fetch_atlas_aal`. - - AAL atlas now returns directly its labels in variable 'labels' and its - index values in variable 'indices'. - -0.2.3 -===== - -Changelog ---------- - -The 0.2.3 is a small feature release for BrainHack 2016. - -New features -............ - - Mathematical formulas based on numpy functions can be applied on an - image or a list of images using :func:`nilearn.image.math_img`. - - Downloader for COBRE datasets of 146 rest fMRI subjects with - function ``nilearn.datasets.fetch_cobre``. - - Downloader for Dosenbach atlas - :func:`nilearn.datasets.fetch_coords_dosenbach_2010` - - Fetcher for multiscale functional brain parcellations (BASC) - :func:`nilearn.datasets.fetch_atlas_basc_multiscale_2015` - -Bug fixes -......... - - Better dimming on white background for plotting - -0.2.2 -====== - -Changelog ---------- - -The 0.2.2 is a bugfix + dependency update release (for sphinx gallery). It -aims at preparing a renewal of the tutorials. - -New features -............ - - Fetcher for Megatrawl Netmats dataset. - -Enhancements -............ - - Flake8 is now run on pull requests. - - Reworking of the documentation organization. - - Sphinx-gallery updated to version 0.1.1 - - The default n_subjects=None in :func:`nilearn.datasets.fetch_adhd` is now - changed to n_subjects=30. - -Bug fixes -......... - - Fix `symmetric_split` behavior in - :func:`nilearn.datasets.fetch_atlas_harvard_oxford` - - Fix casting errors when providing integer data to - :func:`nilearn.image.high_variance_confounds` - - Fix matplotlib 1.5.0 compatibility in - :func:`nilearn.plotting.plot_prob_atlas` - - Fix matplotlib backend choice on Mac OS X. - - :func:`nilearn.plotting.find_xyz_cut_coords` raises a meaningful error - when 4D data is provided instead of 3D. - - :class:`nilearn.maskers.NiftiSpheresMasker` handles radius smaller than - the size of a voxel - - :class:`nilearn.regions.RegionExtractor` handles data containing Nans. - - Confound regression does not force systematically the normalization of - the confounds. - - Force time series normalization in - :class:`nilearn.connectome.ConnectivityMeasure` - and check dimensionality of the input. - - `nilearn._utils.numpy_conversions.csv_to_array` could consider - valid CSV files as invalid. - -API changes summary -................... - - Deprecated dataset downloading function have been removed. - - Download progression message refreshing rate has been lowered to sparsify - CircleCI logs. - -Contributors -............. - -Contributors (from ``git shortlog -ns 0.2.1..0.2.2``):: - - 39 Kamalakar Daddy - 22 Alexandre Abraham - 21 Loïc Estève - 19 Gael Varoquaux - 12 Alexandre Abadie - 7 Salma - 3 Danilo Bzdok - 1 Arthur Mensch - 1 Ben Cipollini - 1 Elvis Dohmatob - 1 Óscar Nájera - -0.2.1 -====== - -Changelog ---------- - -Small bugfix for more flexible input types (targetter in particular at -making code easier in nistats). - -0.2 -=== - -Changelog ---------- - -The new minimum required version of scikit-learn is 0.13 - -New features -............ - - The new module :mod:`nilearn.connectome` now has class - :class:`nilearn.connectome.ConnectivityMeasure` can be useful for - computing functional connectivity matrices. - - The function nilearn.connectome.sym_to_vec in same module - :mod:`nilearn.connectome` is also implemented as a helper function to - :class:`nilearn.connectome.ConnectivityMeasure`. - - The class :class:`nilearn.decomposition.DictLearning` in - :mod:`nilearn.decomposition` is a decomposition method similar to ICA - that imposes sparsity on components instead of independence between them. - - Integrating back references template from sphinx-gallery of 0.0.11 - version release. - - Globbing expressions can now be used in all nilearn functions expecting a - list of files. - - The new module :mod:`nilearn.regions` now has class - :class:`nilearn.regions.RegionExtractor` which can be used for post - processing brain regions of interest extraction. - - The function :func:`nilearn.regions.connected_regions` in - :mod:`nilearn.regions` is also implemented as a helper function to - :class:`nilearn.regions.RegionExtractor`. - - The function :func:`nilearn.image.threshold_img` in :mod:`nilearn.image` - is implemented to use it for thresholding statistical maps. - -Enhancements -............ - - Making website a bit elaborated & modernise by using sphinx-gallery. - - Documentation enhancement by integrating sphinx-gallery notebook style - examples. - - Documentation about :class:`nilearn.maskers.NiftiSpheresMasker`. - -Bug fixes -......... - - Fixed bug to control the behaviour when cut_coords=0. in function - :func:`nilearn.plotting.plot_stat_map` in :mod:`nilearn.plotting`. - See issue # 784. - - Fixed bug in :func:`nilearn.image.copy_img` occurred while caching - the Nifti images. See issue # 793. - - Fixed bug causing an IndexError in fast_abs_percentile. See issue # 875 - -API changes summary -................... - - The utilities in function group_sparse_covariance has been moved - into :mod:`nilearn.connectome`. - - The default value for number of cuts (n_cuts) in function - :func:`nilearn.plotting.find_cut_slices` in :mod:`nilearn.plotting` has - been changed from 12 to 7 i.e. n_cuts=7. - -Contributors -............. - -Contributors (from ``git shortlog -ns 0.1.4..0.2.0``):: - - 822 Elvis Dohmatob - 142 Gael Varoquaux - 119 Alexandre Abraham - 90 Loïc Estève - 85 Kamalakar Daddy - 65 Alexandre Abadie - 43 Chris Filo Gorgolewski - 39 Salma BOUGACHA - 29 Danilo Bzdok - 20 Martin Perez-Guevara - 19 Mehdi Rahim - 19 Óscar Nájera - 17 martin - 8 Arthur Mensch - 8 Ben Cipollini - 4 ainafp - 4 juhuntenburg - 2 Martin_Perez_Guevara - 2 Michael Hanke - 2 arokem - 1 Bertrand Thirion - 1 Dimitri Papadopoulos Orfanos - - -0.1.4 -===== - -Changelog ---------- - -Highlights: - -- NiftiSpheresMasker: extract signals from balls specified by their - coordinates -- Obey Debian packaging rules -- Add the Destrieux 2009 and Power 2011 atlas -- Better caching in maskers - - -Contributors (from ``git shortlog -ns 0.1.3..0.1.4``):: - - 141 Alexandre Abraham - 15 Gael Varoquaux - 10 Loïc Estève - 2 Arthur Mensch - 2 Danilo Bzdok - 2 Michael Hanke - 1 Mehdi Rahim - - -0.1.3 -===== - -Changelog ---------- - -The 0.1.3 release is a bugfix release that fixes a lot of minor bugs. It -also includes a full rewamp of the documentation, and support for Python -3. - -Minimum version of supported packages are now: - -- numpy 1.6.1 -- scipy 0.9.0 -- scikit-learn 0.12.1 -- Matplotlib 1.1.1 (optional) - -A non exhaustive list of issues fixed: - -- Dealing with NaNs in plot_connectome -- Fix extreme values in colorbar were sometimes brok -- Fix confounds removal with single confounds -- Fix frequency filtering -- Keep header information in images -- add_overlay finds vmin and vmax automatically -- vmin and vmax support in plot_connectome -- detrending 3D images no longer puts them to zero - - -Contributors (from ``git shortlog -ns 0.1.2..0.1.3``):: - - 129 Alexandre Abraham - 67 Loïc Estève - 57 Gael Varoquaux - 44 Ben Cipollini - 37 Danilo Bzdok - 20 Elvis Dohmatob - 14 Óscar Nájera - 9 Salma BOUGACHA - 8 Alexandre Gramfort - 7 Kamalakar Daddy - 3 Demian Wassermann - 1 Bertrand Thirion - -0.1.2 -===== - -Changelog ---------- - -The 0.1.2 release is a bugfix release, specifically to fix the -NiftiMapsMasker. - -0.1.1 -===== - -Changelog ---------- - -The main change compared to 0.1 is the addition of connectome plotting -via the nilearn.plotting.plot_connectome function. See the -`plotting documentation `_ -for more details. - -Contributors (from ``git shortlog -ns 0.1..0.1.1``):: - - 81 Loïc Estève - 18 Alexandre Abraham - 18 Danilo Bzdok - 14 Ben Cipollini - 2 Gaël Varoquaux - - -0.1 -=== - -Changelog ---------- -First release of nilearn. - -Contributors (from ``git shortlog -ns 0.1``):: - - 600 Gaël Varoquaux - 483 Alexandre Abraham - 302 Loïc Estève - 254 Philippe Gervais - 122 Virgile Fritsch - 83 Michael Eickenberg - 59 Jean Kossaifi - 57 Jaques Grobler - 46 Danilo Bzdok - 35 Chris Filo Gorgolewski - 28 Ronald Phlypo - 25 Ben Cipollini - 15 Bertrand Thirion - 13 Alexandre Gramfort - 12 Fabian Pedregosa - 11 Yannick Schwartz - 9 Mehdi Rahim - 7 Óscar Nájera - 6 Elvis Dohmatob - 4 Konstantin Shmelkov - 3 Jason Gors - 3 Salma Bougacha - 1 Alexandre Savio - 1 Jan Margeta - 1 Matthias Ekman - 1 Michael Waskom - 1 Vincent Michel From 26de3fe3515ce387f91be66f84277e7bd11978e0 Mon Sep 17 00:00:00 2001 From: Gensollen Date: Thu, 27 Jan 2022 10:28:55 +0100 Subject: [PATCH 37/44] [MAINT] Bump dependencies for release `0.9.0` (#3143) * bump dependencies * [circle full] Add whatsnew. --- README.rst | 10 +++++----- doc/changes/latest.rst | 15 +++++++++++++++ requirements-min.txt | 10 +++++----- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 6e93fbf9be..987513776c 100644 --- a/README.rst +++ b/README.rst @@ -46,12 +46,12 @@ The required dependencies to use the software are: * Python >= 3.6 * setuptools -* Numpy >= 1.16 -* SciPy >= 1.2 -* Scikit-learn >= 0.21 -* Joblib >= 0.12 +* Numpy >= 1.18 +* SciPy >= 1.5 +* Scikit-learn >= 0.22 +* Joblib >= 0.15 * Nibabel >= 3.0 -* Pandas >= 0.24 +* Pandas >= 1.0 If you are using nilearn plotting functionalities or running the examples, matplotlib >= 1.5.1 is required. diff --git a/doc/changes/latest.rst b/doc/changes/latest.rst index 747c38806f..2ae6f63079 100644 --- a/doc/changes/latest.rst +++ b/doc/changes/latest.rst @@ -6,6 +6,21 @@ 0.8.2.dev ========= +.. warning:: + + | **Python 3.6 is deprecated and will be removed in release 0.10.** + | **We recommend upgrading to Python 3.9.** + | + | **Nibabel 2.x is no longer supported. Please consider upgrading to Nibabel >= 3.0.** + | + | **Minimum supported versions of packages have been bumped up:** + | - Numpy -- v1.18 + | - SciPy -- v1.5 + | - Scikit-learn -- v0.22 + | - Pandas -- v1.0 + | - Joblib -- v0.15 + + NEW --- diff --git a/requirements-min.txt b/requirements-min.txt index 230fff9b8e..58b156c27d 100644 --- a/requirements-min.txt +++ b/requirements-min.txt @@ -1,8 +1,8 @@ -numpy==1.16 -scipy==1.2.0 -pandas==0.24.0 -scikit-learn==0.21.0 -joblib==0.12 +numpy==1.18 +scipy==1.5 +pandas==1.0 +scikit-learn==0.22 +joblib==0.15 nibabel==3.0.0 pytest pytest-cov From 55db108e533fa0771fd4677e9fc15a27409bddb2 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Thu, 27 Jan 2022 12:05:20 +0100 Subject: [PATCH 38/44] Jerome's review --- nilearn/datasets/struct.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/nilearn/datasets/struct.py b/nilearn/datasets/struct.py index 19dbd112fc..6fdf3a3f1c 100644 --- a/nilearn/datasets/struct.py +++ b/nilearn/datasets/struct.py @@ -752,10 +752,7 @@ def fetch_oasis_vbm(n_subjects=None, dartel_version=True, data_dir=None, for subject_id in csv_data['ID']]) csv_data = csv_data[subject_mask] csv_data = csv_data.rename( - columns={c: c.lower() for c in csv_data.columns} - ) - csv_data = csv_data.rename( - columns={c: c.replace("/", "") for c in csv_data.columns} + columns={c: c.lower().replace("/", "") for c in csv_data.columns} ) fdescr = _get_dataset_descr(dataset_name) From fb5c56b8388c2deee0702f47ad5588c6c3af6e89 Mon Sep 17 00:00:00 2001 From: NicolasGensollen Date: Thu, 27 Jan 2022 12:05:58 +0100 Subject: [PATCH 39/44] remove warning --- nilearn/datasets/__init__.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nilearn/datasets/__init__.py b/nilearn/datasets/__init__.py index 19ee5000c3..64ad875b81 100644 --- a/nilearn/datasets/__init__.py +++ b/nilearn/datasets/__init__.py @@ -2,7 +2,6 @@ Helper functions to download NeuroImaging datasets """ -from warnings import warn from .struct import (fetch_icbm152_2009, load_mni152_template, load_mni152_brain_mask, load_mni152_gm_template, load_mni152_gm_mask, load_mni152_wm_template, @@ -90,7 +89,3 @@ 'fetch_fiac_first_level', ] -warn("Fetchers from the nilearn.datasets module will be " - "updated in version 0.9 to return python strings " - "instead of bytes and Pandas dataframes instead of " - "Numpy arrays.", FutureWarning) From 27e00f0678b7601b2153fbf5dc3c638177a03aeb Mon Sep 17 00:00:00 2001 From: Gensollen Date: Thu, 27 Jan 2022 15:27:08 +0100 Subject: [PATCH 40/44] [INFRA] Add tests min requirements with Matplotlib (#3144) * Add tests min req with matplotlib * remove useless variable * [circle full] update README --- .github/workflows/testing.yml | 30 ++++++++++++++++++++++++++++++ README.rst | 3 +-- build_tools/github/dependencies.sh | 3 +++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index ba824881a8..4dfc70cc7c 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -55,6 +55,36 @@ jobs: if: success() name: 'Upload coverage to CodeCov' + min_requirements_matplotlib: + needs: check_skip + if: ${{ needs.check_skip.outputs.skip == 'false' }} + runs-on: "ubuntu-latest" + name: Python 3.6, minimal requirements with Matplotlib + defaults: + run: + shell: bash + env: + MIN_REQUIREMENTS: true + MATPLOTLIB: true + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.6 + name: 'Setup python' + - shell: bash -l {0} + name: 'Display Python version' + run: python -c "import sys; print(sys.version)" + - shell: bash -l {0} + run: ./build_tools/github/dependencies.sh + name: 'Install dependencies' + - shell: bash -l {0} + run: ./build_tools/github/install.sh + name: 'Install nilearn' + - shell: bash -l {0} + run: ./build_tools/github/test.sh + name: 'Run tests' + latest: needs: check_skip if: ${{ needs.check_skip.outputs.skip == 'false' }} diff --git a/README.rst b/README.rst index 987513776c..6acd514a72 100644 --- a/README.rst +++ b/README.rst @@ -53,8 +53,7 @@ The required dependencies to use the software are: * Nibabel >= 3.0 * Pandas >= 1.0 -If you are using nilearn plotting functionalities or running the -examples, matplotlib >= 1.5.1 is required. +If you are using nilearn plotting functionalities or running the examples, matplotlib >= 3.0 is required. Some plotting functions in Nilearn support both matplotlib and plotly as plotting engines. In order to use the plotly engine in these functions, you will need to install both plotly and kaleido, which can both be installed with pip and anaconda. diff --git a/build_tools/github/dependencies.sh b/build_tools/github/dependencies.sh index a5c332bb32..ad645b6669 100755 --- a/build_tools/github/dependencies.sh +++ b/build_tools/github/dependencies.sh @@ -3,6 +3,9 @@ python -m pip install --progress-bar off --upgrade pip setuptools wheel flake8 if [ ! -z "$MIN_REQUIREMENTS" ]; then pip install --progress-bar off --upgrade -r requirements-min.txt + if [ ! -z "$MATPLOTLIB" ]; then + pip install --progress-bar off --upgrade matplotlib==3.0 + fi else pip install --progress-bar off --upgrade -r requirements-dev.txt fi From 304e782cb8c61fe88bb672b5836b4f78cbe8c924 Mon Sep 17 00:00:00 2001 From: Gensollen Date: Thu, 27 Jan 2022 15:46:45 +0100 Subject: [PATCH 41/44] 2021 -> 2022 (#3146) --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 2e53ddd21e..d487144ab9 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -102,7 +102,7 @@ # General information about the project. project = u'Nilearn' -copyright = u'The nilearn developers 2010-2021' +copyright = u'The nilearn developers 2010-2022' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the From 1ba24876ea7a3753fcfe3df124456826d0259284 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Fri, 28 Jan 2022 13:18:26 +0100 Subject: [PATCH 42/44] Revert "[MAINT] Bump dependencies for release `0.9.0` (#3143)" This reverts commit 26de3fe3515ce387f91be66f84277e7bd11978e0. --- README.rst | 10 +++++----- doc/changes/latest.rst | 15 --------------- requirements-min.txt | 10 +++++----- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/README.rst b/README.rst index 6acd514a72..a31529a864 100644 --- a/README.rst +++ b/README.rst @@ -46,12 +46,12 @@ The required dependencies to use the software are: * Python >= 3.6 * setuptools -* Numpy >= 1.18 -* SciPy >= 1.5 -* Scikit-learn >= 0.22 -* Joblib >= 0.15 +* Numpy >= 1.16 +* SciPy >= 1.2 +* Scikit-learn >= 0.21 +* Joblib >= 0.12 * Nibabel >= 3.0 -* Pandas >= 1.0 +* Pandas >= 0.24 If you are using nilearn plotting functionalities or running the examples, matplotlib >= 3.0 is required. diff --git a/doc/changes/latest.rst b/doc/changes/latest.rst index 2ae6f63079..747c38806f 100644 --- a/doc/changes/latest.rst +++ b/doc/changes/latest.rst @@ -6,21 +6,6 @@ 0.8.2.dev ========= -.. warning:: - - | **Python 3.6 is deprecated and will be removed in release 0.10.** - | **We recommend upgrading to Python 3.9.** - | - | **Nibabel 2.x is no longer supported. Please consider upgrading to Nibabel >= 3.0.** - | - | **Minimum supported versions of packages have been bumped up:** - | - Numpy -- v1.18 - | - SciPy -- v1.5 - | - Scikit-learn -- v0.22 - | - Pandas -- v1.0 - | - Joblib -- v0.15 - - NEW --- diff --git a/requirements-min.txt b/requirements-min.txt index 58b156c27d..230fff9b8e 100644 --- a/requirements-min.txt +++ b/requirements-min.txt @@ -1,8 +1,8 @@ -numpy==1.18 -scipy==1.5 -pandas==1.0 -scikit-learn==0.22 -joblib==0.15 +numpy==1.16 +scipy==1.2.0 +pandas==0.24.0 +scikit-learn==0.21.0 +joblib==0.12 nibabel==3.0.0 pytest pytest-cov From f1dd5d8bd1feba33ba5dcdfd76a4b48739b301ae Mon Sep 17 00:00:00 2001 From: Ahmad Date: Fri, 28 Jan 2022 13:18:41 +0100 Subject: [PATCH 43/44] Revert "[INFRA] Add tests min requirements with Matplotlib (#3144)" This reverts commit 27e00f0678b7601b2153fbf5dc3c638177a03aeb. --- .github/workflows/testing.yml | 30 ------------------------------ README.rst | 3 ++- build_tools/github/dependencies.sh | 3 --- 3 files changed, 2 insertions(+), 34 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 4dfc70cc7c..ba824881a8 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -55,36 +55,6 @@ jobs: if: success() name: 'Upload coverage to CodeCov' - min_requirements_matplotlib: - needs: check_skip - if: ${{ needs.check_skip.outputs.skip == 'false' }} - runs-on: "ubuntu-latest" - name: Python 3.6, minimal requirements with Matplotlib - defaults: - run: - shell: bash - env: - MIN_REQUIREMENTS: true - MATPLOTLIB: true - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: 3.6 - name: 'Setup python' - - shell: bash -l {0} - name: 'Display Python version' - run: python -c "import sys; print(sys.version)" - - shell: bash -l {0} - run: ./build_tools/github/dependencies.sh - name: 'Install dependencies' - - shell: bash -l {0} - run: ./build_tools/github/install.sh - name: 'Install nilearn' - - shell: bash -l {0} - run: ./build_tools/github/test.sh - name: 'Run tests' - latest: needs: check_skip if: ${{ needs.check_skip.outputs.skip == 'false' }} diff --git a/README.rst b/README.rst index a31529a864..6e93fbf9be 100644 --- a/README.rst +++ b/README.rst @@ -53,7 +53,8 @@ The required dependencies to use the software are: * Nibabel >= 3.0 * Pandas >= 0.24 -If you are using nilearn plotting functionalities or running the examples, matplotlib >= 3.0 is required. +If you are using nilearn plotting functionalities or running the +examples, matplotlib >= 1.5.1 is required. Some plotting functions in Nilearn support both matplotlib and plotly as plotting engines. In order to use the plotly engine in these functions, you will need to install both plotly and kaleido, which can both be installed with pip and anaconda. diff --git a/build_tools/github/dependencies.sh b/build_tools/github/dependencies.sh index ad645b6669..a5c332bb32 100755 --- a/build_tools/github/dependencies.sh +++ b/build_tools/github/dependencies.sh @@ -3,9 +3,6 @@ python -m pip install --progress-bar off --upgrade pip setuptools wheel flake8 if [ ! -z "$MIN_REQUIREMENTS" ]; then pip install --progress-bar off --upgrade -r requirements-min.txt - if [ ! -z "$MATPLOTLIB" ]; then - pip install --progress-bar off --upgrade matplotlib==3.0 - fi else pip install --progress-bar off --upgrade -r requirements-dev.txt fi From 65fe185914be0797a581fd66dbc1e6041e14d04e Mon Sep 17 00:00:00 2001 From: Ahmad Date: Fri, 28 Jan 2022 13:18:55 +0100 Subject: [PATCH 44/44] Revert "2021 -> 2022 (#3146)" This reverts commit 304e782cb8c61fe88bb672b5836b4f78cbe8c924. --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index d487144ab9..2e53ddd21e 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -102,7 +102,7 @@ # General information about the project. project = u'Nilearn' -copyright = u'The nilearn developers 2010-2022' +copyright = u'The nilearn developers 2010-2021' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the