Skip to content
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

Using Pymovements with MIT1003 #853

Open
nisar2 opened this issue Oct 18, 2024 · 11 comments
Open

Using Pymovements with MIT1003 #853

nisar2 opened this issue Oct 18, 2024 · 11 comments

Comments

@nisar2
Copy link

nisar2 commented Oct 18, 2024

Question

Hi. I'm trying to analyze the MIT1003 dataset and perform some processing on it. I get an error when detecting microsaccades: threshold does not provide enough variance as required by min_threshold ([0. 0.] < 1e-10). The code runs for several files but eventually breaks. I think I'm probably setting up things incorrectly.

Sample Code

experiment = pm.gaze.Experiment( # parameters from some code provided by dataset creators

    screen_width_px=1024,
    screen_height_px=768,
    screen_width_cm=40.5,
    screen_height_cm=30,
    distance_cm=75,
    origin='upper left',
    sampling_rate=240,
)

filename_format = r'{filename}.csv'

filename_format_dtypes = {
    'filename': str,
}

custom_read_kwargs = {
    'separator': ',',
}

time_unit = 'step'
pixel_columns = ['x', 'y']

dataset_definition = pm.DatasetDefinition(
    name='my_dataset',
    experiment=experiment,
    filename_format=filename_format,
    filename_format_dtypes=filename_format_dtypes,
    custom_read_kwargs=custom_read_kwargs,
    time_column=time_column,
    time_unit=time_unit,
    pixel_columns=pixel_columns,
)

dataset = pm.Dataset(
    definition=dataset_definition,
    path='/shared/project-storage/users/nisar2/projects/pymovement/data/MIT1003',
)

dataset.load()

dataset.pix2deg()
dataset.pos2vel(method='savitzky_golay', degree=2, window_length=7)
dataset.apply('pos2acc', degree=2, window_length=7)
dataset.detect_events('ivt')
dataset.detect_events('microsaccades') # breaks here after processing several of the files (though not sure if processing correctly)

Please include relevant code snippets or files that provide context for your question.

One of the data files is attached:
ajs_i05june05_static_street_boston_p1010764.csv

@nisar2 nisar2 changed the title [QUESTION SUMMARY] Using Pymovements with MIT1003 Using Pymovements with MIT1003 Oct 18, 2024
@SiQube
Copy link
Member

SiQube commented Oct 19, 2024

could you show the error you're getting?

@nisar2
Copy link
Author

nisar2 commented Oct 19, 2024

Here's the error:

threshold does not provide enough variance as required by min_threshold ([0. 0.] < 1e-10)

@SiQube
Copy link
Member

SiQube commented Oct 19, 2024

can you show the entire output?

@nisar2
Copy link
Author

nisar2 commented Oct 19, 2024

7525it [00:05, 1310.10it/s]

{
	"name": "ValueError",
	"message": "threshold does not provide enough variance as required by min_threshold ([0. 0.] < 1e-10)",
	"stack": "---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[70], line 9
      1 # dataset.pix2deg()
      2 # print('here1')
      3 # dataset.pos2vel(method='savitzky_golay', degree=2, window_length=7)
   (...)
      6 # print('here3')
      7 # dataset.detect_events('ivt', name='fixation.ivt')
      8 print('here4')
----> 9 dataset.detect_events('microsaccades', minimum_duration=12)
     10 print('here5')
     11 # dataset.compute_event_properties(\"dispersion\")
     12 # print('here6')
     13 # dataset.compute_event_properties(['amplitude', 'peak_velocity'])
     14 # print('here7')
     15 # pm.plotting.main_sequence_plot(dataset.events[0])
     16 # print('here8')

File ~/anaconda3/envs/diffts/lib/python3.9/site-packages/pymovements/dataset/dataset.py:537, in Dataset.detect_events(self, method, eye, clear, verbose, **kwargs)
    500 def detect_events(
    501         self,
    502         method: Callable[..., EventDataFrame] | str,
   (...)
    507         **kwargs: Any,
    508 ) -> Dataset:
    509     \"\"\"Detect events by applying a specific event detection method.
    510 
    511     Parameters
   (...)
    535         If gaze files have not been loaded yet or gaze files do not contain the right columns.
    536     \"\"\"
--> 537     return self.detect(
    538         method=method,
    539         eye=eye,
    540         clear=clear,
    541         verbose=verbose,
    542         **kwargs,
    543     )

File ~/anaconda3/envs/diffts/lib/python3.9/site-packages/pymovements/dataset/dataset.py:593, in Dataset.detect(self, method, eye, clear, verbose, **kwargs)
    589 disable_progressbar = not verbose
    590 for file_id, (gaze, fileinfo_row) in tqdm(
    591         enumerate(zip(self.gaze, self.fileinfo.to_dicts())), disable=disable_progressbar,
    592 ):
--> 593     gaze.detect(method, eye=eye, clear=clear, **kwargs)
    594     # workaround until events are fully part of the GazeDataFrame
    595     gaze.events.frame = dataset_files.add_fileinfo(
    596         definition=self.definition,
    597         df=gaze.events.frame,
    598         fileinfo=fileinfo_row,
    599     )

File ~/anaconda3/envs/diffts/lib/python3.9/site-packages/pymovements/gaze/gaze_dataframe.py:668, in GazeDataFrame.detect(self, method, eye, clear, **kwargs)
    659 if self.trial_columns is None:
    660     method_kwargs = self._fill_event_detection_kwargs(
    661         method,
    662         gaze=self.frame,
   (...)
    665         **kwargs,
    666     )
--> 668     new_events = method(**method_kwargs)
    670     self.events.frame = pl.concat(
    671         [self.events.frame, new_events.frame],
    672         how='diagonal',
    673     )
    674 else:

File ~/anaconda3/envs/diffts/lib/python3.9/site-packages/pymovements/events/detection/_microsaccades.py:108, in microsaccades(velocities, timesteps, minimum_duration, threshold, threshold_factor, minimum_threshold, include_nan, name)
    105     threshold = np.array(threshold)
    107 if (threshold < minimum_threshold).any():
--> 108     raise ValueError(
    109         'threshold does not provide enough variance as required by min_threshold'
    110         f' ({threshold} < {minimum_threshold})',
    111     )
    113 # Radius of elliptic threshold.
    114 radius = threshold * threshold_factor

ValueError: threshold does not provide enough variance as required by min_threshold ([0. 0.] < 1e-10)"
}

