-
Notifications
You must be signed in to change notification settings - Fork 118
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
First implementation of the Hypnogram class #116
Conversation
Codecov ReportBase: 91.64% // Head: 92.37% // Increases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## master #116 +/- ##
==========================================
+ Coverage 91.64% 92.37% +0.72%
==========================================
Files 22 23 +1
Lines 2753 3054 +301
==========================================
+ Hits 2523 2821 +298
- Misses 230 233 +3
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
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.
SO COOL @raphaelvallat! No major suggestions from me. As usual, lots to say but not much of substance 🙃
… into hypnogram_class
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.
Current status approved in spirit, but I see you have more you'd like to implement so lmk when you want a full review with formal approval.
Btw, you're call but I would support merging this as-is and then adding "full functionality" in a separate PR. I'm not sure how big of a project that is, but if just the base class was in master I'd start some PRs with it. |
Suggested method: class Hypnogram:
...
def summary(self): # or .get_dataframe
"""
Return a pandas DataFrame summarizing epoch-level information.
Column order and names are compliant with BIDS events files [BIDSevents]_
and MNE events/annotations dataframes [MNEannotations]_.
Returns
-------
summary : :py:class:`pandas.DataFrame`
A dataframe containing epoch onset, duration, stage, etc.
References
----------
.. [BIDSevents] https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/05-task-events.html
.. [MNEannotations] https://mne.tools/stable/glossary.html#term-annotations
"""
data = {
"onset": self.timedelta.total_seconds(),
"duration": 1 / self.sampling_frequency,
"value": self.as_int().to_numpy(),
"description": self.hypno.to_numpy(),
"epoch": 1 + np.arange(self.n_epochs),
}
if hypno.scorer is not None:
data["scorer"] = hypno.scorer
return pd.DataFrame(data) |
@remrama agreed for the new method! What do you think about calling it Also, when I'll wait for your reply, add this new method and then request your final approval before merging 🎉 ! |
Either are cool with me, although it's probably more of a BIDS/events emphasis than an MNE/annotation emphasis.
Ya good question. Definitely want to always have the I think in this case, if the Hypnogram includes timestamp info it should be added as an additional column rather than replacing |
In the future, maybe we could go even one step further and add an Question: why start {"epoch": 1 + np.arange(self.n_epochs)}
After second thought, I think that for the initial implementation I would only include |
Maybe >>> from yasa import Hypnogram
>>> hyp = Hypnogram(["W", "W", "LIGHT", "LIGHT", "DEEP", "REM", "WAKE"], n_stages=4)
>>> hyp.as_annotations()
onset duration value description
epoch
1 0.0 30.0 0 WAKE
2 30.0 30.0 0 WAKE
3 60.0 30.0 2 LIGHT
4 90.0 30.0 2 LIGHT
5 120.0 30.0 3 DEEP
6 150.0 30.0 4 REM
7 180.0 30.0 0 WAKE |
Love the
Ya you called me out on this :) Start it at 0. I wasn't sure about that one, it's just that technically it is the 1st epoch, and the Python indexing can be confusing for new users. But you're right, submit to Python indexing.
Yep that's good. If someone really wants timestamp that can add it trivially with one more line.
That looks great! It won't break things, neither BIDS or MNE expect that column. It's not an incredibly useful column anyways, it's really just a row number... Leave it starting at 0 and so basically we're just renaming that axis to |
Ready for your final review @remrama ! |
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.
Ship it
* Initial class creation for Hypnogram * Add properties + mapping * Add sleep_statistics and upsample * Add mapping for all n_stages + SFI * Fix in sleep_statistics when all WAKE * Minor edits * Added `scorer` and two new methods * Add docstring * Start adding unittest for Hypnogram class * Add more docstring * Add main docstring + unit test upsample_to_data * Uncommented upsample function * Add to API * Add unit tests for 3-5 stages hypnogram * Added consolidate_stages method * First minor comments from PR review * Initial class creation for Hypnogram * Add properties + mapping * Add sleep_statistics and upsample * Add mapping for all n_stages + SFI * Fix in sleep_statistics when all WAKE * Minor edits * Added `scorer` and two new methods * Add docstring * Start adding unittest for Hypnogram class * Add more docstring * Add main docstring + unit test upsample_to_data * Uncommented upsample function * Add to API * Add unit tests for 3-5 stages hypnogram * Added consolidate_stages method * First minor comments from PR review * Add docstring for method `upsample` * Added as_annotations method * Minor docstring edits * Epoch starts at 0 in `as_annotations` * Updated changelog * Fix typo
Merged to |
Hi,
This PR introduces a first working implementation of the
yasa.Hypnogram
class, which will be the new standard way to deal with hypnograms in YASA moving forward, as discussed in #105.This should greatly simplify with implementation of the performance evaluation pipeline (#78).
Remaining tasks
Hypnogram.consolidate_stages
methodImplement the@remrama will implement in a separate PR.Hypnogram.plot_hypnogram
function. Here I'm not sure if we should re-implement from scratch, or instead use the existingyasa.plot_hypnogram
function and add support to 2, 3 and 4-stages hypnograms. The latter will require adding the parametern_stages
to the function however.Hypnogram.as_int()
to get a NumPy array with integer values.@remrama I would appreciate your review on this (but no rush!). Let me know if you see any ideas for improvements and/or new class methods or properties that may be useful.
Thanks,
Raphael