Skip to content

Conversation

@larsoner
Copy link
Member

@larsoner larsoner commented Dec 5, 2019

Closes #7116.

First step, replicate the failure (hopefully). It passes locally on Linux but hopefully Azure shows the issue.

  • Use datetime | None objects for info['meas_date'].
  • Use datetime | None for raw.annotations.orig_time
  • Add code for set_meas_date that takes care of annotations and such. The anonymization code can use this / be refactored to use it. It only takes datetime | None as an argument.
  • Extend set_meas_date and/or anonymize functions to kill some of these other dates (such as meas_id)
  • Fix bug where anonymizing would shift annotations by raw._first_time
  • Fix problems in Windows (fromtimestamp)

@larsoner
Copy link
Member Author

larsoner commented Dec 5, 2019

This is on its way to passing because the bug was already fixed in #7036. I'll re-title and eventually make this into a PR to use datetime objects with meas_date (hopefully).

@larsoner larsoner changed the title WIP, FIX: Fix meas_date info repr WIP: Use datetime objects for meas_date Dec 5, 2019
@codecov
Copy link

codecov bot commented Dec 5, 2019

Codecov Report

Merging #7124 into master will increase coverage by 0.01%.
The diff coverage is 91.45%.

@@            Coverage Diff             @@
##           master    #7124      +/-   ##
==========================================
+ Coverage    89.7%   89.71%   +0.01%     
==========================================
  Files         444      444              
  Lines       78997    79091      +94     
  Branches    12674    12689      +15     
==========================================
+ Hits        70863    70956      +93     
- Misses       5320     5322       +2     
+ Partials     2814     2813       -1

@larsoner
Copy link
Member Author

larsoner commented Dec 6, 2019

FYI I found a bug in master. This code:

import numpy as np
import mne
from mne.annotations import _handle_meas_date

meas_date = (1, 2)
raw = mne.io.RawArray(10e-6 * np.sin(np.linspace(0, 2*np.pi, 10000))[None],
                      mne.create_info(1, 1000., 'eeg'), first_samp=2000)
try:  # PR
    raw.set_meas_date(meas_date)
except:  # master
    raw.info['meas_date'] = meas_date
    raw.annotations.orig_time = _handle_meas_date(meas_date)
raw.annotations.append(3 + raw._first_time, 1, '3-4')
raw.plot()
raw.anonymize()
raw.plot()

Does something bad to the annotation:

Screenshot from 2019-12-06 12-28-07

Screenshot from 2019-12-06 12-30-05

It's fixed in this PR.

And then I noticed that this same code does not produce an annotation in the same place when meas_date=None at the top because of how we treat annotations in that case (the raw._first_time had to be there if and only if meas_date was not None), which seems like a bug. Removing it makes tests and code more consistent, and much simpler.

@larsoner larsoner changed the title WIP: Use datetime objects for meas_date ENH, FIX: Use datetime objects for meas_date Dec 6, 2019
@larsoner
Copy link
Member Author

larsoner commented Dec 6, 2019

Tests pass locally, this is ready for review/merge from my end

@larsoner larsoner changed the title ENH, FIX: Use datetime objects for meas_date MRG, ENH: Use datetime objects for meas_date Dec 6, 2019
raw = _raw_annot(None, None)
assert raw.annotations.orig_time is None
assert raw.annotations.onset[0] == 0.5
assert raw.annotations.onset[0] == 1.5
Copy link
Member Author

Choose a reason for hiding this comment

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

@agramfort this is the line that should match above

emit_warning=emit_warning)
new_annotations.onset -= (
meas_date - new_annotations.orig_time).total_seconds()
new_annotations._orig_time = meas_date
Copy link
Member Author

Choose a reason for hiding this comment

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

Hopefully simpler

assert two is not None
shift = one_n_samples / sfreq # to the right by the number of samples
shift += one_first_samp / sfreq # to the right by the offset
shift -= two_first_samp / sfreq # undo its offset
Copy link
Member Author

Choose a reason for hiding this comment

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

Hopefully simpler

"""Test load brainvision annotations and parse them to events."""
sfreq = 1000.0
expected_orig_time = 1384359243.794231
expected_orig_time = _stamp_to_dt((1384359243, 794232))
Copy link
Member

Choose a reason for hiding this comment

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

why do you have all these changes by 1uS ?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think in principle it should be more accurate now, as it uses round rather than int cast. These values I'm assuming were taken from what was produced by the old code, not necessarily what was most correct.

events, _ = events_from_annotations(raw)
latencies = np.sort(events[:, 0])
assert_array_equal(latencies, EXPECTED_LATENCIES)
assert_allclose(latencies, EXPECTED_LATENCIES, atol=1e-6)
Copy link
Member

Choose a reason for hiding this comment

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

why?

Copy link
Member Author

Choose a reason for hiding this comment

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

Same as above I think, we were operating at the precision limit before. Rather than change all values in EXPECTED_LATENCIES I just made it tolerant of a 1 μs error.

assert_allclose(raw.annotations.duration, duration)
assert_allclose(raw_concat.annotations.duration, duration)
assert_allclose(raw.annotations.duration, duration, atol=1e-6)
assert_allclose(raw_concat.annotations.duration, duration, atol=1e-6)
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 necessary? do we have a loss of precision with this change?

Copy link
Member Author

Choose a reason for hiding this comment

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

This one I can push a little fix for

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.

thx @larsoner

feel free to merge when CIs come back green

@larsoner larsoner merged commit b3f22f9 into mne-tools:master Dec 8, 2019
@larsoner larsoner deleted the meas_date branch December 8, 2019 19:33
AdoNunes pushed a commit to AdoNunes/mne-python that referenced this pull request Apr 6, 2020
* TST: Add test for another meas_date

* ENH: Use datetime instead of float

* FIX: Fwd

* FIX: Simplifications

* ENH: Add set_meas_date

* FIX: Unify treatment of first_samp

* FIX: Ref

* FIX: Ref

* FIX: Closer

* FIX: Replicate and fix

* Update test_annotations.py

* FIX: Tweak duration
AdoNunes pushed a commit to AdoNunes/mne-python that referenced this pull request Apr 6, 2020
* TST: Add test for another meas_date

* ENH: Use datetime instead of float

* FIX: Fwd

* FIX: Simplifications

* ENH: Add set_meas_date

* FIX: Unify treatment of first_samp

* FIX: Ref

* FIX: Ref

* FIX: Closer

* FIX: Replicate and fix

* Update test_annotations.py

* FIX: Tweak duration
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.

BUG: printing the info on windows date time

3 participants