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

[ENH] Allow setting vmin in plot_glass_brain and plot_stat_map #3993

Merged
merged 25 commits into from Oct 11, 2023

Conversation

michellewang
Copy link
Contributor

Changes proposed in this pull request:

  • Made plot_glass_brain use its vmin argument instead of silently ignoring it
    • This involved changing _get_colorbar_and_data_ranges, which changes the behaviour of plot_stat_map to also allow vmin to be set (instead of throwing an error)
  • Updated docstring for symmetric_cbar, since the colorbar will no longer be restricted to (-vmax, vmax), (0, vmax), (-vmax, 0), and the colormap range will also change depending on vmin/vmax
  • Removed symmetric_data_range argument from _get_colorbar_and_data_ranges, which was added in [ENH] add vmin argument to plotting.plot_img_on_surf #3873 to preserve the old behaviour in these functions. We can still get the symmetric data range behaviour if:
    • symmetric_cbar is True, or
    • symmetric_cbar is 'auto', vmin or vmax is None, and the data has both positive and negative values
      • This means that a call with default arguments will plot a symmetric colorbar, same as before
  • Refactored test cases for _get_colorbar_and_data_ranges to have clearer expected results
  • Added some example glass brain plots in examples/01_plotting/plot_demo_glass_brain_extensive.py
    • Other glass brain examples still show the same plots

Example plot_glass_brain calls with vmin:

from nilearn import datasets, plotting

stat_img = datasets.load_sample_motor_activation_image()

plotting.plot_glass_brain(
    stat_img,
    colorbar=True,
    display_mode="lyrz",
    threshold=2,
    cmap='viridis',
    vmin=2,                  # use the whole colormap range even if there is a threshold
    symmetric_cbar=False,
)

image

plotting.plot_glass_brain(
    stat_img,
    colorbar=True,
    display_mode="lyrz",
    threshold=2,
    cmap='viridis',
    vmin=-5,
    vmax=8,
    plot_abs=False,
)

image

Example plot_stat_map calls with vmin:

from nilearn import datasets, plotting
stat_img = datasets.load_sample_motor_activation_image()

plotting.plot_stat_map(
    stat_img,
    colorbar=True, 
    threshold=3,
    vmin=-9,   # symmetric from -9 to 9
)

image

plotting.plot_stat_map(
    stat_img,
    colorbar=True, 
    threshold=3,
    vmin=0,             # non-negative values only
    vmax=10,
    symmetric_cbar=False,
    cmap='viridis',
)

image

plotting.plot_stat_map(
    stat_img,
    colorbar=True, 
    threshold=3,
    vmin=3,            # use the whole colormap range even if there is a threshold
    vmax=10,
    symmetric_cbar=False,
    cmap='viridis',
)

image

@github-actions
Copy link
Contributor

👋 @michellewang Thanks for creating a PR!

Until this PR is ready for review, you can include the [WIP] tag in its title, or leave it as a github draft.

Please make sure it is compliant with our contributing guidelines. In particular, be sure it checks the boxes listed below.

  • PR has an interpretable title.
  • PR links to Github issue with mention Closes #XXXX (see our documentation on PR structure)
  • Code is PEP8-compliant (see our documentation on coding style)
  • Changelog or what's new entry in doc/changes/latest.rst (see our documentation on PR structure)

For new features:

  • There is at least one unit test per new function / class (see our documentation on testing)
  • The new feature is demoed in at least one relevant example.

For bug fixes:

  • There is at least one test that would fail under the original bug conditions.

We will review it as quick as possible, feel free to ping us with questions if needed.

@codecov
Copy link

codecov bot commented Sep 19, 2023

Codecov Report

Merging #3993 (58f717d) into main (0b54555) will decrease coverage by 0.06%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##             main    #3993      +/-   ##
==========================================
- Coverage   91.65%   91.59%   -0.06%     
==========================================
  Files         145      145              
  Lines       16222    16238      +16     
  Branches     3370     3376       +6     