@SiQube
Copy link
Member

SiQube commented Oct 19, 2024

it seems that in your dataframe there are only 0. velocities, maybe you can loop over the files while extracting the events and check whether the dataframe is empty or just 0 velocities?

@SiQube
Copy link
Member

SiQube commented Oct 21, 2024

if you run again into the problem feel free to reopen the issue

@SiQube SiQube closed this as completed Oct 21, 2024
@nisar2
Copy link
Author

nisar2 commented Nov 19, 2024

Thank you! I found that the samples that were causing these problems had eye stationary eye tracking data so it made sense that they would lead to 0 velocities, as you suggested. I removed them and was able to run the code.

However, now I'm getting a different error when trying to use the dataset.compute_event_properties:

experiment = pm.gaze.Experiment( # parameters from some code provided by dataset creators

    screen_width_px=1024,
    screen_height_px=768,
    screen_width_cm=40.5,
    screen_height_cm=30,
    distance_cm=75,
    origin='upper left',
    sampling_rate=240,
)

filename_format = r'{filename}.csv'

filename_format_dtypes = {
    'filename': str,
}

custom_read_kwargs = {
    'separator': ',',
}

time_unit = 'step'
pixel_columns = ['x', 'y']

dataset_definition = pm.DatasetDefinition(
    name='my_dataset',
    experiment=experiment,
    filename_format=filename_format,
    filename_format_dtypes=filename_format_dtypes,
    custom_read_kwargs=custom_read_kwargs,
    time_column=time_column,
    time_unit=time_unit,
    pixel_columns=pixel_columns,
)

dataset = pm.Dataset(
    definition=dataset_definition,
    path='/shared/project-storage/users/nisar2/projects/pymovement/data/MIT1003',
)

dataset.load()

dataset.pix2deg()
dataset.pos2vel(method='savitzky_golay', degree=2, window_length=7)
dataset.apply('pos2acc', degree=2, window_length=7)
dataset.detect_events('ivt')
dataset.detect_events('microsaccades') 
dataset.compute_event_properties("dispersion") # breaks here

here is the error output:

{
	"name": "RuntimeError",
	"message": "No events with name \"None\" found in data frame",
	"stack": "---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[33], line 13
     11 # dataset.compute_event_properties(\"dispersion\")
     12 print('here6')
---> 13 dataset.compute_event_properties(['amplitude', 'peak_velocity'])
     14 print('here7')
     15 pm.plotting.main_sequence_plot(dataset.events[0])

File ~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/dataset/dataset.py:640, in Dataset.compute_event_properties(self, event_properties, name, verbose)
    638 disable_progressbar = not verbose
    639 for events, gaze in tqdm(zip(self.events, self.gaze), disable=disable_progressbar):
--> 640     new_properties = processor.process(
    641         events, gaze, identifiers=identifier_columns, name=name,
    642     )
    643     join_on = identifier_columns + ['name', 'onset', 'offset']
    644     events.add_event_properties(new_properties, join_on=join_on)

File ~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:209, in EventGazeProcessor.process(self, events, gaze, identifiers, name)
    206     joined_frame = joined_frame.filter(pl.col('name').str.contains(f'^{name}$'))
    208 if len(joined_frame) == 0:
--> 209     raise RuntimeError(f'No events with name \"{name}\" found in data frame')
    211 result = (
    212     joined_frame
    213     .filter(pl.col('time').is_between(pl.col('onset'), pl.col('offset')))
   (...)
    222     )
    223 )
    224 return result

RuntimeError: No events with name \"None\" found in data frame"
}

@SiQube
Copy link
Member

SiQube commented Nov 19, 2024

hi -- thank you for your feedback -- the code you're showing and the code that outputs the error seem to be not the same.could you provide the output for your actual code snippet?

