[ENH]: Support for multiple computed masks #175

Merged
fraimondo merged 10 commits from feat/compute_mask into main 2023-01-23 17:32:41 +00:00
fraimondo commented 2023-01-17 12:36:59 +00:00 (Migrated from github.com)

Are you requiring a new dataset or marker?

  • I understand this is not a marker or dataset request

Which feature do you want to include?

Extracted from comment on #170 by @LeSasse:

i would probably just take the literal name of the function and for now implement it with these three functions until there is demand for more:

"compute_epi_mask" -> https://nilearn.github.io/dev/modules/generated/nilearn.masking.compute_epi_mask.html#nilearn.masking.compute_epi_mask

"compute_brain_mask" -> https://nilearn.github.io/dev/modules/generated/nilearn.masking.compute_brain_mask.html#nilearn.masking.compute_brain_mask

"compute_background_mask" -> https://nilearn.github.io/dev/modules/generated/nilearn.masking.compute_background_mask.html#nilearn.masking.compute_background_mask

I think most of the parameters for the functions should be possible to use as well, the important ones are strings and numbers I think. In the very least i think, for "compute_brain_mask" you can set the mask_type as a string. There is an optional target affine parameter as well, but this is only required if you also want to do resampling, which is not needed in this particular step.

How do you imagine this integrated in junifer?

In a pipeline step.

Do you have a sample code that implements this outside of junifer?

No response

Anything else to say?

No response

