-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Fix bug in _project_onto_surface #10930
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
Conversation
FIx a bug when calling _project_onto_surface with method != "accurate" and return_nn == True.
@larsoner These CI fails do not seem to be related to this PR (i.e., moved one line of code two lines above (from inside to outside an if-else statement). How do you normally get these passed? |
The errors seem related to this PR. This one for example:
looks like it's because you deindented / moved out of the conditional the Why do you need this functionality changed? You shouldn't be using this private function in your own code, it should only be used internally by MNE-Python. Do you hit it somehow using a public API? |
Thanks for the feedback, @larsoner. Sorry about that; I should have better checked the log of the CI to debug it myself. I was working on faulty assumptions. Nop. This error was not reached through the use of the public API, and don't worry, I am well aware that there is no guarantee of stability on private methods. Regardless of the fact that it is a corner case, it seemed to me that if there was an erroneous piece of logic in the code it was best to fix it for all than just fix it on my side... just for the sakes of code base robustness. These changes fixed the CI issues, except for this error which does not seem to be related to my edit (?):
|
do we know why it was not detected by current tests? |
Not sure, but it would be simple to test. FYI, in my case, I was just needing to display an overlay of a net on a head for a small GUI app that I coded to digitize electrode positions with the Polhemus Fastrak system (https://github.com/christian-oreilly/fastrak_digitizer/blob/main/fastrakdigitizer/main.py#L532). Somehow, in some instances, the accurate method was taking forever whereas the nearest neighbor method was very fast and I did not need accuracy for this operation since it is just a visualization to guide the user so I don't care for it to be precise to the mm. |
that one should be fixed now by #10933, so if you merge in (or rebase against) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@drammock merge if happy
would still be nice to add a test that failed on |
Something like that would test that. Check if that code seems kosher to your @drammock , and if so, I can wrap it in a test function and commit it. from pathlib import Path
import mne
from mne.datasets import sample
from mne.transforms import _get_trans, transform_surface_to, apply_trans
from mne.bem import read_bem_surfaces
from mne.surface import _project_onto_surface
import pandas as pd
import numpy as np
data_path = Path(sample.data_path())
surf_path = data_path / "subjects" / "sample" / "bem" / "sample-head.fif"
trans_fname = data_path / 'MEG' / 'sample' / 'sample_audvis_raw-trans.fif'
trans = mne.read_trans(trans_fname)
head_surf = transform_surface_to(surf=read_bem_surfaces(surf_path)[0],
dest="mri",
trans=_get_trans(trans, 'head', 'mri'),
copy=True)
montage = mne.channels.make_standard_montage('GSN-HydroCel-129')
info = mne.create_info(montage.ch_names, 100, ch_types='eeg')
raw = mne.io.RawArray(np.zeros((len(montage.ch_names), 100)), info)
raw.set_montage(montage)
mri_fiducials = mne.coreg.get_mni_fiducials("sample", data_path / "subjects")
mri_fid_loc = pd.DataFrame(np.array([fid["r"] for fid in mri_fiducials]),
index=[fid["ident"]._name.split("_")[-1] for fid in mri_fiducials],
columns=["x", "y", "z"])
eeg_picks = mne.pick_types(info, meg=False, eeg=True, ref_meg=False)
eeg_loc = np.array([raw.info['chs'][k]['loc'][:3] for k in eeg_picks])
cap_fid_loc = pd.DataFrame(np.array([fid["r"] for fid in raw.info["dig"][:3]]),
index=[fid["ident"] for fid in raw.info["dig"][:3]],
columns=["x", "y", "z"])
trans = mne.coreg.fit_matched_points(cap_fid_loc.values, mri_fid_loc.values,
out='trans', scale=True)
eeg_loc = apply_trans(trans, eeg_loc)
eeg_loc = _project_onto_surface(eeg_loc, head_surf, project_rrs=True,
return_nn=True, method="nearest neighbor")[2] |
looks reasonable. Couple of quick comments:
|
side comment: here's why we never caught this before: |
1 - Great Side comment: yeah... that is part of the exchange we had with @larsoner where he was saying it is a corner case, currently impossible to reach from the public interface. Nevertheless, if it raises an exception, I guess it is worth fixing, 1) for people like me who hack their way around (after all, this is a toolbox used mainly for research I expect, so people hacking its inner functions to make them do things not currently supported by the public interface is to be expected) and 2) it makes it more robust to future development which may call this function internally for new use cases/functionalities... I'll commit the test. |
mri_fids, frame = _get_fid_coords(mri_fiducials) | ||
mri_fid_loc = np.array(list(mri_fids.values())) | ||
# get montage fiducials | ||
cap_fids, frame = _get_fid_coords(raw.info['dig']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@christian-oreilly just FYI, _get_fid_coords
is a useful private func for testing, to replace the list comprehensions you were using
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the tip. Nice thinking for generalizing the test (i.e., @pytest.mark.parametrize('ret_nn', (False, True))
,
@pytest.mark.parametrize('method', ('accurate', 'nearest')))
.
only remaining CI failures will be addressed by #10944, so this is good to go! Thanks @christian-oreilly |
FIx a bug when calling _project_onto_surface with method != "accurate" and return_nn == True.