| 1027 | |
| 1028 | |
| 1029 | def _check_sphere(sphere, info=None, sphere_units="m"): |
| 1030 | from ..bem import ConductorModel, fit_sphere_to_headshape, get_fitting_dig |
| 1031 | |
| 1032 | if sphere is None: |
| 1033 | sphere = HEAD_SIZE_DEFAULT |
| 1034 | if info is not None: |
| 1035 | # Decide if we have enough dig points to do the auto fit |
| 1036 | try: |
| 1037 | get_fitting_dig(info, "extra", verbose="error") |
| 1038 | except (RuntimeError, ValueError): |
| 1039 | pass |
| 1040 | else: |
| 1041 | sphere = "auto" |
| 1042 | |
| 1043 | if isinstance(sphere, str): |
| 1044 | _check_option( |
| 1045 | "sphere", sphere, ("auto", "eeglab", "extra", "eeg", "cardinal", "hpi") |
| 1046 | ) |
| 1047 | |
| 1048 | if isinstance(sphere, str) and sphere == "eeglab": |
| 1049 | assert info is not None |
| 1050 | |
| 1051 | # We need coordinates for the 2D plane formed by |
| 1052 | # Fpz<->Oz and T7<->T8, as this plane will be the horizon (i.e. it |
| 1053 | # will determine the location of the head circle). |
| 1054 | # |
| 1055 | # We implement some special-handling in case Fpz is missing, as this seems to be |
| 1056 | # a quite common situation in numerous EEG labs. |
| 1057 | montage = info.get_montage() |
| 1058 | if montage is None: |
| 1059 | raise ValueError( |
| 1060 | 'No montage was set on your data, but sphere="eeglab" can only work if ' |
| 1061 | "digitization points for the EEG channels are available. Consider " |
| 1062 | "calling set_montage() to apply a montage." |
| 1063 | ) |
| 1064 | ch_pos = montage.get_positions()["ch_pos"] |
| 1065 | horizon_ch_names = ("Fpz", "Oz", "T7", "T8") |
| 1066 | |
| 1067 | if "FPz" in ch_pos: # "fix" naming |
| 1068 | ch_pos["Fpz"] = ch_pos["FPz"] |
| 1069 | del ch_pos["FPz"] |
| 1070 | elif "Fpz" not in ch_pos and "Oz" in ch_pos: |
| 1071 | logger.info( |
| 1072 | "Approximating Fpz location by mirroring Oz along the X and Y axes." |
| 1073 | ) |
| 1074 | # This assumes Fpz and Oz have the same Z coordinate |
| 1075 | ch_pos["Fpz"] = ch_pos["Oz"] * [-1, -1, 1] |
| 1076 | |
| 1077 | for ch_name in horizon_ch_names: |
| 1078 | if ch_name not in ch_pos: |
| 1079 | msg = ( |
| 1080 | f'sphere="eeglab" requires digitization points of the following ' |
| 1081 | f"electrode locations in the data: {', '.join(horizon_ch_names)}, " |
| 1082 | f"but could not find: {ch_name}" |
| 1083 | ) |
| 1084 | if ch_name == "Fpz": |
| 1085 | msg += ", and was unable to approximate its location from Oz" |
| 1086 | raise ValueError(msg) |