Skip to content

Commit

Permalink
[EEG Browser] Add ability to view annotations in event panel and over…
Browse files Browse the repository at this point in the history
…laid on signal viewer (#8235)

The changes in this PR fill in a few gaps in the code and allow for annotation data to be viewed in the EEG Browser. Annotations are displayed in orange in the Events / Annotation Panel and when selected are shown as an overlay in the signal viewer.

Replaces #7828
  • Loading branch information
laemtl authored Nov 24, 2022
1 parent 1d3a4d0 commit 2ac39b0
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@ class ElectrophysiologySessionView extends Component {
}
return resp.json();
})
.then((data) => {
.then((data) => {
const database = data.database.map((dbEntry) => ({
...dbEntry,
// EEG Visualisation urls
// EEG Visualization parameters
chunksURLs:
dbEntry
&& dbEntry.file.chunks_urls.map(
Expand All @@ -219,6 +219,9 @@ class ElectrophysiologySessionView extends Component {
+ '/electrophysiology_browser/file_reader/?file='
+ group.links[1].file
),
annotations:
dbEntry
&& dbEntry.file.annotations,
}));

this.setState({
Expand Down Expand Up @@ -318,6 +321,7 @@ class ElectrophysiologySessionView extends Component {
chunksURLs,
epochsURL,
electrodesURL,
annotations,
} = this.state.database[i];
const file = this.state.database[i].file;
const splitPagination = [];
Expand Down Expand Up @@ -346,7 +350,8 @@ class ElectrophysiologySessionView extends Component {
chunksURLs?.[file.splitData?.splitIndex] || chunksURLs
}
epochsURL={epochsURL}
electrodesURL={electrodesURL}
electrodesURL={electrodesURL}
annotations={annotations}
>
<Panel
id='channel-viewer'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {setDomain, setInterval} from '../series/store/state/bounds';
import {updateFilteredEpochs} from '../series/store/logic/filterEpochs';
import {setElectrodes} from '../series/store/state/montage';
import {Channel} from '../series/store/types';
import {AnnotationMetadata} from '../series/store/types';

declare global {
interface Window {
Expand All @@ -28,6 +29,7 @@ type CProps = {
chunksURL: string,
epochsURL: string,
electrodesURL: string,
annotations: AnnotationMetadata,
limit: number,
};

Expand Down Expand Up @@ -67,6 +69,7 @@ class EEGLabSeriesProvider extends Component<CProps> {
chunksURL,
epochsURL,
electrodesURL,
annotations,
limit,
} = props;

Expand Down Expand Up @@ -106,20 +109,45 @@ class EEGLabSeriesProvider extends Component<CProps> {
this.store.dispatch(setInterval(timeInterval));
}
}
).then(() => Promise.race(racers(fetchText, epochsURL)).then((text) => {
).then(() => Promise.race(racers(fetchText, epochsURL))
.then((text) => {
if (!(typeof text.json === 'string'
|| text.json instanceof String)) return;
return tsvParse(
text.json.replace('trial_type', 'label'))
.map(({onset, duration, label}, i) => ({
onset: parseFloat(onset),
duration: parseFloat(duration),
type: 'Event',
label: label,
comment: null,
channels: 'all',
}));
}).then(events => {
let epochs = events;
annotations.instances.map(instance => {
const label = annotations.labels
.find(label =>
label.AnnotationLabelID == instance.AnnotationLabelID
).LabelDescription;
epochs.push({
onset: parseFloat(instance.Onset),
duration: parseFloat(instance.Duration),
type: 'Annotation',
label: label,
comment: null,
channels: 'all',
});
});
return epochs;
}).then(epochs => {
this.store.dispatch(
setEpochs(tsvParse(
text.json.replace('trial_type', 'label'))
.map(({onset, duration, label}, i) => ({
onset: parseFloat(onset),
duration: parseFloat(duration),
type: 'Event',
label: label,
comment: null,
channels: 'all',
}))
setEpochs(
epochs
.flat()
.sort(function(a, b) {
return a.onset - b.onset;
})
)
);
this.store.dispatch(updateFilteredEpochs());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export type Epoch = {
channels: number[] | "all",
};

export type AnnotationMetadata = {
instances: any[],
labels: any[],
metadata: any[]
}

export type RightPanel = 'annotationForm' | 'epochList' | null;

export type Electrode = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class ElectrophysioAnnotations

$annotationLabels = $db->pselect(
'SELECT * FROM physiological_annotation_label',
['PFID' => $this->_physioFileID]
[]
);

$this->_data = [
Expand Down
13 changes: 5 additions & 8 deletions modules/electrophysiology_browser/php/sessions.class.inc
Original file line number Diff line number Diff line change
Expand Up @@ -477,15 +477,12 @@ class Sessions extends \NDB_Page
['PFID' => $physioFileID]
);

//Get the annotation data if the output type is derivative
//Get the annotation data if the output type is derivative
if (strcmp($fileOutput, 'derivative') == 0) {
$annotations = new ElectrophysioAnnotations(
intval($physioFileID)
);
$fileSummary['annotations'] = $annotations->getData();
}
//Get the annotation data
$annotations = new ElectrophysioAnnotations(
intval($physioFileID)
);

$fileSummary['annotations'] = $annotations->getData();
$fileSummary['output_type'] = $fileOutput;
$fileSummary['splitData'] = $physioFileObj->getSplitData(0);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ function setUp(): void
[
'SessionID' => '999999',
'PhysiologicalOutputTypeID' => 22,
'InsertedByUser' => 'Unit Tester',
'FilePath' => '/path/to/test/file',
'FileType' => 'testType'
]
);
Expand All @@ -128,6 +130,8 @@ function setUp(): void
[
'SessionID' => '999997',
'PhysiologicalOutputTypeID' => 23,
'InsertedByUser' => 'Unit Tester',
'FilePath' => '/path/to/test/file2',
'FileType' => 'testType2'
]
);
Expand Down

0 comments on commit 2ac39b0

Please # to comment.