### Are you requiring a new dataset or marker? - [X] I understand this is not a marker or dataset request ### Which feature do you want to include? Extracted from comment on #170 by @LeSasse: > i would probably just take the literal name of the function and for now implement it with these three functions until there is demand for more: > > "compute_epi_mask" -> https://nilearn.github.io/dev/modules/generated/nilearn.masking.compute_epi_mask.html#nilearn.masking.compute_epi_mask > >"compute_brain_mask" -> https://nilearn.github.io/dev/modules/generated/nilearn.masking.compute_brain_mask.html#nilearn.masking.compute_brain_mask > >"compute_background_mask" -> https://nilearn.github.io/dev/modules/generated/nilearn.masking.compute_background_mask.html#nilearn.masking.compute_background_mask > >I think most of the parameters for the functions should be possible to use as well, the important ones are strings and numbers I think. In the very least i think, for "compute_brain_mask" you can set the mask_type as a string. There is an optional target affine parameter as well, but this is only required if you also want to do resampling, which is not needed in this particular step. ### How do you imagine this integrated in junifer? In a pipeline step. ### Do you have a sample code that implements this outside of junifer? _No response_ ### Anything else to say? _No response_
github-actions[bot] commented 2023-01-17 12:42:15 +00:00 (Migrated from github.com)
PR Preview Action v1.2.0
Preview removed because the pull request was closed.
2023-01-23 17:39 UTC
[PR Preview Action](https://github.com/rossjrw/pr-preview-action) v1.2.0 :---: Preview removed because the pull request was closed. 2023-01-23 17:39 UTC <!-- Sticky Pull Request Commentpr-preview -->
codecov[bot] commented 2023-01-17 12:57:03 +00:00 (Migrated from github.com)

Codecov Report

Merging #175 (7ffc01f) into main (e1717c5) will increase coverage by 0.06%.
The diff coverage is 98.03%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #175      +/-   ##
==========================================
+ Coverage   93.44%   93.51%   +0.06%     
==========================================
  Files          75       75              
  Lines        2836     2866      +30     
  Branches      508      515       +7     
==========================================
+ Hits         2650     2680      +30     
  Misses        126      126              
  Partials       60       60              
Flag Coverage Δ
docs 100.00% <ø> (ø)
junifer 93.50% <98.03%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
junifer/data/__init__.py 100.00% <ø> (ø)
junifer/markers/ets_rss.py 100.00% <ø> (ø)
junifer/markers/falff/falff_parcels.py 100.00% <ø> (ø)
...al_connectivity/functional_connectivity_parcels.py 100.00% <ø> (ø)
junifer/data/masks.py 95.00% <97.22%> (+3.16%) ⬆️
junifer/markers/falff/falff_spheres.py 100.00% <100.00%> (ø)
...ivity/crossparcellation_functional_connectivity.py 100.00% <100.00%> (ø)
...ional_connectivity/functional_connectivity_base.py 97.05% <100.00%> (ø)
...al_connectivity/functional_connectivity_spheres.py 100.00% <100.00%> (ø)
junifer/markers/parcel_aggregation.py 100.00% <100.00%> (ø)
... and 4 more
# [Codecov](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml) Report > Merging [#175](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml) (7ffc01f) into [main](https://codecov.io/gh/juaml/junifer/commit/e1717c52f4669b90c42b390d53851d6f9b8ebadd?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml) (e1717c5) will **increase** coverage by `0.06%`. > The diff coverage is `98.03%`. [![Impacted file tree graph](https://codecov.io/gh/juaml/junifer/pull/175/graphs/tree.svg?width=650&height=150&src=pr&token=5H21JuZXMw&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml)](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml) ```diff @@ Coverage Diff @@ ## main #175 +/- ## ========================================== + Coverage 93.44% 93.51% +0.06% ========================================== Files 75 75 Lines 2836 2866 +30 Branches 508 515 +7 ========================================== + Hits 2650 2680 +30 Misses 126 126 Partials 60 60 ``` | Flag | Coverage Δ | | |---|---|---| | docs | `100.00% <ø> (ø)` | | | junifer | `93.50% <98.03%> (+0.06%)` | :arrow_up: | Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#carryforward-flags-in-the-pull-request-comment) to find out more. | [Impacted Files](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml) | Coverage Δ | | |---|---|---| | [junifer/data/\_\_init\_\_.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9kYXRhL19faW5pdF9fLnB5) | `100.00% <ø> (ø)` | | | [junifer/markers/ets\_rss.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9tYXJrZXJzL2V0c19yc3MucHk=) | `100.00% <ø> (ø)` | | | [junifer/markers/falff/falff\_parcels.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9tYXJrZXJzL2ZhbGZmL2ZhbGZmX3BhcmNlbHMucHk=) | `100.00% <ø> (ø)` | | | [...al\_connectivity/functional\_connectivity\_parcels.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9tYXJrZXJzL2Z1bmN0aW9uYWxfY29ubmVjdGl2aXR5L2Z1bmN0aW9uYWxfY29ubmVjdGl2aXR5X3BhcmNlbHMucHk=) | `100.00% <ø> (ø)` | | | [junifer/data/masks.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9kYXRhL21hc2tzLnB5) | `95.00% <97.22%> (+3.16%)` | :arrow_up: | | [junifer/markers/falff/falff\_spheres.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9tYXJrZXJzL2ZhbGZmL2ZhbGZmX3NwaGVyZXMucHk=) | `100.00% <100.00%> (ø)` | | | [...ivity/crossparcellation\_functional\_connectivity.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9tYXJrZXJzL2Z1bmN0aW9uYWxfY29ubmVjdGl2aXR5L2Nyb3NzcGFyY2VsbGF0aW9uX2Z1bmN0aW9uYWxfY29ubmVjdGl2aXR5LnB5) | `100.00% <100.00%> (ø)` | | | [...ional\_connectivity/functional\_connectivity\_base.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9tYXJrZXJzL2Z1bmN0aW9uYWxfY29ubmVjdGl2aXR5L2Z1bmN0aW9uYWxfY29ubmVjdGl2aXR5X2Jhc2UucHk=) | `97.05% <100.00%> (ø)` | | | [...al\_connectivity/functional\_connectivity\_spheres.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9tYXJrZXJzL2Z1bmN0aW9uYWxfY29ubmVjdGl2aXR5L2Z1bmN0aW9uYWxfY29ubmVjdGl2aXR5X3NwaGVyZXMucHk=) | `100.00% <100.00%> (ø)` | | | [junifer/markers/parcel\_aggregation.py](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml#diff-anVuaWZlci9tYXJrZXJzL3BhcmNlbF9hZ2dyZWdhdGlvbi5weQ==) | `100.00% <100.00%> (ø)` | | | ... and [4 more](https://codecov.io/gh/juaml/junifer/pull/175?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=juaml) | |
fraimondo commented 2023-01-17 14:14:43 +00:00 (Migrated from github.com)

@kaurao @LeSasse:

I started working on this (should be finished quite easily). Question now it's about the "default".

What shall we do as "default":

  1. Leave it to None (whatever nilearn does will be the default).
  2. "compute_brain" (use the MNI152 1mm-resolution template)
  3. "compute_epi" (will only work with BOLD)
  4. Other suggestions?
@kaurao @LeSasse: I started working on this (should be finished quite easily). Question now it's about the "default". What shall we do as "default": 1) Leave it to None (whatever nilearn does will be the default). 2) "compute_brain" (use the MNI152 1mm-resolution template) 3) "compute_epi" (will only work with BOLD) 4) Other suggestions?
LeSasse commented 2023-01-17 14:20:53 +00:00 (Migrated from github.com)

@kaurao @LeSasse:

I started working on this (should be finished quite easily). Question now it's about the "default".

What shall we do as "default":

1. Leave it to None (whatever nilearn does will be the default).

2. "compute_brain" (use the MNI152 1mm-resolution template)

3. "compute_epi" (will only work with BOLD)

4. Other suggestions?

In my opinion now (it has shifted over time) the best default is likely the nilearn default, although this in my experience often lead to memory errors for larger BOLD images without a mask. But better than to apply a mask without the user knowing about it or setting it explicitly.

(Here in the changelog you can also guess that memory was an issue before masking in clean_img was possible: https://nilearn.github.io/dev/changes/whats_new.html#id1738), but again, I still think better to be explicit:

Function clean_img now accepts a mask to restrict the cleaning of the image, reducing memory load and computation time.

> @kaurao @LeSasse: > > I started working on this (should be finished quite easily). Question now it's about the "default". > > What shall we do as "default": > > 1. Leave it to None (whatever nilearn does will be the default). > > 2. "compute_brain" (use the MNI152 1mm-resolution template) > > 3. "compute_epi" (will only work with BOLD) > > 4. Other suggestions? In my opinion now (it has shifted over time) the best default is likely the nilearn default, although this in my experience often lead to memory errors for larger BOLD images without a mask. But better than to apply a mask without the user knowing about it or setting it explicitly. (Here in the changelog you can also guess that memory was an issue before masking in clean_img was possible: https://nilearn.github.io/dev/changes/whats_new.html#id1738), but again, I still think better to be explicit: > Function [clean_img](https://nilearn.github.io/dev/modules/generated/nilearn.image.clean_img.html#nilearn.image.clean_img) now accepts a mask to restrict the cleaning of the image, reducing memory load and computation time.
kaurao commented 2023-01-17 14:54:27 +00:00 (Migrated from github.com)

My take is "no masking" as a defaukt with documentation clearly stating that this might run into memory issues.
Then user can of course specifty compute_epi_mask etc as they like.

My take is "no masking" as a defaukt with documentation clearly stating that this might run into memory issues. Then user can of course specifty `compute_epi_mask` etc as they like.
LeSasse (Migrated from github.com) reviewed 2023-01-18 07:57:34 +00:00
@ -21,0 +42,4 @@
Parameters
----------
target_img : nibabel.Nifti1Image
LeSasse (Migrated from github.com) commented 2023-01-18 07:57:34 +00:00

I think it would be better to have the actual function name from nilearn (i.e. "compute_brain_mask") rather than an abbreviation of it.

I think it would be better to have the actual function name from nilearn (i.e. "compute_brain_mask") rather than an abbreviation of it.
kaurao commented 2023-01-18 08:35:15 +00:00 (Migrated from github.com)

also how about adding support to some nilearn internal masks like:

  • nilearn.datasets.fetch_icbm152_brain_gm_mask
  • nilearn.datasets.load_mni152_brain_mask
also how about adding support to some `nilearn` internal masks like: - `nilearn.datasets.fetch_icbm152_brain_gm_mask` - `nilearn.datasets.load_mni152_brain_mask`
fraimondo commented 2023-01-18 11:21:42 +00:00 (Migrated from github.com)

also how about adding support to some nilearn internal masks like:

nilearn.datasets.fetch_icbm152_brain_gm_mask
nilearn.datasets.load_mni152_brain_mask

The first one can be added. The second is used in compute_brain_mask

> also how about adding support to some nilearn internal masks like: > nilearn.datasets.fetch_icbm152_brain_gm_mask > nilearn.datasets.load_mni152_brain_mask The first one can be added. The second is used in `compute_brain_mask`
fraimondo commented 2023-01-18 11:37:45 +00:00 (Migrated from github.com)

So now I have added support for using functions to "compute" masks. What we have to decide now is the API. That is, how users will use this. Before, each mask was just a name. But now we have quite some functions with parameters.

So let's say we want to use the compute_brain_mask with whole-brain and a threshold of 0.2:

Option A):

    marker = ParcelAggregation(
        parcellation="Schaefer100x7",
        method="mean",
        name="test_feature",
        on="VBM_GM",
        mask="compute_brain_mask",
        mask_params={"mask_type":"whole-brain", "threshold": 0.2}
    ) 

Option B)

    marker = ParcelAggregation(
        parcellation="Schaefer100x7",
        method="mean",
        name="test_feature",
        on="VBM_GM",
        mask={"compute_brain_mask": {"mask_type":"whole-brain", "threshold": 0.2}}
    ) 

