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: Add digitization class #6369

Merged
merged 8 commits into from
Jun 4, 2019
Merged

Conversation

massich
Copy link
Contributor

@massich massich commented May 23, 2019

This PR:

On the top, here is a summary of which readers go through _test_raw_reader, if so with was type(info['dig']): None, Digitization, or both. And for those readers expected to not have Digitization do they have montage. The goal of this table is to keep in mind the current status + plan following PRs.

                       | _test_raw_reader | None | Digitization | other   |
-----------------------+------------------+------+--------------+---------+
RawArray               |     x            |  x   |              |         |
read_raw_artemis123    |     x            |      |     x        |         |   
read_raw_bdf           |                  |      |              | montage |
read_raw_brainvision   |     x            |  x   |     x        |         |    
read_raw_bti           |     x            |  x   |     x        |         |
read_raw_cnt           |     x            |  x   |              | montage |
read_raw_ctf           |     x            |      |     x        |         |
read_raw_edf           |     x            |  x   |     x        |         |
read_raw_eeglab        |     x            |      |     x        |         |
read_raw_egi           |     x            |  x   |              | montage |
read_raw_eximia        |     x            |  x   |              | ------- |
read_raw_fieldtrip     |                  |      |              | ------- |
read_raw_fif           |     x            |      |     x        |         |
read_raw_gdf           |     x            |  x   |              | montage |
read_raw_kit           |     x            |  x   |     x        |         |
read_raw_nicolet       |     x            |  x   |              | montage |

@lgtm-com
Copy link

lgtm-com bot commented May 23, 2019

This pull request introduces 1 alert when merging 835f0e0 into b9b2c68 - view on LGTM.com

new alerts:

  • 1 for Unreachable code

Comment posted by LGTM.com

@codecov
Copy link

codecov bot commented May 27, 2019

Codecov Report

Merging #6369 into master will increase coverage by <.01%.
The diff coverage is 94.87%.

@@            Coverage Diff             @@
##           master    #6369      +/-   ##
==========================================
+ Coverage   89.26%   89.27%   +<.01%     
==========================================
  Files         410      411       +1     
  Lines       74435    74469      +34     
  Branches    12312    12316       +4     
==========================================
+ Hits        66446    66482      +36     
+ Misses       5135     5131       -4     
- Partials     2854     2856       +2

@lgtm-com
Copy link

lgtm-com bot commented May 27, 2019

This pull request introduces 1 alert when merging 7f37ecb into 5093d00 - view on LGTM.com

new alerts:

  • 1 for Unreachable code

Comment posted by LGTM.com

self._items = list()
elif all([isinstance(_, kls) for _ in elements]):
if elements is None:
self._items = list()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

move this on the previous condition.
if elements is None or (isinstance(elements, list) and not elements):

self._items = deepcopy(list(elements))
else:
# XXX: _msg should not be Digitization related
_msg = 'Digitization expected a iterable of DigPoint objects.'
Copy link
Contributor Author

@massich massich May 29, 2019

Choose a reason for hiding this comment

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

this should be addressed. (the tests should be modified aswell)

@massich massich marked this pull request as ready for review May 29, 2019 14:39
@massich massich requested review from agramfort and larsoner and removed request for agramfort May 29, 2019 14:40
@@ -156,6 +158,7 @@ def _unique_channel_names(ch_names):


# XXX Eventually this should be de-duplicated with the MNE-MATLAB stuff...
# XXX: Digitization, Docstrings need a pass changing lists for Digitization
Copy link
Member

Choose a reason for hiding this comment

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

Is this still true?

Copy link
Contributor Author

@massich massich May 29, 2019

Choose a reason for hiding this comment

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

The one I added? yes. I did not do the pass. True the pass is not needed there but on the refactorized.


class NamedFloat(_Named, float):
"""Float with a name in __repr__."""

pass

class MNEObjectsList(MutableSequence):
Copy link
Member

Choose a reason for hiding this comment

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

One problem I expect with this subclassing MutableSequence instead of list is that mne.externals.h5io.write_hdf5(...) will not work on it. IIRC currently you can write_hdf5 on info objects and it will work because all info entries and Python built-in types. After this PR it will not. Can you check? If this is the case we should fix it somehow.

I would consider just subclassing list like we do for SourceSpaces, and if at some point we want to not subclass list for these sorts of things, we can change Digitization and SourceSpaces at the same time.

Copy link
Member

Choose a reason for hiding this comment

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