@SiQube
Copy link
Member

SiQube commented Nov 19, 2024

however, the error indicates that no event were detect, could you check if this happens for one of the event dataframes?

we should integrate a more helpful error message if this is the case.

@nisar2
Copy link
Author

nisar2 commented Nov 19, 2024

Hi sorry for that. Here is the code:

experiment = pm.gaze.Experiment( # parameters from some code provided by dataset creators

    screen_width_px=1024,
    screen_height_px=768,
    screen_width_cm=40.5,
    screen_height_cm=30,
    distance_cm=75,
    origin='upper left',
    sampling_rate=240,
)

filename_format = r'{filename}.csv'

filename_format_dtypes = {
    'filename': str,
}

custom_read_kwargs = {
    'separator': ',',
}

time_unit = 'step'
pixel_columns = ['x', 'y']

dataset_definition = pm.DatasetDefinition(
    name='my_dataset',
    experiment=experiment,
    filename_format=filename_format,
    filename_format_dtypes=filename_format_dtypes,
    custom_read_kwargs=custom_read_kwargs,
    time_column=time_column,
    time_unit=time_unit,
    pixel_columns=pixel_columns,
)

dataset = pm.Dataset(
    definition=dataset_definition,
    path='/shared/project-storage/users/nisar2/projects/pymovement/data/MIT1003',
)

dataset.load()

dataset.pix2deg()
dataset.pos2vel(method='savitzky_golay', degree=2, window_length=7)
dataset.apply('pos2acc', degree=2, window_length=7)
dataset.detect_events('ivt')
dataset.detect_events('microsaccades') 
dataset.compute_event_properties("dispersion") # breaks here

and the correct output/error message:

100%|██████████| 15042/15042 [00:12<00:00, 1210.69it/s]
100%|██████████| 15042/15042 [00:11<00:00, 1322.10it/s]
100%|██████████| 15042/15042 [00:11<00:00, 1321.83it/s]
15042it [00:09, 1659.89it/s]
15042it [00:10, 1388.71it/s]
5041it [00:16, 297.60it/s]

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[9], [line 6](vscode-notebook-cell:?execution_count=9&line=6)
      [4](vscode-notebook-cell:?execution_count=9&line=4) dataset.detect_events('ivt', name='fixation.ivt')
      [5](vscode-notebook-cell:?execution_count=9&line=5) dataset.detect_events('microsaccades', minimum_duration=12)
----> [6](vscode-notebook-cell:?execution_count=9&line=6) dataset.compute_event_properties("dispersion")
      [7](vscode-notebook-cell:?execution_count=9&line=7) # dataset.compute_event_properties(['amplitude', 'peak_velocity'])
      [8](vscode-notebook-cell:?execution_count=9&line=8) # pm.plotting.main_sequence_plot(dataset.events[0])

File ~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/dataset/dataset.py:640, in Dataset.compute_event_properties(self, event_properties, name, verbose)
    [638](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/dataset/dataset.py:638) disable_progressbar = not verbose
    [639](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/dataset/dataset.py:639) for events, gaze in tqdm(zip(self.events, self.gaze), disable=disable_progressbar):
--> [640](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/dataset/dataset.py:640)     new_properties = processor.process(
    [641](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/dataset/dataset.py:641)         events, gaze, identifiers=identifier_columns, name=name,
    [642](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/dataset/dataset.py:642)     )
    [643](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/dataset/dataset.py:643)     join_on = identifier_columns + ['name', 'onset', 'offset']
    [644](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/dataset/dataset.py:644)     events.add_event_properties(new_properties, join_on=join_on)

File ~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:209, in EventGazeProcessor.process(self, events, gaze, identifiers, name)
    [206](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:206)     joined_frame = joined_frame.filter(pl.col('name').str.contains(f'^{name}$'))
    [208](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:208) if len(joined_frame) == 0:
--> [209](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:209)     raise RuntimeError(f'No events with name "{name}" found in data frame')
    [211](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:211) result = (
    [212](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:212)     joined_frame
    [213](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:213)     .filter(pl.col('time').is_between(pl.col('onset'), pl.col('offset')))
...
    [222](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:222)     )
    [223](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:223) )
    [224](https://file+.vscode-resource.vscode-cdn.net/shared/project-storage/users/nisar2/projects/diff-eye/diff-eye/~/anaconda3/envs/diffeye/lib/python3.10/site-packages/pymovements/events/processing.py:224) return result

RuntimeError: No events with name "None" found in data frame

Regarding your second comment, it seems that detecting events like fixations and microsaccades works fine, but the issue is when I try to use compute_event_properties. Also, computing event properties works for many samples of data before crashing on the 5041 example. I hope I answered your question, but let me know if I can clarify further.

@SiQube
Copy link
Member

SiQube commented Nov 20, 2024

can you reinstall pymovements from source, and then run again? if the error persists I'll reproduce it on my machine and patch it!

thank you so much for your coorperation

@SiQube SiQube reopened this Nov 20, 2024
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

No branches or pull requests

2 participants