Changing EEG locations format from using montages

Hi everyone,

It’s been a while I asked a question.

A question was asked about getting eeg locations from montages from here
electrode positions

When I use that method on an arbitrary data, I get the eeg locations in 3D but in this format

'Fp1' = array([-0.0294367,  0.0839171, -0.00699  ])

whiles if I don’t use the set_montage method, and I use my actual data

raweeg['info']['channels'][0]['locations'][0]

I get this

'Fp1' = {'X': ['-27.0'], 'Y': ['86.0'], 'Z': ['36.0']}

for the locations in 3D.
So my question is when using the set_montage method:

  1. are the locations normalized? and How do I get them to the format
{'X': ['-27.0'], 'Y': ['86.0'], 'Z': ['36.0']}

Also, I found this link eeg_positions it gives all the coordinates in 2d or 3d. I tried comparing them with the 1020 system coordinates using mne.channels.make_standard_montage(“standard_1020”) and they were not the same.
2. Which one is advisable to use?
I am sorry I can’t provide my data for the experiment.

Any help is appreciated.

Hello,

First of all, this line raweeg['info']['channels'][0]['locations'][0] is not valid and will raise.
Next, I believe you are looking at the same electrode position, in 2 different coordinate frames. If I look at the montage on the sample dataset, on the raw object and thus in the head coordinate frame, I get:

from mne.datasets import sample
from mne.io import read_raw_fif


raw = read_raw_fif(
    sample.data_path() / "MEG" / "sample" / "sample_audvis_raw.fif", preload=False
)
raw.pick("eeg").load_data()
raw.get_montage()._get_ch_pos()["EEG 001"]
# array([-0.03737009,  0.10568011,  0.07333875])
raw.info["chs"][0]["loc"][:3]
# array([-0.03737009,  0.10568011,  0.07333875])

Mathieu

HI,

That line is valid and does not raise an error. I believe there are different ways in reading the EEG data especially if the format you are using doesn’t require using read_raw_fif. I use xdf format.

What I am looking for is the electrode coordinate for the 10-20 montage system when I use

mne.channels.make_standard_montage('standard_1020')

in this format

{'X': ['-27.0'], 'Y': ['86.0'], 'Z': ['36.0']}

what i get is

'Fp1' = array([-0.0294367,  0.0839171, -0.00699  ])

in 3D coordinate. So I want to know if those are actual 3d coordinates

All MNE reader functions load a Raw object, in which case the line you describe is not valid. However, reading an XDF file (with pyxdf, not with mne), you get a different data structure that should be (1) parsed and (2) provided to mne.create_info and mne.io.RawArray to create a Raw object for MNE.

Next, mne.channels.make_standard_montage('standard_1020') creates an ideal template 10/20 montage. There is no reason for this template to match the locations found in the XDF file, which can be either from (1) the same or a different template or (2) from an actual digitization measurement device (thus giving true electrode locations).

Next, there is no guarantee the locations in the XDF file are in the head coordinate frame. As a matter of fact, mne.channels.make_standard_montage('standard_1020') does not create a montage in the head coordinate frame either.

from mne.channels import make_standard_montage

montage = make_standard_montage("standard_1020")
montage.dig

This code snippet outputs the lit of digitization points:

<DigPoint |        LPA : (-80.6, -29.1, -41.3) mm  : MRI (surface RAS) frame>,
 <DigPoint |     Nasion : (1.5, 85.1, -34.8) mm     : MRI (surface RAS) frame>,
 <DigPoint |        RPA : (84.4, -28.5, -41.3) mm   : MRI (surface RAS) frame>,
 <DigPoint |     EEG #1 : (-29.4, 83.9, -7.0) mm    : MRI (surface RAS) frame>,
 <DigPoint |     EEG #2 : (0.1, 88.2, -1.7) mm      : MRI (surface RAS) frame>,
 <DigPoint |     EEG #3 : (29.9, 84.9, -7.1) mm     : MRI (surface RAS) frame>,
...

Which are in the MRI coordinate frame. Let’s now apply this montage to a Raw object:

import numpy as np
from mne import create_info
from mne.channels import make_standard_montage
from mne.io import RawArray