I have the same feeling as @larsoner here. Subclassing list is not a great pattern but it's simple. We just want to have a repr. The argument to make sure that it contains only instance of DigPoint is fair but do we really expect to have the problem with users hacking the info['dig'] manually? I don't expect anyone to do this and think that it will be fine...

my 2c

Copy link
Contributor Author

@massich massich May 29, 2019

Choose a reason for hiding this comment

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

I can make MNEObjectsList derive from list() I can leave with it.

I am not expecting "users" to mess up the list, but I do like to have some safety nets when writing digitizations, montages, etc.. (or force developers of new readers to use these safeties) I can always get read of this class and do that in Digitization, or keep it as a private thing. But we have lots of lists of things and we never ensure those elements are always the same. (if I'm not mistaken, this object does not prevent insertions of other types. I thought YAGNI, and that it was easy to add if needed)

Copy link
Member

Choose a reason for hiding this comment

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

can we avoid the MNEObjectsList and have Digitization inherit from list? it would remove a lot of code in this PR

Copy link
Member

Choose a reason for hiding this comment

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

It's a trade off between safety net and barrier to write new code. The more you nest classes, the less accessible it becomes to new contributors. I tend to lean more on the side of assuming good intent -- i.e., if you hack info['dig'] you are on your own.

@lgtm-com
Copy link

lgtm-com bot commented May 29, 2019

This pull request introduces 1 alert when merging 8b17361 into f4ff170 - view on LGTM.com

new alerts:

  • 1 for Unreachable code

Comment posted by LGTM.com

@@ -73,3 +74,16 @@ def __eq__(self, other): # noqa: D105
return False
else:
return np.allclose(self['r'], other['r'])


class Digitization(MNEObjectsList):
Copy link
Member

Choose a reason for hiding this comment

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

New public class has been added but it's not documented in API reference.

@massich
Copy link
Contributor Author

massich commented Jun 3, 2019

Do we miss entry to the glossary? cc: @drammock
Shall we review the visualization module? cc: @GuillaumeFavelier

@@ -663,13 +663,15 @@ def object_size(x):
x : object
Object to approximate the size of.
Can be anything comprised of nested versions of:
{dict, list, tuple, ndarray, str, bytes, float, int, None}.
{dict, list, tuple, ndarray, str, bytes, float, int, None,
Digitization}.
Copy link
Member

Choose a reason for hiding this comment

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

maybe the changes in this file are not needed as Digitization is just a list?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

great catch!

@massich
Copy link
Contributor Author

massich commented Jun 3, 2019

This should be green. Feel free to merge.

@@ -261,7 +261,7 @@ def _make_dig_points(nasion=None, lpa=None, rpa=None, hpi=None,
'kind': FIFF.FIFFV_POINT_EEG,
'coord_frame': FIFF.FIFFV_COORD_HEAD})

return _format_dig_points(dig)
return Digitization(_format_dig_points(dig))
Copy link
Member

Choose a reason for hiding this comment

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

It looks like things would be a bit simpler if _format_dig_points returned a list cast to Digitization already. Then there wouldn't need to be a bunch of Digitization(_format_dig_points(...)) calls

Copy link
Member

Choose a reason for hiding this comment

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

agreed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, that was on my list already. But I can do it here. no prob.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would have liked better to do it the other way around. Prefer to import a constructor and have a call that does something = MyConstructor() than importing a private function and call something = _my_obscure_func(foo).

But since I'll be doing subsequent PRs in these things, I'll change it back.

@GuillaumeFavelier
Copy link
Contributor

@massich as we discussed we could review the visualization module. I think having a dig.plot() function could be a good idea for two reasons. For context encapsulation and from a user point of view, it would be easier to use. Also, something similar is already done for other classes (i.e. stc.plot() and evoked.plot()) so it's consistent with the architecture. If you want, we can discuss how to make it work with a potential follow-up PR, what do you think?

@drammock
Copy link
Member

drammock commented Jun 3, 2019

Do we miss entry to the glossary? cc: @drammock

Added "Digitization" to TODO list in #6321

@massich
Copy link
Contributor Author

massich commented Jun 4, 2019

@GuillaumeFavelier great! we should open an issue and cross reference it here.

@massich massich changed the title Add digitization class ENH: Add digitization class Jun 4, 2019
@massich massich merged commit dbda584 into mne-tools:master Jun 4, 2019
@massich massich deleted the add_Digitization branch June 4, 2019 16:33
@massich massich mentioned this pull request Jun 17, 2019
19 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants