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

MRG: Link brains with _LinkViewer and plot_linked_brains #7227

Merged

Conversation

GuillaumeFavelier
Copy link
Contributor

@GuillaumeFavelier GuillaumeFavelier commented Jan 17, 2020

This PR adds the plot_linked_brains() function which contains a collection of _TimeViewer and share their properties. This is still a work in progress and only the time_slider is shared for now (we assume the same time array between the brains). This design provides independant apps and focus on what should be 'linked' with very little change. Please note that it can totally change depending on user needs/experience or performance.

Here is an example:

import os
import os
import mne
from mne.datasets import sample
from mne.viz import plot_linked_brains
data_path = sample.data_path()
sample_dir = os.path.join(data_path, 'MEG', 'sample')
subjects_dir = os.path.join(data_path, 'subjects')
fname_stc = os.path.join(sample_dir, 'sample_audvis-meg')
stc1 = mne.read_source_estimate(fname_stc, subject='sample')
stc2 = mne.read_source_estimate(fname_stc, subject='sample')
initial_time = 0.1
with mne.viz.use_3d_backend('pyvista'):
    brain1 = stc1.plot(subjects_dir=subjects_dir, initial_time=initial_time,
                       clim=dict(kind='value', pos_lims=[3, 6, 9]),
                       time_viewer=True, hemi='split', views=['lat', 'med'])
    brain2 = stc2.plot(subjects_dir=subjects_dir, initial_time=initial_time,
                       clim=dict(kind='value', pos_lims=[4, 6, 7]),
                       time_viewer=True)
    plot_linked_brains([brain1, brain2])

output

ToDo

  • Link playback_speed and play
  • Remember widget representation to avoid unnecessary loops: IntSlider, ShowView and SmartSlider (UpdateColorbarScale and BumpColorbarPoints will be done in another PR)
  • Rework naming convention to avoid confusion between class method and internal callback
  • Add plot_linked_brains to mne/viz/tests/test_3d.py
  • Add _LinkViewer to mne/viz/_brain/tests/test_brain.py
  • Remove the local patch for slider normalized coordinates in multi-view
  • Fix visibility issue of the sliders with toggle_interface
  • Fix inconsistency between UpdateColorbarScale and BumpColorbarPoints

Known issue

  • The slave brain slider handles are not udpated.

It's an item of #7162

@hoechenberger
Copy link
Member

This is just one amazing unit of work you’re doing here!! ❤️❤️❤️

@codecov
Copy link

codecov bot commented Jan 20, 2020

Codecov Report

Merging #7227 into master will increase coverage by <.01%.
The diff coverage is 96.45%.

@@            Coverage Diff             @@
##           master    #7227      +/-   ##
==========================================
+ Coverage   89.78%   89.79%   +<.01%     
==========================================
  Files         445      445              
  Lines       80241    80350     +109     
  Branches    12842    12857      +15     
==========================================
+ Hits        72043    72148     +105     
- Misses       5379     5381       +2     
- Partials     2819     2821       +2

@GuillaumeFavelier
Copy link
Contributor Author

What can I use in the docstring of plot_linked_brains() as return type? It's complaining when I say the truth:

    """Plot multiple SourceEstimate objects with PyVista.

    Parameters
    ----------
    brains : list, tuple or np.ndarray
        The collection of brains to plot.

    Returns
    -------
    link_viewer : instance of _brain._LinkViewer
       The interactive interface to plot the linked brains.
    """

Or is it okay not to specify a return at all?

@agramfort
Copy link
Member

agramfort commented Jan 20, 2020 via email

@larsoner
Copy link
Member

Could you just not return anything?

@larsoner
Copy link
Member

(If there is a return you must describe it, but if you don't return anything then you don't need a returns section at all)

@GuillaumeFavelier
Copy link
Contributor Author

I'll try returning nothing then if it does not work I'll make it private. Thank you.

