Skip to content

Conversation

@hoechenberger
Copy link
Member

@hoechenberger hoechenberger commented Jan 7, 2021

Basically, I just moved the explanation of the different "rank" settings from the Notes section up to the rank parameter, where I think they belong. I also added an info box, suggesting to use rank='info' on Maxwell-filtered data. I had discussed this with @SophieHerbst, but would appreciate feedback from @agramfort and / or @larsoner

Basically, I just moved the explanation of the different "rank"
settings from the Notes section up to the `rank` parameter, where
I think they belong. I also added an info box, suggesting to use
`rank='info'` on Maxwell-filtered data. I had discussed this with
@SophieHerbst, but would appreciate feedback from @agramfort and / or
@larsoner
Comment on lines 879 to 880
.. note:: For Maxwell-filtered data, you will typically want set this to
``'info'``.
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 say this is actually not true if you use movement compensation

Copy link
Member Author

Choose a reason for hiding this comment

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

Any suggestion on how to phrase this better?

Background is that empirical rank determination doesn't work properly for @SophieHerbst with the default settings: rank is always equal to number of channels. Only with rank='info' do we get what looks like a more "trustworthy" rank. We figured that we somehow should inform users about this. Maybe we can take an entirely different approach in communication here? I know too little about this stuff to come up with really useful proposals, I'm afraid! (as just demonstrated!)

Copy link
Member

Choose a reason for hiding this comment

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

It might depend on whether Python or Elekta MaxFilter was used (?) but in general what I do is do everything in Python, compute rank on epochs, then pass this as the rank param in all functions (like cov and inverse computation, etc.). I don't usually have trouble with rank when doing this, so we should figure out what the problem is.

For now I would just remove this extra bit of wording (it's an orthogonal issue) and discuss in #4676 what the right thing is to do, probably by sharing files and figuring out what the problems actually are.

@hoechenberger
Copy link
Member Author

@hoechenberger hoechenberger changed the title DOC: Make "rank" options in docs more accessible MRG, DOC: Make "rank" options in docs more accessible Jan 7, 2021
@hoechenberger hoechenberger removed the request for review from agramfort January 7, 2021 15:55
number of good channels. If a `~mne.Covariance` is passed, this can
make sense if it has been (possibly improperly) regularized without
taking into account the true data rank.
"""
Copy link
Member

Choose a reason for hiding this comment

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

missing explanation of rank = dict(...)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes so what does this actually do? What is the use case? Looking at the code, it seems it simply skips the rank estimation for the channel types that are present in the dict? Why do we need that?

Copy link
Member

Choose a reason for hiding this comment

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

What is the use case? Looking at the code, it seems it simply skips the rank estimation for the channel types that are present in the dict? Why do we need that?

Precisely the one I mentioned that I use above: compute rank once on epochs to obtain a rank dict, then pass this rank dict to compute_covariance, make_inverse_operator, etc.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok this does make sense for those functions, but clearly not for compute_rank – but we do have support there, part of the public API. I think what should be done is refactor compute_rank such that we move the implementation into a private function, which gets called by compute_rank, make_inverse_operator etc; and compute_rank wouldn't accept a dict anymore, while make_inverse_operator and friends would.

Copy link
Member

Choose a reason for hiding this comment

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

This seems like a bit of overkill / overengineering to deal with a use case that isn't really causing people problems

Copy link
Member

Choose a reason for hiding this comment

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

(and it's even possible someone knows their EEG rank but not MEG, but wants the result to have both because they have both, so doing out = compute_rank(epochs, rank=dict(eeg=59)) might even be a valid use case for example)

Copy link
Member Author

Choose a reason for hiding this comment

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

(and it's even possible someone knows their EEG rank but not MEG, but wants the result to have both because they have both, so doing out = compute_rank(epochs, rank=dict(eeg=59)) might even be a valid use case for example)

Honestly I think that this is over-engineered. Because my naive approach would have been:

out = compute_rank(epochs.copy().pick_types(meg=True))

Anyway, I've added a doctoring now :)

Copy link
Member

Choose a reason for hiding this comment

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

Honestly I think that this is over-engineered.

Indeed, but the important difference is that this is (perhaps) over-engineered at the user's end, I'm trying to avoid unnecessary code churn and complications at our (MNE maintenance) end. Plus if it's a valid use case (even if over-engineered) then we don't want to break it just to simplify our docstrings a bit.

@hoechenberger
Copy link
Member Author

Comment on lines 307 to 329

Notes
-----
The ``rank`` parameter can be:

:data:`python:None` (default)
Rank will be estimated from the data after proper scaling of
different channel types.
``'info'``
Rank is inferred from ``info``. If data have been processed
with Maxwell filtering, the Maxwell filtering header is used.
Otherwise, the channel counts themselves are used.
In both cases, the number of projectors is subtracted from
the (effective) number of channels in the data.
For example, if Maxwell filtering reduces the rank to 68, with
two projectors the returned value will be 68.
``'full'``
Rank is assumed to be full, i.e. equal to the
number of good channels. If a `Covariance` is passed, this can make
sense if it has been (possibly improperly) regularized without taking
into account the true data rank.

.. versionadded:: 0.18
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
Notes
-----
The ``rank`` parameter can be:
:data:`python:None` (default)
Rank will be estimated from the data after proper scaling of
different channel types.
``'info'``
Rank is inferred from ``info``. If data have been processed
with Maxwell filtering, the Maxwell filtering header is used.
Otherwise, the channel counts themselves are used.
In both cases, the number of projectors is subtracted from
the (effective) number of channels in the data.
For example, if Maxwell filtering reduces the rank to 68, with
two projectors the returned value will be 68.
``'full'``
Rank is assumed to be full, i.e. equal to the
number of good channels. If a `Covariance` is passed, this can make
sense if it has been (possibly improperly) regularized without taking
into account the true data rank.
.. versionadded:: 0.18
Notes
-----
.. versionadded:: 0.18

@larsoner
Copy link
Member

larsoner commented Jan 8, 2021

Thanks @hoechenberger

@larsoner larsoner merged commit 01b8b36 into mne-tools:master Jan 8, 2021
@hoechenberger hoechenberger deleted the docs branch January 8, 2021 06:07
@hoechenberger
Copy link
Member Author

@drammock @larsoner I'd like to backport this, any objections?

hoechenberger added a commit to hoechenberger/mne-python that referenced this pull request Jan 8, 2021
hoechenberger added a commit that referenced this pull request Jan 8, 2021
cbrnr pushed a commit to cbrnr/mne-python that referenced this pull request Jan 15, 2021
larsoner added a commit to vpeterson/mne-python that referenced this pull request Feb 25, 2021
* upstream/master: (66 commits)
  MRG, ENH: Add infant template downloader (mne-tools#8738)
  ENH: add reader for NeuroElectrics .nedf files (mne-tools#8734)
  DOC: improve glossary entry about fiducials (mne-tools#8763)
  MRG, ENH: Add Report.add_custom_css (mne-tools#8762)
  BUG, DOC: read_raw_egi didn't support pathlib.Path; update read_raw() docstring (mne-tools#8759)
  Add "dbs" as new channel type (mne-tools#8739)
  MRG, VIZ: Fix title position in plot_sensors (mne-tools#8752)
  MRG: Support for non-FIFF files in Report.parse_folder (mne-tools#8744)
  MRG, VIZ, FIX: sEEG picking in _prepare_topomap_plot() (mne-tools#8736)
  DOC: don't use single letter variable name in _compute_forward (mne-tools#8727)
  WIP: Fix search [skip github] [skip azp] (mne-tools#8742)
  WIP: Compare Beer-lambert to HOMER (mne-tools#8711)
  MRG: bump spyder version (mne-tools#8020)
  FIX anon with IO round trip (mne-tools#8731)
  fix set_bipolar_reference for Epochs (mne-tools#8728)
  WIP: Add width argument, reduce default (mne-tools#8725)
  ENH: Add toggle-all button to Report (mne-tools#8723)
  fix int/float conversion in nicolet header (mne-tools#8712)
  MRG, BUG: Fix Report.add_bem_to_section n_jobs != 1 (mne-tools#8713)
  MRG, DOC: Make "rank" options in docs more accessible (mne-tools#8707)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants