Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MAINT] run test and flake8 github actions #131

Merged
merged 33 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d59d9ba
install all other dependencies
Remi-Gau Aug 30, 2023
42d3f4d
improve tests
Remi-Gau Aug 30, 2023
1d32598
improve install in ci
Remi-Gau Aug 30, 2023
3c735de
add coveralls
Remi-Gau Aug 30, 2023
f97fb3d
update args
Remi-Gau Aug 30, 2023
4061ca4
start with old python versions
Remi-Gau Aug 30, 2023
7702dd6
use latest scikit image
Remi-Gau Aug 30, 2023
a15e995
skip coverage for now
Remi-Gau Aug 30, 2023
ca5088d
install nbval later
Remi-Gau Aug 30, 2023
4d24e31
verbose
Remi-Gau Aug 30, 2023
10ba6ee
skip test before cancel run
Remi-Gau Aug 30, 2023
20b3c44
skip test
Remi-Gau Aug 30, 2023
0d7d595
add GHA for flake8
Remi-Gau Aug 30, 2023
b02080e
skip more tests
Remi-Gau Aug 30, 2023
b0ee188
fix flake8
Remi-Gau Aug 30, 2023
3077855
check each atlas
Remi-Gau Aug 30, 2023
4fc4417
unskip
Remi-Gau Aug 30, 2023
eba9d63
try another
Remi-Gau Aug 30, 2023
b147329
Merge branch 'flake8' into tests
Remi-Gau Aug 30, 2023
25bbee9
flake8
Remi-Gau Aug 30, 2023
818307d
split tests
Remi-Gau Aug 31, 2023
6bfa6b2
add pre commit for flake8 and rm travis
Remi-Gau Aug 31, 2023
a84aba8
split tests
Remi-Gau Aug 31, 2023
198f9cf
drop python 3.7
Remi-Gau Aug 31, 2023
f198845
fix tests
Remi-Gau Aug 31, 2023
7d78c72
fix test
Remi-Gau Aug 31, 2023
272d4fa
rm unused imports
Remi-Gau Aug 31, 2023
a411899
Adds minimal package versions to requirements
Oct 14, 2023
f6bdcc3
Corrects shape bug in labels file
Oct 14, 2023
9938e77
Adds coveralls badge to readme
Oct 14, 2023
a4ea91a
Updates faulty batches
Oct 14, 2023
413528e
fix cover all
Remi-Gau Oct 16, 2023
e272e4c
add setup tools
Remi-Gau Oct 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
# Documentation
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
35 changes: 35 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

name: validate

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

on:
push:
branches: [master]
pull_request:
branches: ['*']

jobs:

validate:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Install dependencies
run: |
python -m pip install flake8

- name: run flake8
run: flake8 atlasreader
10 changes: 7 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']

runs-on: ubuntu-latest

Expand All @@ -35,16 +35,20 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
python -m pip install --upgrade pip pytest jupyter nbval
python -m pip install --upgrade pip setuptools pytest pytest-cov

- name: Install
run: pip install .

- name: Test
run: pytest --cov-report term-missing --cov=atlasreader
run: python -m pytest -vvv --pyargs atlasreader --cov=atlasreader

- name: Coveralls
uses: coverallsapp/github-action@v2

- name: Test notebooks
run: |
pip install nbval
for n in `ls notebooks/*ipynb`
do
pytest --nbval-lax -v -s ${n};
Expand Down
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks

repos:

- repo: https://github.com/pyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
47 changes: 0 additions & 47 deletions .travis.yml

This file was deleted.

