Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 81 additions & 15 deletions mne/data/html_templates.py
Original file line number Diff line number Diff line change
@@ -1,78 +1,101 @@
import uuid
from ..externals.tempita import Template


info_template = Template("""
{{style}}

<table class="table table-hover">

<tr>
<th colspan="2" style="text-align: left;">
<label for={{section_ids[0]}}> {{sections[0]}} </label>
</th>
</tr>

<tr class="{{section_ids[0]}}">
<th>Measurement date</th>
{{if meas_date is not None}}
<td>{{meas_date}}</td>
{{else}}<td>Unknown</td>{{endif}}
</tr>
<tr>
<tr class="{{section_ids[0]}}">
<th>Experimenter</th>
{{if info['experimenter'] is not None}}
<td>{{info['experimenter']}}</td>
{{else}}<td>Unknown</td>{{endif}}
</tr>
<tr class="{{section_ids[0]}}">
<th>Participant</th>
{{if info['subject_info'] is not None}}
{{if 'his_id' in info['subject_info'].keys()}}
<td>{{info['subject_info']['his_id']}}</td>
{{endif}}
{{else}}<td>Unknown</td>{{endif}}
</tr>

<tr>
<th colspan="2" style="text-align: left;">
<label for={{section_ids[1]}}> {{sections[1]}} </label>
</th>
</tr>

<tr class="{{section_ids[1]}}">
<th>Digitized points</th>
{{if info['dig'] is not None}}
<td>{{len(info['dig'])}} points</td>
{{else}}
<td>Not available</td>
{{endif}}
</tr>
<tr>
<tr class="{{section_ids[1]}}">
<th>Good channels</th>
<td>{{n_mag}} magnetometer, {{n_grad}} gradiometer,
and {{n_eeg}} EEG channels</td>
</tr>
<tr>
<tr class="{{section_ids[1]}}">
<th>Bad channels</th>
{{if info['bads'] is not None}}
<td>{{', '.join(info['bads'])}}</td>
{{else}}<td>None</td>{{endif}}
</tr>
<tr>
<tr class="{{section_ids[1]}}">
<th>EOG channels</th>
<td>{{eog}}</td>
</tr>
<tr>
<tr class="{{section_ids[1]}}">
<th>ECG channels</th>
<td>{{ecg}}</td>
</tr>

<tr>
<th colspan="2" style="text-align: left;">
<label for={{section_ids[2]}}> {{sections[2]}} </label>
</th>
</tr>
<tr class="{{section_ids[2]}}">
<th>Sampling frequency</th>
<td>{{u'%0.2f' % info['sfreq']}} Hz</td>
</tr>
<tr>
<tr class="{{section_ids[2]}}">
<th>Highpass</th>
<td>{{u'%0.2f' % info['highpass']}} Hz</td>
</tr>
<tr>
<tr class="{{section_ids[2]}}">
<th>Lowpass</th>
<td>{{u'%0.2f' % info['lowpass']}} Hz</td>
</tr>
</table>
""")

raw_template = Template("""
{{info_repr[:-9]}}
<tr>
{{if filenames is not None}}
<tr class="{{section_ids[2]}}">
<th>Filenames</th>
<td>{{', '.join(filenames)}}</td>
</tr>
<tr>
{{endif}}
{{if duration is not None}}
<tr class="{{section_ids[2]}}">
<th>Duration</th>
<td>{{duration}} (HH:MM:SS)</td>
</tr>
{{endif}}
</table>
""")

Expand Down Expand Up @@ -100,3 +123,46 @@
</tr>
</table>
""")


def _section_style(section_id):
"""Set CSS style for collapsible section's label."""
html = f"""#{section_id} ~ table [for="{section_id}"]::before {{
display: inline-block;
content: "►";
font-size: 11px;
width: 15px;
text-align: left;
}}

#{section_id}:checked ~ table [for="{section_id}"]::before {{
content: "▼";
}}

#{section_id} ~ table tr.{section_id} {{
visibility: collapse;
}}

#{section_id}:checked ~ table tr.{section_id} {{
visibility: visible;
}}
"""
return html


def _collapsible_sections_reprt_html(sections):
"""Set style and unique ID for all collapsible sections."""
style = "<style> label { cursor: pointer; }"
ids_ = []
for section in sections:
section_id = f"section_{str(uuid.uuid4())}"
style += _section_style(section_id)
ids_.append(section_id)
style += "</style>"

for i in ids_:
style += f"""
<input type="checkbox" id="{i}" hidden aria-hidden="true"/>
"""

return style, ids_
6 changes: 2 additions & 4 deletions mne/io/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
from ..viz import plot_raw, plot_raw_psd, plot_raw_psd_topo, _RAW_CLIP_DEF
from ..event import find_events, concatenate_events
from ..annotations import Annotations, _combine_annotations, _sync_onset
from ..data.html_templates import raw_template


class TimeMixin(object):
Expand Down Expand Up @@ -1709,9 +1708,8 @@ def _repr_html_(self, caption=None):
m, s = divmod(self._last_time - self.first_time, 60)
h, m = divmod(m, 60)
duration = f'{int(h):02d}:{int(m):02d}:{int(s):02d}'
return raw_template.substitute(
info_repr=self.info._repr_html_(caption=caption),
filenames=basenames, duration=duration)
return self.info._repr_html_(
caption=caption, filenames=basenames, duration=duration)

def add_events(self, events, stim_channel=None, replace=False):
"""Add events to stim channel.
Expand Down
12 changes: 9 additions & 3 deletions mne/io/meas_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
_dig_kind_rev, _dig_kind_ints, _read_dig_fif)
from ._digitization import write_dig as _dig_write_dig
from .compensator import get_current_comp
from ..data.html_templates import info_template
from ..data.html_templates import (info_template,
_collapsible_sections_reprt_html)

b = bytes # alias

Expand Down Expand Up @@ -809,7 +810,8 @@ def pick_channels(self, ch_names, ordered=False):
def ch_names(self):
return self['ch_names']

def _repr_html_(self, caption=None):
def _repr_html_(self, caption=None, filenames=None,
duration=None):
if isinstance(caption, str):
html = f'<h4>{caption}</h4>'
else:
Expand All @@ -831,9 +833,13 @@ def _repr_html_(self, caption=None):
if meas_date is not None:
meas_date = meas_date.strftime("%B %d, %Y %H:%M:%S") + ' GMT'

sections = ['General', 'Channels', 'Data']
style, section_ids = _collapsible_sections_reprt_html(sections)
html += info_template.substitute(
style=style, section_ids=section_ids, sections=sections,
caption=caption, info=self, meas_date=meas_date, n_eeg=n_eeg,
n_grad=n_grad, n_mag=n_mag, eog=eog, ecg=ecg)
n_grad=n_grad, n_mag=n_mag, eog=eog, ecg=ecg, filenames=filenames,
duration=duration)
return html


Expand Down
2 changes: 1 addition & 1 deletion tutorials/intro/plot_20_events_from_raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

In the :ref:`introductory tutorial <overview-tut-events-section>` we saw an
example of reading experimental events from a :term:`"STIM" channel <stim
channel>`; here we'll discuss :term:`events` and :term:`annotations` more
channel>`; here we will discuss :term:`events` and :term:`annotations` more
broadly, give more detailed information about reading from STIM channels, and
give an example of reading events that are in a marker file or included in
the data file as an embedded array. The tutorials :ref:`tut-event-arrays` and
Expand Down
2 changes: 1 addition & 1 deletion tutorials/misc/plot_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
# will open the HTML in a new tab in the browser. To disable this, use the
# ``open_browser=False`` parameter of :meth:`~mne.Report.save`.
#
# For our first example, we'll generate a barebones report for all the
# For our first example, we will generate a barebones report for all the
# :file:`.fif` files containing raw data in the sample dataset, by passing the
# pattern ``*raw.fif`` to :meth:`~mne.Report.parse_folder`. We'll omit the
# ``subject`` and ``subjects_dir`` parameters from the :class:`~mne.Report`
Expand Down