The problem is that you have your columns separated by a mixture of spaces and tabs, but MNE-Python expects tabs only in XYZ files.
So if we fix it like this:
1 0 0 1 A1
2 0 -0.19937 0.97992 A2
3 0 -0.39073 0.9205 A3
4 0 -0.56641 0.82413 A4
5 -0.27528 -0.66458 0.69466 A5
6 -0.50865 -0.50865 0.69466 A6
7 -0.59637 -0.59637 0.5373 A7
8 -0.54874 -0.75528 0.35837 A8
9 -0.57972 -0.79792 0.16505 A9
10 -0.58743 -0.80852 -0.034899 A10
11 -0.57154 -0.78666 -0.23345 A11
12 -0.53271 -0.73322 -0.42262 A12
13 -0.28006 -0.86195 -0.42262 A13
14 -0.30048 -0.92478 -0.23345 A14
15 -0.30883 -0.95048 -0.034899 A15
16 -0.30478 -0.93801 0.16505 A16
17 -0.28849 -0.88789 0.35837 A17
18 -0.32275 -0.77919 0.5373 A18
19 0 -0.71934 0.69466 A19
20 0 -0.84339 0.5373 A20
21 0 -0.93358 0.35837 A21
22 0 -0.98629 0.16505 A22
23 0 -0.99939 -0.034899 A23
24 0 -0.97237 -0.23345 A24
25 0 -0.90631 -0.42262 A25
26 0.28006 -0.86195 -0.42262 A26
27 0.30048 -0.92478 -0.23345 A27
28 0.30883 -0.95048 -0.034899 A28
29 0.30478 -0.93801 0.16505 A29
30 0.28849 -0.88789 0.35837 A30
31 0.32275 -0.77919 0.5373 A31
32 0.27528 -0.66458 0.69466 A32
33 0.18961 -0.061608 0.97992 B1
34 0.27629 -0.27629 0.9205 B2
35 0.50865 -0.50865 0.69466 B3
36 0.59637 -0.59637 0.5373 B4
37 0.54874 -0.75528 0.35837 B5
38 0.57972 -0.79792 0.16505 B6
39 0.58743 -0.80852 -0.034899 B7
40 0.57154 -0.78666 -0.23345 B8
41 0.53271 -0.73322 -0.42262 B9
42 0.78666 -0.57154 -0.23345 B10
43 0.80852 -0.58743 -0.034899 B11
44 0.79792 -0.57972 0.16505 B12
45 0.75528 -0.54874 0.35837 B13
46 0.95048 -0.30883 -0.034899 B14
47 0.93801 -0.30478 0.16505 B15
48 0.88789 -0.28849 0.35837 B16
49 0.77919 -0.32275 0.5373 B17
50 0.66458 -0.27528 0.69466 B18
51 0.49052 -0.2832 0.82413 B19
52 0.39073 0 0.9205 B20
53 0.56641 0 0.82413 B21
54 0.71934 0 0.69466 B22
55 0.84339 0 0.5373 B23
56 0.93358 0 0.35837 B24
57 0.98629 0 0.16505 B25
58 0.99939 0 -0.034899 B26
59 0.95048 0.30883 -0.034899 B27
60 0.93801 0.30478 0.16505 B28
61 0.88789 0.28849 0.35837 B29
62 0.77919 0.32275 0.5373 B30
63 0.66458 0.27528 0.69466 B31
64 0.49052 0.2832 0.82413 B32
65 0.11719 0.16129 0.97992 C1
66 0.27629 0.27629 0.9205 C2
67 0.50865 0.50865 0.69466 C3
68 0.59637 0.59637 0.5373 C4
69 0.75528 0.54874 0.35837 C5
70 0.79792 0.57972 0.16505 C6
71 0.80852 0.58743 -0.034899 C7
72 0.58743 0.80852 -0.034899 C8
73 0.57972 0.79792 0.16505 C9
74 0.54874 0.75528 0.35837 C10
75 0.2832 0.49052 0.82413 C11
76 0.27528 0.66458 0.69466 C12
77 0.32275 0.77919 0.5373 C13
78 0.28849 0.88789 0.35837 C14
79 0.30478 0.93801 0.16505 C15
80 0.30883 0.95048 -0.034899 C16
81 0 0.99939 -0.034899 C17
82 0 0.98629 0.16505 C18
83 0 0.93358 0.35837 C19
84 0 0.84339 0.5373 C20
85 0 0.71934 0.69466 C21
86 0 0.56641 0.82413 C22
87 0 0.39073 0.9205 C23
88 -0.2832 0.49052 0.82413 C24
89 -0.27528 0.66458 0.69466 C25
90 -0.32275 0.77919 0.5373 C26
91 -0.28849 0.88789 0.35837 C27
92 -0.30478 0.93801 0.16505 C28
93 -0.30883 0.95048 -0.034899 C29
94 -0.58743 0.80852 -0.034899 C30
95 -0.57972 0.79792 0.16505 C31
96 -0.54874 0.75528 0.35837 C32
97 -0.11719 0.16129 0.97992 D1
98 -0.27629 0.27629 0.9205 D2
99 -0.50865 0.50865 0.69466 D3
100 -0.59637 0.59637 0.5373 D4
101 -0.75528 0.54874 0.35837 D5
102 -0.79792 0.57972 0.16505 D6
103 -0.80852 0.58743 -0.034899 D7
104 -0.95048 0.30883 -0.034899 D8
105 -0.93801 0.30478 0.16505 D9
106 -0.88789 0.28849 0.35837 D10
107 -0.77919 0.32275 0.5373 D11
108 -0.66458 0.27528 0.69466 D12
109 -0.49052 0.2832 0.82413 D13
110 -0.39073 0 0.9205 D14
111 -0.18961 -0.061608 0.97992 D15
112 -0.27629 -0.27629 0.9205 D16
113 -0.49052 -0.2832 0.82413 D17
114 -0.56641 0 0.82413 D18
115 -0.71934 0 0.69466 D19
116 -0.84339 0 0.5373 D20
117 -0.93358 0 0.35837 D21
118 -0.98629 0 0.16505 D22
119 -0.99939 0 -0.034899 D23
120 -0.95048 -0.30883 -0.034899 D24
121 -0.93801 -0.30478 0.16505 D25
122 -0.88789 -0.28849 0.35837 D26
123 -0.77919 -0.32275 0.5373 D27
124 -0.66458 -0.27528 0.69466 D28
125 -0.75528 -0.54874 0.35837 D29
126 -0.79792 -0.57972 0.16505 D30
127 -0.80852 -0.58743 -0.034899 D31
128 -0.78666 -0.57154 -0.23345 D32
129 -0.57219 0.78756 -0.2288 EXG1
130 0.58743 0.80852 -0.2349 EXG2
131 -0.30883 0.95048 -0.4349 EXG3
132 0.30883 0.95048 -0.4349 EXG4
133 -0.97751 -0.15881 -0.13872 EXG5
134 0.95048 -0.15442 -0.1349 EXG6
135 0 0.99939 -0.3349 EXG7
136 0 0 0 EXG8
we can successfully load and visualize the montage:
import mne
montage_path = '~/Development/Support/mne-python/montage-xyz/montage_fixed_delim.xyz'
montage = mne.channels.read_custom_montage(fname=montage_path)
montage.plot()
But you can see that something is off: the head circle is way too small. This is because MNE interprets the values in the XYZ file as coordinates in meters, and the head circle is made for a head with a … well, more natural size.
The problem with all these different data formats is that they’re so poorly specified. So while we could try to fix the reader in MNE, I’d suggest to manually import and scale the original data, so you wouldn’t even have to worry about this “mixed tabs and spaces thing” and can work directly with the file you originally shared above. We’ll use pandas to read the data; pandas can readily handle mixed delimiters (which pandas calls “separators”, as it uses the term “delimiters” for a different thing…):
import pandas as pd
import mne
montage_path = '~/Development/Support/mne-python/montage-xyz/montage.xyz'
montage_data = pd.read_csv(
montage_path,
sep='\s+|\t+', # multiple spaces or tabs
header=None,
names=['ch_idx', 'x', 'y', 'z', 'ch_name'],
engine='python' # avoid a warning
)
montage_data = montage_data.drop(columns=['ch_idx']) # We don't need it
montage_data = montage_data.set_index('ch_name', drop=True)
# Now scale based on the head radius (i.e., a value of 1 becomes equal to the head radius)
head_radius = 0.095 # in meters
montage_data *= head_radius
# %%
# Prepare for creation of our custom montage – MNE needs the data in the following shape
ch_name_to_pos_mapping = montage_data.T.to_dict(orient='list')
# Finally, create the montage
montage = mne.channels.make_dig_montage(
ch_pos=montage_data.T.to_dict(orient='list') # need to get it into the right shape
)
montage.plot()
Voila!