@GuillaumeFavelier
Copy link
Contributor Author

GuillaumeFavelier commented Jan 20, 2020

Now the play toggle and the playback_speed are linked too and no need to specify time_viewer=True in the example:

import os
import mne
from mne.datasets import sample
from mne.viz import plot_linked_brains
data_path = sample.data_path()
sample_dir = os.path.join(data_path, 'MEG', 'sample')
subjects_dir = os.path.join(data_path, 'subjects')
fname_stc = os.path.join(sample_dir, 'sample_audvis-meg')
stc1 = mne.read_source_estimate(fname_stc, subject='sample')
stc2 = mne.read_source_estimate(fname_stc, subject='sample')
initial_time = 0.1
with mne.viz.use_3d_backend('pyvista'):
    brain1 = stc1.plot(subjects_dir=subjects_dir, initial_time=initial_time,
                       clim=dict(kind='value', pos_lims=[3, 6, 9]),
                       hemi='split', views=['lat', 'med'])
    brain2 = stc2.plot(subjects_dir=subjects_dir, initial_time=initial_time,
                       clim=dict(kind='value', pos_lims=[4, 6, 7]))
    plot_linked_brains([brain1, brain2])

output

What else could be linked between the windows?

@GuillaumeFavelier
Copy link
Contributor Author

This is caused by the outdated slider representation: It turns out that it is built at every update of the slider so it does not makes sense to store it. I thought it could help improve performance. I will revert.

@GuillaumeFavelier GuillaumeFavelier changed the title MRG: Link brains with _LinkViewer and plot_linked_brains WIP: Link brains with _LinkViewer and plot_linked_brains Jan 22, 2020
@GuillaumeFavelier GuillaumeFavelier changed the title WIP: Link brains with _LinkViewer and plot_linked_brains MRG: Link brains with _LinkViewer and plot_linked_brains Jan 22, 2020
@GuillaumeFavelier
Copy link
Contributor Author

GuillaumeFavelier commented Jan 22, 2020

Not related at all to the representation: _TimeViewer wrapping was applied twice.

Let's look together tomorrow

Sure, my pleasure

value=default_playback_speed,
rng=[0.01, 1], title="playback speed",
rng=[0.01, 1], title="play speed",
Copy link
Member

Choose a reason for hiding this comment

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

We should just use speed, it's short but still descriptive. Let's do it in another PR unless you're planning to push more commits

Copy link
Contributor Author

Choose a reason for hiding this comment

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

let's do it here. it's a very short change

Copy link
Member

@larsoner larsoner left a comment

Choose a reason for hiding this comment

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

LGTM +1 for merge after:

  • latest.inc update
  • update to the capability table in the code, if relevant

GuillaumeFavelier added a commit to GuillaumeFavelier/mne-python that referenced this pull request Jan 24, 2020
agramfort pushed a commit that referenced this pull request Jan 24, 2020
* Add support for both in _TimeViewer

* Port slider position patch from #7227
@GuillaumeFavelier
Copy link
Contributor Author

I implemented @larsoner feedbacks and fix the conflicts with master.

This is ready to go on my end @agramfort

Copy link
Member

@agramfort agramfort left a comment

Choose a reason for hiding this comment

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

also I still get the bug with the colormap change when pressing y. It switches to all red.

@GuillaumeFavelier @larsoner you want to do this in a follow up PR?

mne/viz/_3d.py Outdated
brains : list, tuple or np.ndarray
The collection of brains to plot.
"""
import collections
Copy link
Member

Choose a reason for hiding this comment

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

I would not nest this import

The collection of brains to plot.
"""
import collections
from ._brain import _Brain, _TimeViewer, _LinkViewer
Copy link
Member

Choose a reason for hiding this comment

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

do we need to do a check that this function requires pyvista backend?

