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] Improve plotting contours for PlotlySurfaceFigure objects by adding add_contours method #3949

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

psadil
Copy link
Contributor

@psadil psadil commented Sep 4, 2023

Changes proposed in this pull request:

@github-actions
Copy link
Contributor

github-actions bot commented Sep 4, 2023

👋 @psadil 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 4, 2023

Codecov Report

Attention: 3 lines in your changes are missing coverage. Please review.

Comparison is base (6578329) 91.77% compared to head (cb7f960) 91.80%.
Report is 190 commits behind head on main.

Files Patch % Lines
nilearn/plotting/displays/_figures.py 94.33% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3949      +/-   ##
==========================================
+ Coverage   91.77%   91.80%   +0.03%     
==========================================
  Files         134      134              
  Lines       15751    15822      +71     
  Branches     3283     3298      +15     
==========================================
+ Hits        14455    14526      +71     
  Misses        752      752              
  Partials      544      544              
Flag Coverage Δ
macos-latest_3.10 91.72% <94.33%> (+0.03%) ⬆️
macos-latest_3.11 91.72% <94.33%> (+0.03%) ⬆️
macos-latest_3.8 91.68% <94.33%> (+0.03%) ⬆️
macos-latest_3.9 91.68% <94.33%> (+0.03%) ⬆️
ubuntu-latest_3.10 91.72% <94.33%> (+0.03%) ⬆️
ubuntu-latest_3.11 91.72% <94.33%> (+0.03%) ⬆️
ubuntu-latest_3.8 91.68% <94.33%> (+0.03%) ⬆️
ubuntu-latest_3.9 ?
windows-latest_3.10 91.66% <94.33%> (+0.03%) ⬆️
windows-latest_3.11 91.66% <94.33%> (+0.03%) ⬆️
windows-latest_3.8 91.62% <94.33%> (+0.03%) ⬆️
windows-latest_3.9 91.62% <94.33%> (+0.03%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ymzayek
Copy link
Member

ymzayek commented Sep 5, 2023

@psadil thanks for getting started on this! Will try to start a review this week

@ymzayek ymzayek changed the title Improving plot surf contours [ENH] Improve plotting contours for PlotlySurfaceFigure objects by adding add_contours method Sep 5, 2023
@psadil
Copy link
Contributor Author

psadil commented Sep 6, 2023

Tests added!

Do these seem like they're on the right track?

@Remi-Gau
Copy link
Collaborator

Remi-Gau commented Sep 6, 2023

Tests added!

Thanks!!

Do these seem like they're on the right track?

Had a very quick look: it does help also understand how these methods are used, so definitely useful

psadil and others added 4 commits September 6, 2023 10:08
Co-authored-by: Remi Gau <remi_gau@hotmail.com>
Co-authored-by: Remi Gau <remi_gau@hotmail.com>
Co-authored-by: Remi Gau <remi_gau@hotmail.com>
nilearn/plotting/displays/_figures.py Outdated Show resolved Hide resolved
nilearn/plotting/displays/_figures.py Outdated Show resolved Hide resolved
nilearn/plotting/tests/test_surf_plotting.py Outdated Show resolved Hide resolved
@ymzayek
Copy link
Member

ymzayek commented Sep 7, 2023

Thanks @psadil for the updates! Here is the built example: https://output.circle-artifacts.com/output/job/9e7e0100-bdac-4eaf-99d5-b5d2f512e8bd/artifacts/0/dev/auto_examples/01_plotting/plot_3d_map_to_surface_projection.html#sphx-glr-auto-examples-01-plotting-plot-3d-map-to-surface-projection-py

It looks good! There is a small skip that I see in the postcentral gyrus contour. Idk if that can be improved further. And the other contour is hard to see but I guess that is to showcase the line width feature.

Also the API reference looks good: https://output.circle-artifacts.com/output/job/9e7e0100-bdac-4eaf-99d5-b5d2f512e8bd/artifacts/0/dev/modules/generated/nilearn.plotting.displays.PlotlySurfaceFigure.html#nilearn.plotting.displays.PlotlySurfaceFigure

@ymzayek
Copy link
Member

ymzayek commented Sep 7, 2023

BTW while checking this I noticed that in the same example where plot_surf_contours is used the contours are not rendered anymore. This is not related to this PR as I can also see it in the build artifacts dating back at least a month. I'll open a separate issue

@psadil
Copy link
Contributor Author

psadil commented Sep 7, 2023

It looks good! There is a small skip that I see in the postcentral gyrus contour. Idk if that can be improved further. And the other contour is hard to see but I guess that is to showcase the line width feature.

Oh dear, thanks. I think this might be a rendering issue. But let me find a way to either confirm or fix. Aiming for the next couple of days.

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 besides the last glitch mentioned by @ymzayek

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.

Mostly small doc stuff. I think this is in a good enough state and we can merge after addressing these. A follow-up PR can be done to address the small skip to close the contour. I don't think it should block this

@@ -134,11 +134,15 @@
##############################################################################
# Display outlines of the regions of interest on top of a statistical map
# -----------------------------------------------------------------------
#
# Regions can be outlined using both engines.
Copy link
Member

Choose a reason for hiding this comment

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

Maybe add a line clarifying that for the default matplotlib engine used by plot_surf_stat_map, plotting.plot_surf_contours is used.

Copy link
Member

Choose a reason for hiding this comment

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

Makes me also think we should raise an error in plot_surf_contours if plotly object is passed. Now we get the error AttributeError: 'PlotlySurfaceFigure' object has no attribute 'axes' but it would be better to raise one specifying that plot_surf_contours only works with matplotlib. WDYT?

Copy link
Collaborator

Choose a reason for hiding this comment

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

yes a more explicit error message would be a good thing for users

Comment on lines +158 to +160
# Note that the contours are added with a method of the object that is
# returned by :func:`~nilearn.plotting.plot_surf_stat_map`:
# :meth:`~nilearn.plotting.displays.PlotlySurfaceFigure.add_contours`.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
# Note that the contours are added with a method of the object that is
# returned by :func:`~nilearn.plotting.plot_surf_stat_map`:
# :meth:`~nilearn.plotting.displays.PlotlySurfaceFigure.add_contours`.
# Note that the contours are added with
# :meth:`~nilearn.plotting.displays.PlotlySurfaceFigure.add_contours`
# method of a :class:`~nilearn.plotting.displays.PlotlySurfaceFigure` object
# that is returned by :func:`~nilearn.plotting.plot_surf_stat_map`
# when engine is set to "plotly".

Comment on lines +123 to +124
"""
Draw boundaries around roi.
Copy link
Member

Choose a reason for hiding this comment

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

Just for consistency

Suggested change
"""
Draw boundaries around roi.
"""Draw boundaries around roi.

Comment on lines +134 to +135
The value at each vertex one inside the ROI and zero inside ROI,
or an :obj:`int` giving the label number for atlases.
Copy link
Member

Choose a reason for hiding this comment

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

??

Suggested change
The value at each vertex one inside the ROI and zero inside ROI,
or an :obj:`int` giving the label number for atlases.
The value at each vertex is one inside the ROI and zero outside
the ROI, or an :obj:`int` giving the label number for atlases.

Comment on lines +188 to +189
"""
Identify which vertices lie on the outer edge of a parcellation.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"""
Identify which vertices lie on the outer edge of a parcellation.
"""Identify which vertices lie on the outer edge of a parcellation.


Returns
-------
data : :class:`numpy.ndarray`
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
data : :class:`numpy.ndarray`
sorted_vertices : :class:`numpy.ndarray`

@ymzayek
Copy link
Member

ymzayek commented Sep 14, 2023

Oh can you also add a whatsnew entry in doc/changes/latest.rst?

@psadil
Copy link
Contributor Author

psadil commented Sep 17, 2023

A follow-up PR can be done to address the small skip to close the contour. I don't think it should block this

Just to give an update, I'm now suspecting a bug, though I'm not sure of the source. Plotting the sorted_vertices with markers shows that one vertex was missing from the postcentral gyrus contour. This vertex that is not in the contour ends up in the second-to-last row of sorted_vertices array, and the skip seems to be related to how the lines are drawn when trying to account for this other vertex (one edge of the gap is row in sorted_vertices that is one before the one that is missing from the contour.)

newplot

So, I'm hoping to sort this out before the pull request is merged.

@ymzayek
Copy link
Member

ymzayek commented Sep 18, 2023

I see in that case we'll hold off until that is resolved. Thanks @psadil

@psadil
Copy link
Contributor Author

psadil commented Sep 28, 2023

Here's a wireframe view of the surface to help clarify the situation:

frame

Vertices in the roi are marked with circles. The circles are orange when they are on the edge of the boundary (defined as a vertex of a triangle inside the roi and on a face with only two vertices in the roi) and otherwise purple.

Building up the boundary edge by sequentially selecting the next closest vertex ends up skipping the orange vertex that is lowest in the figure (the one with only one orange neighbor).

Is there an expectation for how to trace this boundary? I see these options

  • Color every edge between boundary vertices, and only those edges (would lead to faces whose edges are only partially colored)
  • Color every edge between boundary vertices, and only those edges, but exclude vertices that have only one neighbor on the graph (some vertices would be missing from an roi)
  • Color the outer edges of every face that has at least two vertices in the roi (could lead to the boundaries of two rois overlapping)

@ymzayek
Copy link
Member

ymzayek commented Oct 2, 2023

@psadil first thought would be to go with the third option since it seems most conservative, however the visual consequence of overlapping boundaries is not clear. We'd need to test it.

@psadil
Copy link
Contributor Author

psadil commented Oct 8, 2023

Sorry, but hoping to check another implementation detail. I wonder how to handle drawing handle regions that do not share an edge with another vertex in the roi. For example, this region has 2 isolated vertices.

newplot

Should I follow the matplotlib approach? I think that would mean ignoring the isolated vertices.

image

@ymzayek
Copy link
Member

ymzayek commented Oct 9, 2023

@psadil thanks for checking that. I think then it would be best to stay consistent with the matplotlib approach and ignore isolated vertices. That would then be more like the 2nd option you describe in #3949 (comment)?

@psadil
Copy link
Contributor Author

psadil commented Oct 9, 2023

@psadil thanks for checking that. I think then it would be best to stay consistent with the matplotlib approach and ignore isolated vertices. That would then be more like the 2nd option you describe in #3949 (comment)?

It wouldn't quite be the 2nd option, because it looks like the current matplotlib approach colors the faces around vertices that share only one edge with another vertex in the ROI. For example, here is the post-central gyrus contour in matplotlib

image

In the plotly implementation, I think that a comparable boundary could be the one traced by the purple line in the following (the vertex with only one shared edge is included in the contour)

newplot

@bthirion
Copy link
Member

bthirion commented Oct 9, 2023

I don't know if there are conventions somewhere that explain what is best. If there aren't I would go for the easiest and most maintainable solution (and possibly a warning if some vertices have to be missed).

@ymzayek
Copy link
Member

ymzayek commented Oct 10, 2023

I see, thanks @psadil for the clear explanation. There are certainly pros and cons to each approach so if we make it clear what the contours include in the docstring and consider @bthirion 's last comment I think we can move forward with one of these implementations.

@psadil
Copy link
Contributor Author

psadil commented Oct 10, 2023

Thanks for all the input. I'll work on something that tries to match the matplotlib approach (unless someone encounters another convention in the meanwhile).

FWIW, the behavior of plot_surf_roi includes isolated vertices. But hopefully a clear explanation of how the contours are generated (and warnings about when an isolated vertex is excluded) will avoid too much confusion.

roi27

roi28

@ymzayek
Copy link
Member

ymzayek commented Nov 10, 2023

@psadil would you have the bandwidth to finish this in the next month or two? It would be great to include it in the major release we are planning for January. Thanks for all your work on this!

@Remi-Gau Remi-Gau added Surface Related to surface data or surface analysis. Plotting The issue is related to plotting functionalities. labels Jan 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Plotting The issue is related to plotting functionalities. Surface Related to surface data or surface analysis.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ENH] improving plot_surf_contours
4 participants