montage = make_standard_montage("standard_1020")
info = create_info(montage.ch_names, sfreq=1000., ch_types="eeg")
raw = RawArray(np.zeros((len(montage.ch_names), 1000)), info)
raw.set_montage(montage)
raw.get_montage().dig

Again, we look at the list of digitization points:

<DigPoint |        LPA : (-82.5, -0.0, 0.0) mm     : head frame>,
 <DigPoint |     Nasion : (0.0, 114.0, 0.0) mm      : head frame>,
 <DigPoint |        RPA : (82.5, 0.0, -0.0) mm      : head frame>,
 <DigPoint |     EEG #1 : (-30.9, 114.6, 27.9) mm   : head frame>,
 <DigPoint |     EEG #2 : (-1.3, 119.1, 32.9) mm    : head frame>,
 <DigPoint |     EEG #3 : (28.4, 115.3, 27.7) mm    : head frame>,
...

Now, the montage is in the head coordinate frame. Note that the X, Y, Z coordinate have ‘changed’, but in reality what changed is the position of the origin and the orientation of the X/Y/Z axis, i.e. the coordinate frame.
See also this tutorial about the coordinate frames: Source alignment and coordinate frames — MNE 1.7.1 documentation

I hope that answer your question, good luck!

Mathieu

Hi, thanks for your response.

You are right in your first paragraph.

Secondly, I did not say the locations in the template mne.channels.make_standard_montage('standard_1020') will match that of the xdf file electrode locations.

Well if you use

from mne.channels import make_standard_montage

montage = make_standard_montage("standard_1020")
montage._get_ch_pos()
>>>>  array([-0.0294367,  0.0839171, -0.00699  ])

you will get positions in an numpy object.

Also, when you apply the montage to the mne object, it changes. That’s also true.

  1. My question is it possible to get the location of the template montage in this format (angles)
    {'X': ['-27.0'], 'Y': ['86.0'], 'Z': ['36.0']} which is the output of the measurement device in one of the xdf file rather than this array([-0.0294367, 0.0839171, -0.00699 ]) format.
    I am trying to convert the 3d coordinate into 2d.

  2. I also asked if array([-0.0294367, 0.0839171, -0.00699 ]) were normalized, i want to know if these are the actual coordinate values or they have been transformed.

That is all I am asking.

My question is it possible to get the location of the template montage in this format (angles)
{'X': ['-27.0'], 'Y': ['86.0'], 'Z': ['36.0']} which is the output of the measurement device in one of the xdf file rather than this array([-0.0294367, 0.0839171, -0.00699 ]) format.
I am trying to convert the 3d coordinate into 2d.

You example is still 3D? What do you mean by ‘this format (angles)’?

also asked if array([-0.0294367, 0.0839171, -0.00699 ]) were normalized

There is no normalization, it’s just a matter of coordinate frame and units. Those values are expressed in meters, and the coordinate frame depends (MRI if you get the montage from make_standard_montage, head if you get the montage from a raw object).
In any case, the value you get from montage.dig (or _get_ch_pos) are just the X/Y/Z coordinate of each point in the current montage coordinate frame, expressed in meters.

Mathieu

You example is still 3D? What do you mean by ‘this format (angles)’?

Yeah, the output is in 3D. If i use the make_standard_montage i get the output in 3D. I want to know what the output is expressed in before I can change it to 2D.
Also when i read the xdf file from the measurement device, I get my output in 3D but they look like this
{'X': ['-27.0'], 'Y': ['86.0'], 'Z': ['36.0']} so supposedly I am thinking the output is in degrees. Sorry I said angles, I meant degrees.

it’s just a matter of coordinate frame and units. Those values are expressed in meters, and the coordinate frame depends (MRI if you get the montage from make_standard_montage , head if you get the montage from a raw object).

Okay thank you.

  1. So is it possible to get the actual coordinates in degrees or what I am asking for does not make sense?

Also, what is your take on this eeglocations

You either have cartesian coordinates, or spherical coordinates. X, Y, Z is cartesian coordinates, thus {'X': ['-27.0'], 'Y': ['86.0'], 'Z': ['36.0']} likely represents the X, Y, Z coordinates of your sensor… but maybe in milimeters? I think it’s just a matter of units.

Mathieu

1 Like

Thank you so much. makes sense