mne/viz/_3d.py Outdated
if not hasattr(brain, 'time_viewer') or brain.time_viewer is None:
brain = _TimeViewer(brain)
else:
raise TypeError("Expected type is _Brain but"
Copy link
Member

Choose a reason for hiding this comment

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

I would not refer to a private type.

Suggested change
raise TypeError("Expected type is _Brain but"
raise TypeError("Expected type is Brain but"

this is now a bit wrong but I prefer this.



class SmartSlider(object):
"""Class to manage smart slider."""
Copy link
Member

Choose a reason for hiding this comment

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

can you be more explicit. smart in what sense? What does it allow you to do?

@GuillaumeFavelier
Copy link
Contributor Author

also I still get the bug with the colormap change when pressing y. It switches to all red.
you want to do this in a follow up PR?

+1 to do this in another PR

Copy link
Member

@agramfort agramfort left a comment

Choose a reason for hiding this comment

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

Ok merge if CIs are green. Thx

@larsoner
Copy link
Member

+1 to do this in another PR

Yes I still need to do the refactoring of _limits_to_control_points. Plenty of other stuff to work on in the meantime and I see this as a really minor use case issue -- it only happens if you are using auto-reset mode and you have one-sided data that you've chosen to display with a two-sided colormap, or vice-versa, so probably quite rare in real use cases.

@larsoner
Copy link
Member

CircleCI is unrelated, thanks @GuillaumeFavelier !

@larsoner larsoner merged commit f6e036d into mne-tools:master Jan 28, 2020
@GuillaumeFavelier GuillaumeFavelier deleted the time_viewer_plot_linked_brains branch January 29, 2020 09:42
AdoNunes pushed a commit to AdoNunes/mne-python that referenced this pull request Apr 6, 2020
* Add support for both in _TimeViewer

* Port slider position patch from mne-tools#7227
AdoNunes pushed a commit to AdoNunes/mne-python that referenced this pull request Apr 6, 2020
)

* Build first prototype

* Fix docstring

* Synchronize the slider handle

* Add representation memory to IntSlider and ShowView

* Introduce SmartSlider

* Update time callback

* Update orientation callback

* Change default name of the time slider

* Update smoothing call

* Update fmin/fmid/fmax callbacks

* Update fscale callback

* Improve performance for auto_scaling

* Use local _update_slider_callback

* Improve plot_linked_brains docstring

* Add plot_linked_brains to reference

* Link play and playback speed

* Update docstring

* Add plot_linked_brains to tests

* Add _LinkViewer to tests

* Rename plot_linked_brains into link_brains

* Remove local patch for normalized coordinate system

* Fix double _TimeViewer wrapping

* Fix issue with slider placement

* Fix UI inconsistency

* Change playback speed title to short version

* Update latest and overview table

* Fix name spelling

* Implement reviews
AdoNunes pushed a commit to AdoNunes/mne-python that referenced this pull request Apr 6, 2020
* Add support for both in _TimeViewer

* Port slider position patch from mne-tools#7227
AdoNunes pushed a commit to AdoNunes/mne-python that referenced this pull request Apr 6, 2020
)

* Build first prototype

* Fix docstring

* Synchronize the slider handle

* Add representation memory to IntSlider and ShowView

* Introduce SmartSlider

* Update time callback

* Update orientation callback

* Change default name of the time slider

* Update smoothing call

* Update fmin/fmid/fmax callbacks

* Update fscale callback

* Improve performance for auto_scaling

* Use local _update_slider_callback

* Improve plot_linked_brains docstring

* Add plot_linked_brains to reference

* Link play and playback speed

* Update docstring

* Add plot_linked_brains to tests

* Add _LinkViewer to tests

* Rename plot_linked_brains into link_brains

* Remove local patch for normalized coordinate system

* Fix double _TimeViewer wrapping

* Fix issue with slider placement

* Fix UI inconsistency

* Change playback speed title to short version

* Update latest and overview table

* Fix name spelling

* Implement reviews
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants