Skip to content

Commit f230b21

Browse files
authored
Merge pull request hed-standard#741 from VisLab/develop
Handled nan conversion in df_to_hed
2 parents bae6b55 + f2e7174 commit f230b21

10 files changed

Lines changed: 248 additions & 101 deletions

hed/tools/analysis/annotation_util.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,18 @@ def df_to_hed(dataframe, description_tag=True):
3232
description_tag (bool): If True description tag is included.
3333
3434
Returns:
35-
dict: A dictionary compatible compatible with BIDS JSON tabular file that includes HED.
35+
dict: A dictionary compatible with BIDS JSON tabular file that includes HED.
3636
3737
Notes:
3838
- The DataFrame must have the columns with names: column_name, column_value, description, and HED.
3939
4040
"""
41-
missing_cols = check_df_columns(dataframe)
41+
df = dataframe.fillna('n/a')
42+
missing_cols = check_df_columns(df)
4243
if missing_cols:
4344
raise HedFileError("RequiredColumnsMissing", f"Columns {str(missing_cols)} are missing from dataframe", "")
4445
hed_dict = {}
45-
for index, row in dataframe.iterrows():
46+
for index, row in df.iterrows():
4647
if row['HED'] == 'n/a' and row['description'] == 'n/a':
4748
continue
4849
if row['column_value'] == 'n/a':

hed/tools/analysis/event_manager.py

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
""" Manages events of temporal extent. """
22

3-
from hed.tools.analysis.temporal_event import TemporalEvent
43
from hed.models.model_constants import DefTagNames
4+
from hed.models.df_util import get_assembled
5+
from hed.tools.analysis.temporal_event import TemporalEvent
56

67

78
class EventManager:
89

9-
def __init__(self, hed_strings, onsets, def_dict):
10-
""" Create an event manager for an events file. Manages events of temporal extent. This
10+
def __init__(self, input_data, hed_schema, extra_defs=None):
11+
""" Create an event manager for an events file. Manages events of temporal extent.
1112
1213
Parameters:
13-
data (TabularInput): A tabular input file.
14-
schema (HedSchema): A HED schema
14+
input_data (TabularInput): Represents an events file with its sidecar.
15+
hed_schema (HedSchema): HED schema used in this
16+
extra_defs (DefinitionDict): Extra definitions not included in the input_data information.
1517
1618
:raises HedFileError:
1719
- if there are any unmatched offsets.
@@ -21,40 +23,61 @@ def __init__(self, hed_strings, onsets, def_dict):
2123
2224
"""
2325

24-
self.event_list = [[] for _ in range(len(onsets))]
25-
self.onsets = onsets
26-
self.hed_strings = hed_strings
27-
self.def_dict = def_dict
28-
self.contexts = []
29-
self._create_event_list()
26+
self.event_list = [[] for _ in range(len(input_data.dataframe))]
27+
self.hed_schema = hed_schema
28+
self.def_dict = input_data.get_def_dict(hed_schema, extra_def_dicts=extra_defs)
29+
self.onsets = input_data.dataframe['onset'].tolist()
30+
self.hed_strings = None # Remaining HED strings copy.deepcopy(hed_strings)
31+
self.anchor_dict = {}
32+
self._create_event_list(input_data)
33+
self._create_anchor_list()
34+
35+
# def iter_context(self):
36+
# """ Iterate rows of context.
37+
#
38+
# Yields:
39+
# int: position in the dataFrame
40+
# HedString: Context
41+
#
42+
# """
43+
#
44+
# for index in range(len(self.contexts)):
45+
# yield index, self.contexts[index]
46+
47+
def _create_anchor_list(self):
48+
""" Populate the dictionary of def names to list of temporal events.
3049
31-
def iter_context(self):
32-
""" Iterate rows of context.
50+
:raises HedFileError:
51+
- If the hed_strings contain unmatched offsets.
3352
34-
Yields:
35-
int: position in the dataFrame
36-
HedString: Context
53+
Notes:
3754
3855
"""
56+
for index, events in enumerate(self.event_list):
57+
for event in events:
58+
index_list = self.anchor_dict.get(event.anchor, [])
59+
index_list.append(event)
60+
self.anchor_dict[event.anchor] = index_list
3961

40-
for index in range(len(self.contexts)):
41-
yield index, self.contexts[index]
42-
43-
def _create_event_list(self):
44-
""" Create a list of events of extended duration.
62+
def _create_event_list(self, input_data):
63+
""" Populate the event_list with the events with temporal extent indexed by event number.
4564
4665
:raises HedFileError:
4766
- If the hed_strings contain unmatched offsets.
4867
4968
Notes:
5069
5170
"""
71+
hed_strings, def_dict = get_assembled(input_data, input_data._sidecar, self.hed_schema,
72+
extra_def_dicts=None, join_columns=True,
73+
shrink_defs=True, expand_defs=False)
5274
onset_dict = {} # Temporary dictionary keeping track of temporal events that haven't ended yet.
53-
for event_index, hed in enumerate(self.hed_strings):
75+
for event_index, hed in enumerate(hed_strings):
5476
self._extract_temporal_events(hed, event_index, onset_dict)
5577
# Now handle the events that extend to end of list
5678
for item in onset_dict.values():
5779
item.set_end(len(self.onsets), None)
80+
self.hed_strings = hed_strings
5881

5982
def _extract_temporal_events(self, hed, event_index, onset_dict):
6083
""" Extract the temporal events and remove them from the other HED strings.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
""" Manages events of temporal extent. """
2+
3+
from hed.tools.analysis.temporal_event import TemporalEvent
4+
from hed.models.model_constants import DefTagNames
5+
6+
7+
class EventManagerCopy:
8+
9+
def __init__(self, input_data, hed_schema, extra_def_dict=None):
10+
""" Create an event manager for an events file. Manages events of temporal extent. This
11+
12+
Parameters:
13+
hed_strings (list): A list of HED strings
14+
onsets (list): A list of onset times that is the same length as hed_strings
15+
def_dict (DefinitionDict): Contains the definitions for this dataset.
16+
17+
:raises HedFileError:
18+
- if there are any unmatched offsets.
19+
20+
Notes: Keeps the events of temporal extend by their starting index in events file. These events
21+
are separated from the rest of the annotations.
22+
23+
"""
24+
25+
self.event_list = [[] for _ in range(len(onsets))]
26+
self.onsets = onsets
27+
self.hed_strings = hed_strings ## copy.deepcopy(hed_strings)
28+
self.def_dict = def_dict
29+
self.anchor_dict ={}
30+
self._create_event_list()
31+
self._create_anchor_list()
32+
33+
# def iter_context(self):
34+
# """ Iterate rows of context.
35+
#
36+
# Yields:
37+
# int: position in the dataFrame
38+
# HedString: Context
39+
#
40+
# """
41+
#
42+
# for index in range(len(self.contexts)):
43+
# yield index, self.contexts[index]
44+
45+
def _create_anchor_list(self):
46+
""" Populate the dictionary of def names to list of temporal events.
47+
48+
:raises HedFileError:
49+
- If the hed_strings contain unmatched offsets.
50+
51+
Notes:
52+
53+
"""
54+
for index, events in enumerate(self.event_list):
55+
for event in events:
56+
index_list = self.anchor_dict.get(event.anchor, [])
57+
index_list.append(event)
58+
self.anchor_dict[event.anchor] = index_list
59+
60+
def _create_event_list(self):
61+
""" Populate the event_list with the events with temporal extent indexed by event number.
62+
63+
:raises HedFileError:
64+
- If the hed_strings contain unmatched offsets.
65+
66+
Notes:
67+
68+
"""
69+
onset_dict = {} # Temporary dictionary keeping track of temporal events that haven't ended yet.
70+
for event_index, hed in enumerate(self.hed_strings):
71+
self._extract_temporal_events(hed, event_index, onset_dict)
72+
# Now handle the events that extend to end of list
73+
for item in onset_dict.values():
74+
item.set_end(len(self.onsets), None)
75+
76+
def _extract_temporal_events(self, hed, event_index, onset_dict):
77+
""" Extract the temporal events and remove them from the other HED strings.
78+
79+
Parameters:
80+
hed (HedString): The assembled HedString at position event_index in the data.
81+
event_index (int): The position of this string in the data.
82+
onset_dict (dict): Running dict that keeps track of temporal events that haven't yet ended.
83+
84+
Note:
85+
This removes the events of temporal extent from the HED string.
86+
87+
"""
88+
if not hed:
89+
return
90+
group_tuples = hed.find_top_level_tags(anchor_tags={DefTagNames.ONSET_KEY, DefTagNames.OFFSET_KEY},
91+
include_groups=2)
92+
to_remove = []
93+
for tup in group_tuples:
94+
anchor_tag = tup[1].find_def_tags(recursive=False, include_groups=0)[0]
95+
anchor = anchor_tag.extension.lower()
96+
if anchor in onset_dict or tup[0].short_base_tag.lower() == DefTagNames.OFFSET_KEY:
97+
temporal_event = onset_dict.pop(anchor)
98+
temporal_event.set_end(event_index, self.onsets[event_index])
99+
if tup[0] == DefTagNames.ONSET_KEY:
100+
new_event = TemporalEvent(tup[1], event_index, self.onsets[event_index])
101+
self.event_list[event_index].append(new_event)
102+
onset_dict[anchor] = new_event
103+
to_remove.append(tup[1])
104+
hed.remove(to_remove)
105+
106+
def _set_event_contexts(self):
107+
""" Creates an event context for each hed string.
108+
109+
Notes:
110+
The event context would be placed in an event context group, but is kept in a separate array without the
111+
event context group or tag.
112+
113+
"""
114+
# contexts = [[] for _ in range(len(self.hed_strings))]
115+
# for onset in self.onset_list:
116+
# for i in range(onset.start_index+1, onset.end_index):
117+
# contexts[i].append(onset.contents)
118+
# for i in range(len(self.hed_strings)):
119+
# contexts[i] = HedString(",".join(contexts[i]), hed_schema=self.hed_schema)
120+
# self.contexts = contexts
121+
print("_set_event_contexts not implemented yet")
122+
123+
def _update_onset_list(self, group, onset_dict, event_index):
124+
""" Process one onset or offset group to create onset_list.
125+
126+
Parameters:
127+
group (HedGroup): The HedGroup containing the onset or offset.
128+
onset_dict (dict): A dictionary of OnsetGroup objects that keep track of span of an event.
129+
event_index (int): The event number in the list.
130+
131+
:raises HedFileError:
132+
- if an unmatched offset is encountered.
133+
134+
Notes:
135+
- Modifies onset_dict and onset_list.
136+
"""
137+
# def_tags = group.find_def_tags(recursive=False, include_groups=0)
138+
# name = def_tags[0].extension
139+
# onset_element = onset_dict.pop(name, None)
140+
# if onset_element:
141+
# onset_element.end_index = event_index
142+
# self.onset_list.append(onset_element)
143+
# elif is_offset:
144+
# raise HedFileError("UnmatchedOffset", f"Unmatched {name} offset at event {event_index}", " ")
145+
# if not is_offset:
146+
# onset_element = TemporalEvent(name, group, event_index)
147+
# onset_dict[name] = onset_element