While Option A seems more straigthforward, we also need to consider that we will also support multiple masks by combining them (#174):

Then option A might end up like this:

marker = ParcelAggregation(
    parcellation="Schaefer100x7",
    method="mean",
    name="test_feature",
    on="VBM_GM",
    mask=["compute_brain_mask", "compute_epi_mask"]
    mask_params={
        "compute_brain_mask": {
            "mask_type":"whole-brain",
            "threshold": 0.2
        },
        "compute_epi_mask": {
            "lower_cutoff": 0.3, 
            "upper_cuttoff": 0.8
        }, 
        "threshold": 1  # full intersection
    }

Then option 2 would be like this:

    marker = ParcelAggregation(
        parcellation="Schaefer100x7",
        method="mean",
        name="test_feature",
        on="VBM_GM",
        mask={
            "compute_brain_mask": {
                "mask_type":"whole-brain",
                "threshold": 0.2
            },
            "compute_epi_mask": {
                "lower_cutoff": 0.3, 
                "upper_cuttoff": 0.8
            }, 
            "threshold": 1  # full intersection
        } 

The ideal YAML section should be like this:

masks:
  - compute_brain_mask:
    - mask_type: "whole-brain"
    - threshold: "0.2"
  - compute_epi_mask:
    - lower_cutoff: 0.3
    - upper_cutoff: 0.8
  - threshold: 1

Now, option 1 will require some translation/interpretation of the YAML before passing the parameter. Option 2 is a direct intepretation of the yaml. However, we will need to make sure that noone tries to register a mask that is named like one of the parameters of intersect_mask (threshold and connected).

What do you think @kaurao , @LeSasse and @synchon ? Ideally, I would like that both python and YAML uses are "understandable"

So now I have added support for using functions to "compute" masks. What we have to decide now is the API. That is, how users will use this. Before, each mask was just a name. But now we have quite some functions with parameters. So let's say we want to use the `compute_brain_mask` with `whole-brain` and a threshold of 0.2: Option A): ```Python marker = ParcelAggregation( parcellation="Schaefer100x7", method="mean", name="test_feature", on="VBM_GM", mask="compute_brain_mask", mask_params={"mask_type":"whole-brain", "threshold": 0.2} ) ``` Option B) ```Python marker = ParcelAggregation( parcellation="Schaefer100x7", method="mean", name="test_feature", on="VBM_GM", mask={"compute_brain_mask": {"mask_type":"whole-brain", "threshold": 0.2}} ) ``` While Option A seems more straigthforward, we also need to consider that we will also support _multiple_ masks by combining them (#174): Then option A might end up like this: ```Python marker = ParcelAggregation( parcellation="Schaefer100x7", method="mean", name="test_feature", on="VBM_GM", mask=["compute_brain_mask", "compute_epi_mask"] mask_params={ "compute_brain_mask": { "mask_type":"whole-brain", "threshold": 0.2 }, "compute_epi_mask": { "lower_cutoff": 0.3, "upper_cuttoff": 0.8 }, "threshold": 1 # full intersection } ``` Then option 2 would be like this: ```Python marker = ParcelAggregation( parcellation="Schaefer100x7", method="mean", name="test_feature", on="VBM_GM", mask={ "compute_brain_mask": { "mask_type":"whole-brain", "threshold": 0.2 }, "compute_epi_mask": { "lower_cutoff": 0.3, "upper_cuttoff": 0.8 }, "threshold": 1 # full intersection } ``` The ideal YAML section should be like this: ```yaml masks: - compute_brain_mask: - mask_type: "whole-brain" - threshold: "0.2" - compute_epi_mask: - lower_cutoff: 0.3 - upper_cutoff: 0.8 - threshold: 1 ``` Now, option 1 will require some translation/interpretation of the YAML before passing the parameter. Option 2 is a direct intepretation of the yaml. However, we will need to make sure that noone tries to register a mask that is named like one of the parameters of `intersect_mask` (`threshold` and `connected`). What do you think @kaurao , @LeSasse and @synchon ? Ideally, I would like that both python and YAML uses are "understandable"
LeSasse commented 2023-01-18 12:02:38 +00:00 (Migrated from github.com)

@fraimondo I find option two more intuitive, i.e. simply hand over a dictionary with function name as key and function parameters as value. My only question would be in option 2, how does it work with non-function masks, i.e. where there is only a "key" but not a value (as no further parameters are needed). My guess is, if there is a mask from the dataset/datagrabber then it will for option 2 be sth like:

{"dataset/datagrabber (whatever the key is)": /path/to/the/mask}

Or how would that fit into the API?

@fraimondo I find option two more intuitive, i.e. simply hand over a dictionary with function name as key and function parameters as value. My only question would be in option 2, how does it work with non-function masks, i.e. where there is only a "key" but not a value (as no further parameters are needed). My guess is, if there is a mask from the dataset/datagrabber then it will for option 2 be sth like: ``` {"dataset/datagrabber (whatever the key is)": /path/to/the/mask} ``` Or how would that fit into the API?
synchon commented 2023-01-18 12:16:42 +00:00 (Migrated from github.com)

I would also go with option 2 but just rename the parameter name to masks.

I would also go with option 2 but just rename the parameter name to `masks`.
fraimondo commented 2023-01-18 12:38:17 +00:00 (Migrated from github.com)

@fraimondo I find option two more intuitive, i.e. simply hand over a dictionary with function name as key and function parameters as value. My only question would be in option 2, how does it work with non-function masks, i.e. where there is only a "key" but not a value (as no further parameters are needed). My guess is, if there is a mask from the dataset/datagrabber then it will for option 2 be sth like:

{"dataset/datagrabber (whatever the key is)": /path/to/the/mask}

Or how would that fit into the API?

That's the issue. It will be a key with None value. This is assuming that mask is a Dict.

    marker = ParcelAggregation(
        parcellation="Schaefer100x7",
        method="mean",
        name="test_feature",
        on="VBM_GM",
        mask={
            "compute_brain_mask": {
                "mask_type":"whole-brain",
                "threshold": 0.2
            },
            "GM_prob0.2": None,
            "threshold": 1  # full intersection
        }

The corresponding yaml then, it's not like I posted before (that's a list of dicts).

It will be something like this (notice that I removed the -):

masks:
  compute_brain_mask:
    - mask_type: "whole-brain"
    - threshold: "0.2"
  compute_epi_mask:
    - lower_cutoff: 0.3
    - upper_cutoff: 0.8
  threshold: 1
  GM_prob0.2: null

Which also makes it quite stupid when we only used "named" masks:

masks:
  GM_prob0.2: null

So to have a nice Yaml, then the mask parameter should accept a str or (list of (dict or str)).

That way you can do this:

masks:
  - GM_prob0.2

or this

masks:
  - compute_brain_mask:
    - mask_type: "whole-brain"
    - threshold: "0.2"
  - compute_epi_mask:
    - lower_cutoff: 0.3
    - upper_cutoff: 0.8
  - threshold: 1
  - GM_prob0.2

or even this

masks2: [GM_prob0.2, inherit]
> @fraimondo I find option two more intuitive, i.e. simply hand over a dictionary with function name as key and function parameters as value. My only question would be in option 2, how does it work with non-function masks, i.e. where there is only a "key" but not a value (as no further parameters are needed). My guess is, if there is a mask from the dataset/datagrabber then it will for option 2 be sth like: > > ``` > {"dataset/datagrabber (whatever the key is)": /path/to/the/mask} > ``` > > Or how would that fit into the API? That's the issue. It will be a key with None value. This is assuming that `mask` is a Dict. ```Python marker = ParcelAggregation( parcellation="Schaefer100x7", method="mean", name="test_feature", on="VBM_GM", mask={ "compute_brain_mask": { "mask_type":"whole-brain", "threshold": 0.2 }, "GM_prob0.2": None, "threshold": 1 # full intersection } ``` The corresponding yaml then, it's not like I posted before (that's a list of dicts). It will be something like this (notice that I removed the `-`): ```yaml masks: compute_brain_mask: - mask_type: "whole-brain" - threshold: "0.2" compute_epi_mask: - lower_cutoff: 0.3 - upper_cutoff: 0.8 threshold: 1 GM_prob0.2: null ``` Which also makes it quite stupid when we only used "named" masks: ```yaml masks: GM_prob0.2: null ``` So to have a nice Yaml, then the `mask` parameter should accept a str or (list of (dict or str)). That way you can do this: ```yaml masks: - GM_prob0.2 ``` or this ```yaml masks: - compute_brain_mask: - mask_type: "whole-brain" - threshold: "0.2" - compute_epi_mask: - lower_cutoff: 0.3 - upper_cutoff: 0.8 - threshold: 1 - GM_prob0.2 ``` or even this ```yaml masks2: [GM_prob0.2, inherit] ```
LeSasse commented 2023-01-18 12:45:15 +00:00 (Migrated from github.com)

I think masks taking str or (list of (dict or str)) makes sense to me. That way, it is very similar to the scoring parameter in scikit-learn's GridSearchCV (for example).

I think `masks` taking str or (list of (dict or str)) makes sense to me. That way, it is very similar to the `scoring` parameter in scikit-learn's GridSearchCV (for example).
LeSasse commented 2023-01-18 14:21:43 +00:00 (Migrated from github.com)

It looks good to me, changes to implement actually handling/combinging the multiple masks, and changes to preprocessing will be done in #174?

It looks good to me, changes to implement actually handling/combinging the multiple masks, and changes to preprocessing will be done in #174?
LeSasse (Migrated from github.com) reviewed 2023-01-18 14:23:52 +00:00
LeSasse (Migrated from github.com) commented 2023-01-18 14:23:52 +00:00

this should be str or list of (str or dict) now, no?

this should be str or list of (str or dict) now, no?
LeSasse (Migrated from github.com) reviewed 2023-01-18 14:25:52 +00:00
@ -11,7 +11,7 @@ from nilearn.image import math_img, new_img_like, resample_to_img
from nilearn.maskers import NiftiMasker
LeSasse (Migrated from github.com) commented 2023-01-18 14:25:51 +00:00

same here: in the ParcelAggregation init method should masks not be this should be str or list of (str or dict) now?

same here: in the ParcelAggregation init method should masks not be this should be str or list of (str or dict) now?
fraimondo (Migrated from github.com) reviewed 2023-01-18 14:55:31 +00:00
fraimondo (Migrated from github.com) commented 2023-01-18 14:55:31 +00:00

for the moment this is for one mask at the time.

for the moment this is for one mask at the time.
fraimondo (Migrated from github.com) reviewed 2023-01-18 14:55:49 +00:00
@ -11,7 +11,7 @@ from nilearn.image import math_img, new_img_like, resample_to_img
from nilearn.maskers import NiftiMasker
fraimondo (Migrated from github.com) commented 2023-01-18 14:55:49 +00:00

same as before. This is for computing masks.

same as before. This is for computing masks.
LeSasse (Migrated from github.com) reviewed 2023-01-18 14:59:48 +00:00
@ -11,7 +11,7 @@ from nilearn.image import math_img, new_img_like, resample_to_img
from nilearn.maskers import NiftiMasker
LeSasse (Migrated from github.com) commented 2023-01-18 14:59:47 +00:00

i see makes sense!

i see makes sense!
synchon (Migrated from github.com) requested changes 2023-01-19 11:16:00 +00:00
synchon (Migrated from github.com) left a comment

Along with the comments, lint of the code base (isort + black + flake8 checks) would be great.

Edit: Would be cool if you can also add the updated YAML and example in the docs.

Along with the comments, lint of the code base (isort + black + flake8 checks) would be great. Edit: Would be cool if you can also add the updated YAML and example in the docs.
synchon (Migrated from github.com) commented 2023-01-19 11:15:02 +00:00

Can we have refs for the functions?

Can we have refs for the functions?
@ -18,6 +36,30 @@ if TYPE_CHECKING:
# Path to the VOIs
synchon (Migrated from github.com) commented 2023-01-19 10:44:16 +00:00

Missing type annotations.

Missing type annotations.
synchon (Migrated from github.com) commented 2023-01-19 10:44:42 +00:00

**kwargs : dict

`**kwargs : dict`
synchon (Migrated from github.com) commented 2023-01-19 10:48:50 +00:00

Why not have the family as nilearn?

Why not have the family as `nilearn`?
@ -88,11 +146,67 @@ def list_masks() -> List[str]:
return sorted(_available_masks.keys())
synchon (Migrated from github.com) commented 2023-01-19 10:53:31 +00:00

Would prefer to have the type as dict and the key-value pair information in the description below.

Would prefer to have the type as `dict` and the key-value pair information in the description below.
synchon (Migrated from github.com) commented 2023-01-19 10:55:27 +00:00

Missing coverage here.

Missing coverage here.
@ -127,2 +242,4 @@
elif t_family == "Vickery-Patil":
mask_fname = _load_vickery_patil_mask(name, resolution)
elif t_family == "Callable":
mask_img = mask_definition["func"]
synchon (Migrated from github.com) commented 2023-01-19 10:54:00 +00:00

Needs a newline after this line.

Needs a newline after this line.
@ -137,3 +253,4 @@
mask_img = nib.load(mask_fname)
return mask_img, mask_fname
synchon (Migrated from github.com) commented 2023-01-19 10:54:51 +00:00

This if block is missing coverage.

This `if` block is missing coverage.
synchon (Migrated from github.com) commented 2023-01-19 11:13:15 +00:00

Is it possible to parametrize this test?

Is it possible to parametrize this test?
fraimondo (Migrated from github.com) reviewed 2023-01-19 12:51:32 +00:00
fraimondo (Migrated from github.com) commented 2023-01-19 12:51:31 +00:00

Here I meant to add the junifer options, not the nilearn functions.

Here I meant to add the junifer options, not the nilearn functions.
fraimondo (Migrated from github.com) reviewed 2023-01-19 12:53:42 +00:00
fraimondo (Migrated from github.com) commented 2023-01-19 12:53:41 +00:00

Because I use it later. I need to know that the family is "Callable". We will also support other functions later on.

Because I use it later. I need to know that the family is "Callable". We will also support other functions later on.
fraimondo (Migrated from github.com) reviewed 2023-01-19 12:56:37 +00:00
fraimondo (Migrated from github.com) commented 2023-01-19 12:56:35 +00:00

It will be computationally inefficient + some masks require extra steps.

It will be computationally inefficient + some masks require extra steps.
synchon (Migrated from github.com) reviewed 2023-01-19 13:27:06 +00:00
synchon (Migrated from github.com) commented 2023-01-19 13:27:06 +00:00

Then can we have a sub-family which specifies that it's from nilearn or custom (for example)?

Then can we have a `sub-family` which specifies that it's from `nilearn` or custom (for example)?
synchon (Migrated from github.com) reviewed 2023-01-19 13:30:41 +00:00
synchon (Migrated from github.com) commented 2023-01-19 13:30:40 +00:00

If you parametrize the tests, it will essentially run as the structure as you have now but more atomic and cleaner. What do you mean by "computationally inefficient"? For the ones you require extra steps, it might be worth putting it in other functions. IMO, this makes it maintainable and easy for others to approach it.

If you parametrize the tests, it will essentially run as the structure as you have now but more atomic and cleaner. What do you mean by "computationally inefficient"? For the ones you require extra steps, it might be worth putting it in other functions. IMO, this makes it maintainable and easy for others to approach it.
synchon (Migrated from github.com) reviewed 2023-01-19 13:33:04 +00:00
synchon (Migrated from github.com) commented 2023-01-19 13:33:03 +00:00

What I meant was a map from junifer options to nilearn functions.

What I meant was a map from `junifer` options to `nilearn` functions.
synchon commented 2023-01-19 13:37:09 +00:00 (Migrated from github.com)

@fraimondo Before a review, would be great if you can take care of other comments that I had from my previous note:

  • lint of the code base (isort + black + flake8 checks)
  • update YAML and example in the docs.
@fraimondo Before a review, would be great if you can take care of other comments that I had from my previous note: - lint of the code base (isort + black + flake8 checks) - update YAML and example in the docs.
fraimondo (Migrated from github.com) reviewed 2023-01-19 13:40:13 +00:00
fraimondo (Migrated from github.com) commented 2023-01-19 13:40:13 +00:00

no need, why shall we add this? the concept of family is to call the function/use internally, not to organise them for the user.

no need, why shall we add this? the concept of family is to call the function/use internally, not to organise them for the user.
fraimondo (Migrated from github.com) reviewed 2023-01-19 13:40:48 +00:00
fraimondo (Migrated from github.com) commented 2023-01-19 13:40:47 +00:00

it's in the docs.

it's in the docs.
synchon (Migrated from github.com) reviewed 2023-01-19 13:43:24 +00:00
synchon (Migrated from github.com) commented 2023-01-19 13:43:24 +00:00

I don't see a problem either way, my comment was more from a maintenance POV.

I don't see a problem either way, my comment was more from a maintenance POV.
synchon (Migrated from github.com) reviewed 2023-01-19 13:45:06 +00:00
synchon (Migrated from github.com) commented 2023-01-19 13:45:05 +00:00

Okay, all good here.

Okay, all good here.
fraimondo (Migrated from github.com) reviewed 2023-01-19 13:51:20 +00:00
fraimondo (Migrated from github.com) commented 2023-01-19 13:51:19 +00:00

done

done
fraimondo commented 2023-01-19 13:54:38 +00:00 (Migrated from github.com)
  • lint of the code base (isort + black + flake8 checks)

Done. I was dealing with a bugbear issue so that's why I did not look at it for the moment.

update YAML and example in the docs.

No need to change the YAML for the moment. This will happen in #174. We'll need examples with computing masks + multiple masks.

> * lint of the code base (isort + black + flake8 checks) Done. I was dealing with a bugbear issue so that's why I did not look at it for the moment. > update YAML and example in the docs. No need to change the YAML for the moment. This will happen in #174. We'll need examples with computing masks + multiple masks.
synchon commented 2023-01-19 13:57:21 +00:00 (Migrated from github.com)
  • lint of the code base (isort + black + flake8 checks)

Done. I was dealing with a bugbear issue so that's why I did not look at it for the moment.

update YAML and example in the docs.

No need to change the YAML for the moment. This will happen in #174. We'll need examples with computing masks + multiple masks.

Okay then I would just wait for the CI to complete and if the coverage is good, we merge.

> > * lint of the code base (isort + black + flake8 checks) > > Done. I was dealing with a bugbear issue so that's why I did not look at it for the moment. > > > update YAML and example in the docs. > > No need to change the YAML for the moment. This will happen in #174. We'll need examples with computing masks + multiple masks. Okay then I would just wait for the CI to complete and if the coverage is good, we merge.
synchon commented 2023-01-19 13:57:53 +00:00 (Migrated from github.com)

@fraimondo Can you please do a rebase on main?

@fraimondo Can you please do a rebase on `main`?
synchon (Migrated from github.com) reviewed 2023-01-19 15:12:24 +00:00
synchon (Migrated from github.com) approved these changes 2023-01-23 17:31:04 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
juaml/junifer!175
No description provided.