38 changes: 19 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[![codecov](https://codecov.io/gh/miykael/atlasreader/branch/master/graph/badge.svg)](https://codecov.io/gh/miykael/atlasreader)
[![Coverage Status](https://coveralls.io/repos/github/miykael/atlasreader/badge.svg?branch=master)](https://coveralls.io/github/miykael/atlasreader?branch=master)
[![Build Status](https://travis-ci.org/miykael/atlasreader.svg?branch=master)](https://travis-ci.org/miykael/atlasreader)
[![GitHub issues](https://img.shields.io/github/issues/miykael/atlasreader.svg)](https://github.com/miykael/atlasreader/issues/)
[![GitHub pull-requests](https://img.shields.io/github/issues-pr/miykael/atlasreader.svg)](https://github.com/miykael/atlasreader/pulls/)
[![GitHub contributors](https://img.shields.io/github/contributors/miykael/atlasreader.svg)](https://GitHub.com/miykael/atlasreader/graphs/contributors/)
[![GitHub Commits](https://github-basic-badges.herokuapp.com/commits/miykael/atlasreader.svg)](https://github.com/miykael/atlasreader/commits/master)
[![GitHub size](https://github-size-badge.herokuapp.com/miykael/atlasreader.svg)](https://github.com/miykael/atlasreader/archive/master.zip)
![GitHub repo size](https://img.shields.io/github/repo-size/miykael/atlasreader)

# AtlasReader

Expand All @@ -15,10 +15,10 @@ to localize and extract relevant peak and cluster information and create
informative and nice looking overview figures.

Please check out our interactive notebook on mybinder.org to see `atlasreader`
in action:
in action:
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/miykael/atlasreader/master?filepath=notebooks%2Fatlasreader.ipynb)

If you are using `atlasreader` in your publication, please cite the following paper:
If you are using `atlasreader` in your publication, please cite the following paper:
[![DOI](http://joss.theoj.org/papers/10.21105/joss.01257/status.svg)](https://doi.org/10.21105/joss.01257)

Notter M. P., Gale D., Herholz P., Markello R. D., Notter-Bielser M.-L., & Whitaker K. (2019). AtlasReader: A Python package to generate coordinate tables, region labels, and informative figures from statistical MRI images. *Journal of Open Source Software, 4(34), 1257*, [https://doi.org/10.21105/joss.01257](https://doi.org/10.21105/joss.01257).
Expand All @@ -33,7 +33,7 @@ installing `atlasreader` is as simple as this:
pip install atlasreader
```

If you want to build `atlasreader` directly from source code, use the
If you want to build `atlasreader` directly from source code, use the
following code:

```bash
Expand Down Expand Up @@ -67,25 +67,25 @@ atlasreader file_name 5

After executing AtlasReader on a given image, four kinds of outputs are generated:

1. An **overview figure** that shows the results within the whole brain at once
1. An **overview figure** that shows the results within the whole brain at once
![Overview Figure](paper/fig_overview_figure.png)

2. **For each cluster**, an **informative figure** showing the sagittal, coronal
and transversal plane centered on the main peak of the cluster
and transversal plane centered on the main peak of the cluster
![Cluster Figure](paper/fig_cluster_figure.png)

3. A **csv file** containing relevant information about the **peak** of each
cluster. This table contains the cluster association and location of each
peak, its signal value at this location, the cluster extent (in mm, not in
number of voxels), as well as the membership of each peak, given a
particular atlas.
particular atlas.
![Table Peak](paper/table_peak.png)

4. A **csv** file containing relevant information about each **cluster**. Table
showing relevant information for the cluster extent of each ROI. This table
contains the cluster association and location of each peak, the mean value
within the cluster, the cluster extent (in mm, not in number of voxels), as
well as the membership of each cluster, given a particular atlas.
well as the membership of each cluster, given a particular atlas.
![Table Cluster](paper/table_cluster.png)


Expand All @@ -94,34 +94,34 @@ After executing AtlasReader on a given image, four kinds of outputs are generate
`atlasreader.create_output` has many additional parameters that allow you to change the way
the clusters are generated and what kind of outputs are generated:

- **filename**: Niimg_like
- **filename**: Niimg_like
A 3D statistical image.
- **cluster_extent**: int
- **cluster_extent**: int
Minimum number of contiguous voxels required to consider a cluster in `filename`
- **atlas**: str or list, optional
- **atlas**: str or list, optional
Name of atlas(es) to consider for cluster analysis. ***Default***: `'default'`
- **voxel_thresh**: float, optional
Threshold to apply to `stat_img`. Use `direction` to specify the
Threshold to apply to `stat_img`. Use `direction` to specify the
directionality of the threshold. If a negative number is provided a
percentile threshold is used instead, where the percentile is determined
by the equation `100 - voxel_thresh`. ***Default***: `1.96`
- **direction**: str, optional
Specifies the direction in which `voxel_thresh` should be applied. Possible
values are `'both'`, `'pos'` or `'neg'`. ***Default***: `'both'`
- **prob_thresh**: int, optional
- **prob_thresh**: int, optional
Probability (percentage) threshold to apply to `atlas`, if it is
probabilistic. ***Default***: `5`
- **min_distance**: float, optional
- **min_distance**: float, optional
Specifies the minimum distance (in mm) required between sub-peaks in a
cluster. If None, sub-peaks will not be examined and only the primary
cluster peak will be reported. ***Default***: `None`
- **outdir**: str or None, optional
- **outdir**: str or None, optional
Path to desired output directory. If None, generated files will be
saved to the same folder as `filename`. ***Default***: `None`
- **glass_plot_kws**: dict or None, optional
- **glass_plot_kws**: dict or None, optional
Additional keyword arguments to pass to `nilearn.plotting.plot_glass_brain`.
***Default***: `None`
- **stat_plot_kws**: dict or None, optional
- **stat_plot_kws**: dict or None, optional
Additional keyword arguments to pass to `nilearn.plotting.plot_stat_map`.
***Default***: `None`

Expand All @@ -148,7 +148,7 @@ about it!

## Licence

AtlasReader is licensed under the BSD-3 license; however, the atlases it uses
AtlasReader is licensed under the BSD-3 license; however, the atlases it uses
are separately licensed under more restrictive frameworks.
By using AtlasReader, you agree to abide by the license terms of the
individual atlases. Information on these terms can be found online at:
Expand Down
16 changes: 11 additions & 5 deletions atlasreader/atlasreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,15 @@ def get_subpeak_coords(clust_img, min_distance=20):
data = check_niimg(clust_img).get_fdata()

# find local maxima, excluding peaks that are on the border of the cluster
local_max = peak_local_max(data, exclude_border=1, indices=False)
local_max = peak_local_max(data, exclude_border=1)
miykael marked this conversation as resolved.
Show resolved Hide resolved

# make new clusters to check for "flat" peaks + find CoM of those clusters
labels, nl = label(local_max)
labels_img = np.zeros_like(data)
for ldx in range(len(labels)):
labels_img[tuple(local_max[ldx])] = np.mean(labels[ldx])
labels = labels_img.astype('int')

ijk = center_of_mass(data, labels=labels, index=range(1, nl + 1))
ijk = np.round(ijk).astype(int)

Expand Down Expand Up @@ -341,7 +346,7 @@ def read_atlas_peak(atlastype, coordinate, prob_thresh=5):

# get atlas data
checked_atlastype = check_atlases(atlastype)
if type(checked_atlastype) == list:
if isinstance(checked_atlastype, list):
if not len(checked_atlastype) == 1:
raise ValueError(
'\'{}\' is not a string or a single atlas. \'all\' '
Expand Down Expand Up @@ -407,7 +412,7 @@ def read_atlas_cluster(atlastype, cluster, affine, prob_thresh=5):

# get atlas data
checked_atlastype = check_atlases(atlastype)
if type(checked_atlastype) == list:
if isinstance(checked_atlastype, list):
if not len(checked_atlastype) == 1:
raise ValueError(
'\'{}\' is not a string or a single atlas. \'all\' '
Expand Down Expand Up @@ -572,8 +577,9 @@ def get_peak_data(clust_img, atlas='default', prob_thresh=5,
segment = read_atlas_peak(atype, coord, prob_thresh)
coord_info.append([atype.atlas, segment])

peak_info += [[peak if type(peak) != list else
'; '.join(['{}% {}'.format(*e) for e in peak])
peak_info += [['; '.join(['{}% {}'.format(*e) for e in peak])
if isinstance(peak, list)
else peak
for (_, peak) in coord_info]]

return np.column_stack([coords, peak_values, cluster_volume, peak_info])
Expand Down
3 changes: 2 additions & 1 deletion atlasreader/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@

TESTS_REQUIRE = [
'pytest',
'pytest-cov'
'pytest-cov',
'nbval'
]

PACKAGE_DATA = {
Expand Down
12 changes: 12 additions & 0 deletions atlasreader/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import pytest
from pathlib import Path


@pytest.fixture
def data_dir():
return Path(__file__).parent / 'data'


@pytest.fixture
def stat_img(data_dir):
return data_dir / 'collection_658' / "image_10426.nii.gz"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id": 658, "url": "http://neurovault.org/collections/658/", "download_url": "http://neurovault.org/collections/658/download", "owner": 470, "contributors": "bthirion, gael.varoquaux", "owner_name": "schwarty", "number_of_images": 65, "name": "Principal Component Regression predicts functional responses across individuals", "DOI": null, "authors": null, "paper_url": null, "journal_name": null, "description": "Inter-subject variability is a major hurdle for neuroimaging group-level inference, as it creates complex image patterns that are not captured by standard analysis models and jeopardizes the sensitivity of statistical procedures. A solution to this problem is to model random subjects effects by using the redundant information conveyed by multiple imaging contrasts. In this paper, we introduce a novel analysis framework, where we estimate the amount of variance that is fit by a random effects subspace learned on other images; we show that a principal component regression estimator outperforms other regression models and that it fits a significant proportion (10% to 25%) of the between-subject variability. This proves for the first time that the accumulation of contrasts in each individual can provide the basis for more sensitive neuroimaging group analyzes.", "full_dataset_url": null, "private": false, "add_date": "2015-06-22T13:54:57.479256+02:00", "modify_date": "2016-01-27T23:00:42.540459+01:00", "doi_add_date": null, "type_of_design": null, "number_of_imaging_runs": null, "number_of_experimental_units": null, "length_of_runs": null, "length_of_blocks": null, "length_of_trials": null, "optimization": null, "optimization_method": null, "subject_age_mean": null, "subject_age_min": null, "subject_age_max": null, "handedness": null, "proportion_male_subjects": null, "inclusion_exclusion_criteria": null, "number_of_rejected_subjects": null, "group_comparison": null, "group_description": null, "scanner_make": null, "scanner_model": null, "field_strength": null, "pulse_sequence": null, "parallel_imaging": null, "field_of_view": null, "matrix_size": null, "slice_thickness": null, "skip_distance": null, "acquisition_orientation": null, "order_of_acquisition": null, "repetition_time": null, "echo_time": null, "flip_angle": null, "software_package": null, "software_version": null, "order_of_preprocessing_operations": null, "quality_control": null, "used_b0_unwarping": null, "b0_unwarping_software": null, "used_slice_timing_correction": null, "slice_timing_correction_software": null, "used_motion_correction": null, "motion_correction_software": null, "motion_correction_reference": null, "motion_correction_metric": null, "motion_correction_interpolation": null, "used_motion_susceptibiity_correction": null, "used_intersubject_registration": null, "intersubject_registration_software": null, "intersubject_transformation_type": null, "nonlinear_transform_type": null, "transform_similarity_metric": null, "interpolation_method": null, "object_image_type": null, "functional_coregistered_to_structural": null, "functional_coregistration_method": null, "coordinate_space": null, "target_template_image": null, "target_resolution": null, "used_smoothing": null, "smoothing_type": null, "smoothing_fwhm": null, "resampled_voxel_size": null, "intrasubject_model_type": null, "intrasubject_estimation_type": null, "intrasubject_modeling_software": null, "hemodynamic_response_function": null, "used_temporal_derivatives": null, "used_dispersion_derivatives": null, "used_motion_regressors": null, "used_reaction_time_regressor": null, "used_orthogonalization": null, "orthogonalization_description": null, "used_high_pass_filter": null, "high_pass_filter_method": null, "autocorrelation_model": null, "group_model_type": null, "group_estimation_type": null, "group_modeling_software": null, "group_inference_type": null, "group_model_multilevel": null, "group_repeated_measures": null, "group_repeated_measures_method": null, "nutbrain_hunger_state": null, "nutbrain_food_viewing_conditions": null, "nutbrain_food_choice_type": null, "nutbrain_taste_conditions": null, "nutbrain_odor_conditions": null, "communities": [], "relative_path": "collection_658"}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"url": "http://neurovault.org/images/10426/", "id": 10426, "file": "http://neurovault.org/media/images/658/task001_left_vs_right_motor.nii.gz", "collection": "http://neurovault.org/collections/658/", "collection_id": 658, "file_size": 186649, "cognitive_paradigm_cogatlas": null, "cognitive_paradigm_cogatlas_id": null, "cognitive_contrast_cogatlas": null, "cognitive_contrast_cogatlas_id": null, "map_type": "other", "analysis_level": null, "name": "task001 left vs right motor", "description": null, "add_date": "2016-01-21T18:22:58.807468+01:00", "modify_date": "2016-01-27T22:59:40.180124+01:00", "is_valid": false, "surface_left_file": null, "surface_right_file": null, "data_origin": "volume", "target_template_image": "GenericMNI", "subject_species": "homo sapiens", "figure": null, "handedness": null, "age": null, "gender": null, "race": null, "ethnicity": null, "BMI": null, "fat_percentage": null, "waist_hip_ratio": null, "mean_PDS_score": null, "tanner_stage": null, "days_since_menstruation": null, "hours_since_last_meal": null, "bis_bas_score": null, "spsrq_score": null, "bis11_score": null, "thumbnail": "http://neurovault.org/media/images/658/glass_brain_10426.jpg", "reduced_representation": "http://neurovault.org/media/images/658/transform_4mm_10426.npy", "is_thresholded": false, "perc_bad_voxels": 70.4103024857742, "not_mni": false, "brain_coverage": 68.1115393334845, "perc_voxels_outside": 0.840521035029044, "number_of_subjects": null, "modality": null, "statistic_parameters": null, "smoothness_fwhm": null, "contrast_definition": null, "contrast_definition_cogatlas": null, "cognitive_paradigm_description_url": null, "image_type": "statistic_map", "relative_path": "collection_658/image_10426.nii.gz", "resampled_relative_path": "collection_658/image_10426_resampled.nii.gz"}
Loading