hed/tools/analysis/hed_context_manager.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ def __init__(self, hed_strings, hed_schema):
4545
self.onset_list = []
4646
self.onset_count = 0
4747
self.offset_count = 0
48-
self.contexts = []
4948
self._create_onset_list()
5049
self._set_event_contexts()
5150

hed/tools/analysis/hed_type_definitions.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,16 @@
55

66

77
class HedTypeDefinitions:
8+
"""
89
10+
Properties:
11+
def_map (dict): keys are definition names, values are dict {type_values, description, tags}
12+
Example: A definition 'famous-face-cond' with contents
13+
`(Condition-variable/Face-type,Description/A face that should be recognized by the participants,(Image,(Face,Famous)))`
14+
would have type_values ['face_type']. All items are strings not objects.
15+
16+
17+
"""
918
def __init__(self, definitions, hed_schema, type_tag='condition-variable'):
1019
""" Create a definition manager for a type of variable.
1120
@@ -14,8 +23,6 @@ def __init__(self, definitions, hed_schema, type_tag='condition-variable'):
1423
hed_schema (Hedschema or HedSchemaGroup): The schema used for parsing.
1524
type_tag (str): Lower-case HED tag string representing the type managed.
1625
17-
# TODO: [Refactor] - should dict be allowed for definitions.
18-
1926
"""
2027

2128
self.type_tag = type_tag.lower()
@@ -26,8 +33,8 @@ def __init__(self, definitions, hed_schema, type_tag='condition-variable'):
2633
self.definitions = definitions
2734
else:
2835
self.definitions = {}
29-
self.def_map = self._extract_def_map() # maps def names to conditions.
30-
self.type_map = self._extract_type_map()
36+
self.def_map = self._extract_def_map()
37+
self.type_map = self._extract_type_map() #
3138

3239
def get_type_values(self, item):
3340
""" Return a list of type_tag values in item.

0 commit comments

Comments
 (0)