==========================================
+ Hits        14869    14874       +5     
- Misses        810      817       +7     
- Partials      543      547       +4     
Flag Coverage Δ
macos-latest_3.10 91.51% <100.00%> (-0.06%) ⬇️
macos-latest_3.11 91.51% <100.00%> (-0.06%) ⬇️
macos-latest_3.12 91.51% <100.00%> (-0.06%) ⬇️
macos-latest_3.8 91.47% <100.00%> (-0.06%) ⬇️
macos-latest_3.9 91.48% <100.00%> (-0.06%) ⬇️
ubuntu-latest_3.10 91.51% <100.00%> (-0.06%) ⬇️
ubuntu-latest_3.11 91.51% <100.00%> (-0.06%) ⬇️
ubuntu-latest_3.12 91.51% <100.00%> (-0.06%) ⬇️
ubuntu-latest_3.8 91.47% <100.00%> (-0.06%) ⬇️
ubuntu-latest_3.9 91.48% <100.00%> (-0.06%) ⬇️
windows-latest_3.10 91.46% <100.00%> (-0.06%) ⬇️
windows-latest_3.11 91.46% <100.00%> (-0.06%) ⬇️
windows-latest_3.12 91.46% <100.00%> (-0.06%) ⬇️
windows-latest_3.8 91.42% <100.00%> (-0.06%) ⬇️
windows-latest_3.9 91.43% <100.00%> (-0.06%) ⬇️

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

Files Coverage Δ
nilearn/_utils/docs.py 91.86% <ø> (ø)
nilearn/plotting/displays/_slicers.py 90.93% <100.00%> (+0.05%) ⬆️
nilearn/plotting/img_plotting.py 88.00% <100.00%> (-1.55%) ⬇️
nilearn/plotting/surf_plotting.py 94.30% <ø> (ø)

... and 1 file with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@michellewang michellewang changed the title [ENH] Add vmin argument to plot_glass_brain and plot_stat_map [ENH] Allow setting vmin in plot_glass_brain and plot_stat_map Sep 20, 2023
@ymzayek
Copy link
Member

ymzayek commented Sep 20, 2023

Thx @michellewang for working on this! The example plots look great! Will give a more thorough review soon.

Copy link
Member

@ymzayek ymzayek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall all, looks pretty good! Can you explain the refactoring concerning the plotting of absolute values?

nilearn/_utils/docs.py Outdated Show resolved Hide resolved
nilearn/plotting/displays/_slicers.py Outdated Show resolved Hide resolved
@michellewang
Copy link
Contributor Author

Can you explain the refactoring concerning the plotting of absolute values?

Yes, I had to move the thresholding because it needs to happen after we take the absolute value of the data (which happens in GlassBrainAxes.transform_to_2d). Otherwise, when plot_abs is True, vmin is set to 0, and the new thresholding function will mask all negative values in the data (if a non-zero threshold is defined), so the resulting plot will only show values that were positive in the original data instead of the absolute value of all values.

I'll remove the lines with data_selection = np.abs(data_selection) in nilearn/plotting/displays/_axes.py because after looking at them again I think they are redundant with what the code already did.

@michellewang
Copy link
Contributor Author

Also: are there any tests for slicers and _map_show? I couldn't find any from a quick search

@ymzayek
Copy link
Member

ymzayek commented Oct 2, 2023

Also: are there any tests for slicers and _map_show? I couldn't find any from a quick search

Slicers are tested in nilearn/plotting/tests/test_displays.py but _map_show is not tested directly (only through calls of add_contours and add_overlay). I'd suggest adding tests relevant to the changes you made.

Copy link
Member

@bthirion bthirion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great overall ! Thx !

nilearn/_utils/docs.py Outdated Show resolved Hide resolved
nilearn/plotting/img_plotting.py Outdated Show resolved Hide resolved
Copy link
Member

@bthirion bthirion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Can you consider codecov complaints ?

@ymzayek
Copy link
Member

ymzayek commented Oct 9, 2023

LGTM. Can you consider codecov complaints ?

Not sure why that is happening. I checked the report and the added code is fully covered and the codecov/patch report is 100% so I think it's ok. Seems like there is a small decrease on the project level but this seems to come from indirect changes. I think @michellewang you can just make the changes from the last review and this should be good to go.

@michellewang
Copy link
Contributor Author

Ok, I was confused by the Codecov report. Just addressed the remaining comments, thanks @ymzayek and @bthirion for reviewing!

Copy link
Member

@ymzayek ymzayek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI something went wrong with the merge so I redid it. This PR LGTM, thanks @michellewang!

@ymzayek ymzayek requested a review from bthirion October 10, 2023 12:34
Copy link
Member

@bthirion bthirion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thx.

@ymzayek ymzayek merged commit c018480 into nilearn:main Oct 11, 2023
32 checks passed
@michellewang michellewang deleted the 3084/more_vmin branch November 1, 2023 22:15
Comment on lines -401 to -410
if threshold is not None:
data = _safe_get_data(img, ensure_finite=True)
if threshold == 0:
data = np.ma.masked_equal(data, 0, copy=False)
else:
data = np.ma.masked_inside(
data, -threshold, threshold, copy=False
)
img = new_img_like(img, data, img.affine)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants