'NoneType' object has no attribute '_widget

  • MNE version: e.g. 1.3.0
  • operating system: Windows 10

Hi there, I am now using the following code

brain = plot_glm_surface_projection(raw_haemo.copy().pick("hbo").pick(significant_channels), model_df, colorbar=True)

brain.add_sensors(raw_haemo.info, trans='fsaverage', fnirs=['channels', 'pairs', 'sources', 'detectors'])

to plot my significant result on scalp, but I always get this error. I have tried different types of backend, including: qt, tk, webAgg, notebook etc., none of them are working, I got the same error message with this function. It would be super helpful if you could provide me the solution how to fix it! Thank you.

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[47], line 3
      1 # Plot the projection and sensor locations
      2 get_ipython().run_line_magic('matplotlib', 'inline')
----> 3 brain = plot_glm_surface_projection(raw_haemo.copy().pick("hbo").pick(significant_channels), model_df, colorbar=True)
      5 brain.add_sensors(raw_haemo.info, trans='fsaverage', fnirs=['channels', 'pairs', 'sources', 'detectors'])
      7 # mark the premotor cortex in red

File <decorator-gen-610>:10, in plot_glm_surface_projection(inst, statsmodel_df, picks, value, background, figure, clim, mode, colormap, surface, hemi, size, view, colorbar, distance, subjects_dir, src, verbose)

File D:\Anaconda\envs\fnirs\lib\site-packages\mne_nirs\visualisation\_plot_GLM_surface_projection.py:97, in plot_glm_surface_projection(inst, statsmodel_df, picks, value, background, figure, clim, mode, colormap, surface, hemi, size, view, colorbar, distance, subjects_dir, src, verbose)
     90     raise RuntimeError('MNE data structure does not match dataframe '
     91                        f'results.\nMNE = {info.ch_names}.\n'
     92                        f'GLM = {list(statsmodel_df["ch_name"].values)}')
     94 ea = EvokedArray(np.tile(statsmodel_df[value].values.T, (1, 1)).T,
     95                  info.copy())
---> 97 return _plot_3d_evoked_array(inst, ea, picks=picks,
     98                              value=value,
     99                              background=background, figure=figure,
    100                              clim=clim,
    101                              mode=mode, colormap=colormap,
    102                              surface=surface, hemi=hemi, size=size,
    103                              view=view, colorbar=colorbar,
    104                              distance=distance,
    105                              subjects_dir=subjects_dir, src=src,
    106                              verbose=verbose)

File D:\Anaconda\envs\fnirs\lib\site-packages\mne_nirs\visualisation\_plot_GLM_surface_projection.py:142, in _plot_3d_evoked_array(inst, ea, picks, value, background, figure, clim, mode, colormap, surface, hemi, size, view, colorbar, distance, subjects_dir, src, verbose)
    139 stc = stc_near_sensors(picks=picks, **kwargs, verbose=verbose)
    141 # Produce brain plot
--> 142 brain = stc.plot(src=src, subjects_dir=subjects_dir, hemi=hemi,
    143                  surface=surface, initial_time=0, clim=clim, size=size,
    144                  colormap=colormap, figure=figure, background=background,
    145                  colorbar=colorbar, verbose=verbose)
    146 if view is not None:
    147     brain.show_view(view)

File D:\Anaconda\envs\fnirs\lib\site-packages\mne\source_estimate.py:650, in _BaseSourceEstimate.plot(self, subject, surface, hemi, colormap, time_label, smoothing_steps, transparent, alpha, time_viewer, subjects_dir, figure, views, colorbar, clim, cortex, size, background, foreground, initial_time, time_unit, backend, spacing, title, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs, verbose)
    639 @copy_function_doc_to_method_doc(plot_source_estimates)
    640 def plot(self, subject=None, surface='inflated', hemi='lh',
    641          colormap='auto', time_label='auto', smoothing_steps=10,
   (...)
    648          src=None, volume_options=1., view_layout='vertical',
    649          add_data_kwargs=None, brain_kwargs=None, verbose=None):
--> 650     brain = plot_source_estimates(
    651         self, subject, surface=surface, hemi=hemi, colormap=colormap,
    652         time_label=time_label, smoothing_steps=smoothing_steps,
    653         transparent=transparent, alpha=alpha, time_viewer=time_viewer,
    654         subjects_dir=subjects_dir, figure=figure, views=views,
    655         colorbar=colorbar, clim=clim, cortex=cortex, size=size,
    656         background=background, foreground=foreground,
    657         initial_time=initial_time, time_unit=time_unit, backend=backend,
    658         spacing=spacing, title=title, show_traces=show_traces,
    659         src=src, volume_options=volume_options, view_layout=view_layout,
    660         add_data_kwargs=add_data_kwargs, brain_kwargs=brain_kwargs,
    661         verbose=verbose)
    662     return brain

File <decorator-gen-125>:10, in plot_source_estimates(stc, subject, surface, hemi, colormap, time_label, smoothing_steps, transparent, alpha, time_viewer, subjects_dir, figure, views, colorbar, clim, cortex, size, background, foreground, initial_time, time_unit, backend, spacing, title, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs, verbose)

File D:\Anaconda\envs\fnirs\lib\site-packages\mne\viz\_3d.py:1987, in plot_source_estimates(stc, subject, surface, hemi, colormap, time_label, smoothing_steps, transparent, alpha, time_viewer, subjects_dir, figure, views, colorbar, clim, cortex, size, background, foreground, initial_time, time_unit, backend, spacing, title, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs, verbose)
   1985 else:
   1986     with use_3d_backend(backend):
-> 1987         return _plot_stc(
   1988             stc, overlay_alpha=alpha, brain_alpha=alpha,
   1989             vector_alpha=alpha, cortex=cortex, foreground=foreground,
   1990             size=size, scale_factor=None, show_traces=show_traces,
   1991             src=src, volume_options=volume_options,
   1992             view_layout=view_layout, add_data_kwargs=add_data_kwargs,
   1993             brain_kwargs=brain_kwargs, **kwargs)

File D:\Anaconda\envs\fnirs\lib\site-packages\mne\viz\_3d.py:2110, in _plot_stc(stc, subject, surface, hemi, colormap, time_label, smoothing_steps, subjects_dir, views, clim, figure, initial_time, time_unit, background, time_viewer, colorbar, transparent, brain_alpha, overlay_alpha, vector_alpha, cortex, foreground, size, scale_factor, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs)
   2107 del kwargs
   2109 if time_viewer:
-> 2110     brain.setup_time_viewer(time_viewer=time_viewer,
   2111                             show_traces=show_traces)
   2112 else:
   2113     brain.show()

File D:\Anaconda\envs\fnirs\lib\site-packages\mne\viz\_brain\_brain.py:523, in Brain.setup_time_viewer(***failed resolving arguments***)
    521 self._configure_menu()
    522 self._configure_status_bar()
--> 523 self._configure_playback()
    524 self._configure_help()
    525 # show everything at the end

File D:\Anaconda\envs\fnirs\lib\site-packages\mne\viz\_brain\_brain.py:1004, in Brain._configure_playback(self)
   1003 def _configure_playback(self):
-> 1004     self._renderer._playback_initialize(
   1005         func=self._play,
   1006         timeout=self.refresh_rate_ms,
   1007         value=self._data['time_idx'],
   1008         rng=[0, len(self._data['time']) - 1],
   1009         time_widget=self.widgets["time"],
   1010         play_widget=self.widgets["play"],
   1011     )

File D:\Anaconda\envs\fnirs\lib\site-packages\mne\viz\backends\_notebook.py:1227, in _IpyPlayback._playback_initialize(self, func, timeout, value, rng, time_widget, play_widget)
   1225 play.max = rng[1]
   1226 play.value = value
-> 1227 slider = time_widget._widget
   1228 jsdlink((play, 'value'), (slider, 'value'))
   1229 jsdlink((slider, 'value'), (play, 'value'))

AttributeError: 'NoneType' object has no attribute '_widget

Hi, I wonder if you’ve found the solution to this issue? I’m having the same problem working on Mac Sonoma with MNE 1.5.1.

hi @Jiahui, I’ve edited your post to format the code and traceback as “preformatted text” so it’s easier to read.

If possible, can you (or @PuddleJumper2018) post a complete reproducible example (i.e., one that any user could copy-paste into a python terminal and generate the same error you’re seeing)? Ideally it would use one of our example datasets and include all necessary imports. Given the nature of @Jiahui’s example code above, I’m guessing the fnirs motor dataset would be the place to start.

Hi @drammock , I’ll do my best. I tried on tapping example from here.

My OS: Sonoma 14.1.1
MNE-NIRS version: 0.5.0
MNE version: 1.5.1
Python: 3.10.12
Should probably add I work in conda environment.
If there’s something I missed let me know.

Thank you!

import numpy as np
import pandas as pd

import mne
from mne.preprocessing.nirs import optical_density, beer_lambert_law

import statsmodels.formula.api as smf

from mne_bids import BIDSPath, read_raw_bids, get_entity_vals
import mne_nirs

from mne_nirs.experimental_design import make_first_level_design_matrix
from mne_nirs.statistics import run_glm, statsmodels_to_results
from mne_nirs.channels import get_long_channels, get_short_channels
from mne_nirs.io.fold import fold_landmark_specificity
from mne_nirs.visualisation import plot_nirs_source_detector, plot_glm_surface_projection
from mne_nirs.datasets import fnirs_motor_group

def individual_analysis(bids_path, ID):

    raw_intensity = read_raw_bids(bids_path=bids_path, verbose=False)
    raw_intensity.annotations.delete(raw_intensity.annotations.description == '15.0')
     # sanitize event names
    raw_intensity.annotations.description[:] = [
        d.replace('/', '_') for d in raw_intensity.annotations.description]

    # Convert signal to haemoglobin and resample
    raw_od = optical_density(raw_intensity)
    raw_haemo = beer_lambert_law(raw_od, ppf=0.1)
    raw_haemo.resample(0.3)

    # Cut out just the short channels for creating a GLM repressor
    sht_chans = get_short_channels(raw_haemo)
    raw_haemo = get_long_channels(raw_haemo)

    # Create a design matrix
    design_matrix = make_first_level_design_matrix(raw_haemo, stim_dur=5.0)

    # Append short channels mean to design matrix
    design_matrix["ShortHbO"] = np.mean(sht_chans.copy().pick(picks="hbo").get_data(), axis=0)
    design_matrix["ShortHbR"] = np.mean(sht_chans.copy().pick(picks="hbr").get_data(), axis=0)

    # Run GLM
    glm_est = run_glm(raw_haemo, design_matrix)

    # Extract channel metrics
    cha = glm_est.to_dataframe()

    # Add the participant ID to the dataframes
    cha["ID"] = ID

    # Convert to uM for nicer plotting below.
    cha["theta"] = [t * 1.e6 for t in cha["theta"]]

    return raw_haemo, cha


# Get dataset details
root = fnirs_motor_group.data_path()
dataset = BIDSPath(root=root, task="tapping",
                   datatype="nirs", suffix="nirs", extension=".snirf")
subjects = get_entity_vals(root, 'subject')

df_cha = pd.DataFrame()  # To store channel level results
for sub in subjects:  # Loop from first to fifth subject

    # Create path to file based on experiment info
    bids_path = dataset.update(subject=sub)

    # Analyse data and return both ROI and channel results
    raw_haemo, channel = individual_analysis(bids_path, sub)

    # Append individual results to all participants
    df_cha = pd.concat([df_cha, channel], ignore_index=True)

ch_summary = df_cha.query("Condition in ['Tapping_Right']")
assert len(ch_summary)
ch_summary = ch_summary.query("Chroma in ['hbo']")
ch_model = smf.mixedlm("theta ~ -1 + ch_name", ch_summary,
                       groups=ch_summary["ID"]).fit(method='nm')
model_df = statsmodels_to_results(ch_model, order=raw_haemo.copy().pick("hbo").ch_names)

# Plot the projection and sensor locations
brain = plot_glm_surface_projection(raw_haemo.copy().pick("hbo"), model_df, colorbar=True)
brain.add_sensors(raw_haemo.info, trans='fsaverage', fnirs=['channels', 'pairs', 'sources', 'detectors'])

# mark the premotor cortex in green
aud_label = [label for label in labels_combined if label.name == 'Premotor Cortex-lh'][0]
brain.add_label(aud_label, borders=True, color='green')

# mark the auditory association cortex in blue
aud_label = [label for label in labels_combined if label.name == 'Auditory Association Cortex-lh'][0]
brain.add_label(aud_label, borders=True, color='blue')

brain.show_view(azimuth=160, elevation=60, distance=400)

Which seems to work:

Using default location ~/mne_data for fnirs_motor_group...
Downloading file 'BIDS-NIRS-Tapping-master.zip' from 'https://github.com/rob-luke/BIDS-NIRS-Tapping/archive/v0.1.0.zip' to '/Users/xxxx/mne_data'.
0.00B [00:00, ?B/s]     
Unzipping contents of '/Users/xxxxx/mne_data/BIDS-NIRS-Tapping-master.zip' to '/Users/xxxxx/mne_data/./fNIRS-motor-group'
Download complete in 06s (41.7 MB)
Reading 0 ... 23238  =      0.000 ...  2974.464 secs...
Reading 0 ... 18877  =      0.000 ...  2416.256 secs...
Reading 0 ... 18874  =      0.000 ...  2415.872 secs...
Reading 0 ... 23120  =      0.000 ...  2959.360 secs...
Reading 0 ... 23006  =      0.000 ...  2944.768 secs...
/Users/xxxxx/anaconda3/envs/svwm/lib/python3.10/site-packages/mne_nirs/statistics/_statsmodels.py:114: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  sdf[jj, 1] = np.sqrt(model.scale) * model.bse[model.k_fe + jj]

Until I get error on plot_glm_surface_projection here’s the error I get

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Untitled-1.ipynb Cell 5 line 2
      1 # Plot the projection and sensor locations
----> 2 brain = plot_glm_surface_projection(raw_haemo.copy().pick("hbo"), model_df, colorbar=True)
      3 brain.add_sensors(raw_haemo.info, trans='fsaverage', fnirs=['channels', 'pairs', 'sources', 'detectors'])
      5 # mark the premotor cortex in green

File <decorator-gen-651>:10, in plot_glm_surface_projection(inst, statsmodel_df, picks, value, background, figure, clim, mode, colormap, surface, hemi, size, view, colorbar, distance, subjects_dir, src, verbose)

File ~/anaconda3/envs/svwm/lib/python3.10/site-packages/mne_nirs/visualisation/_plot_GLM_surface_projection.py:97, in plot_glm_surface_projection(inst, statsmodel_df, picks, value, background, figure, clim, mode, colormap, surface, hemi, size, view, colorbar, distance, subjects_dir, src, verbose)
     90     raise RuntimeError('MNE data structure does not match dataframe '
     91                        f'results.\nMNE = {info.ch_names}.\n'
     92                        f'GLM = {list(statsmodel_df["ch_name"].values)}')
     94 ea = EvokedArray(np.tile(statsmodel_df[value].values.T, (1, 1)).T,
     95                  info.copy())
---> 97 return _plot_3d_evoked_array(inst, ea, picks=picks,
     98                              value=value,
     99                              background=background, figure=figure,
    100                              clim=clim,
    101                              mode=mode, colormap=colormap,
    102                              surface=surface, hemi=hemi, size=size,
    103                              view=view, colorbar=colorbar,
    104                              distance=distance,
    105                              subjects_dir=subjects_dir, src=src,
    106                              verbose=verbose)

File ~/anaconda3/envs/svwm/lib/python3.10/site-packages/mne_nirs/visualisation/_plot_GLM_surface_projection.py:142, in _plot_3d_evoked_array(inst, ea, picks, value, background, figure, clim, mode, colormap, surface, hemi, size, view, colorbar, distance, subjects_dir, src, verbose)
    139 stc = stc_near_sensors(picks=picks, **kwargs, verbose=verbose)
    141 # Produce brain plot
--> 142 brain = stc.plot(src=src, subjects_dir=subjects_dir, hemi=hemi,
    143                  surface=surface, initial_time=0, clim=clim, size=size,
    144                  colormap=colormap, figure=figure, background=background,
    145                  colorbar=colorbar, verbose=verbose)
    146 if view is not None:
    147     brain.show_view(view)

File ~/anaconda3/envs/svwm/lib/python3.10/site-packages/mne/source_estimate.py:740, in _BaseSourceEstimate.plot(self, subject, surface, hemi, colormap, time_label, smoothing_steps, transparent, alpha, time_viewer, subjects_dir, figure, views, colorbar, clim, cortex, size, background, foreground, initial_time, time_unit, backend, spacing, title, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs, verbose)
    706 @copy_function_doc_to_method_doc(plot_source_estimates)
    707 def plot(
    708     self,
   (...)
    738     verbose=None,
    739 ):
--> 740     brain = plot_source_estimates(
    741         self,
    742         subject,
    743         surface=surface,
    744         hemi=hemi,
    745         colormap=colormap,
    746         time_label=time_label,
    747         smoothing_steps=smoothing_steps,
    748         transparent=transparent,
    749         alpha=alpha,
    750         time_viewer=time_viewer,
    751         subjects_dir=subjects_dir,
    752         figure=figure,
    753         views=views,
    754         colorbar=colorbar,
    755         clim=clim,
    756         cortex=cortex,
    757         size=size,
    758         background=background,
    759         foreground=foreground,
    760         initial_time=initial_time,
    761         time_unit=time_unit,
    762         backend=backend,
    763         spacing=spacing,
    764         title=title,
    765         show_traces=show_traces,
    766         src=src,
    767         volume_options=volume_options,
    768         view_layout=view_layout,
    769         add_data_kwargs=add_data_kwargs,
    770         brain_kwargs=brain_kwargs,
    771         verbose=verbose,
    772     )
    773     return brain

File <decorator-gen-130>:10, in plot_source_estimates(stc, subject, surface, hemi, colormap, time_label, smoothing_steps, transparent, alpha, time_viewer, subjects_dir, figure, views, colorbar, clim, cortex, size, background, foreground, initial_time, time_unit, backend, spacing, title, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs, verbose)

File ~/anaconda3/envs/svwm/lib/python3.10/site-packages/mne/viz/_3d.py:2467, in plot_source_estimates(stc, subject, surface, hemi, colormap, time_label, smoothing_steps, transparent, alpha, time_viewer, subjects_dir, figure, views, colorbar, clim, cortex, size, background, foreground, initial_time, time_unit, backend, spacing, title, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs, verbose)
   2465 else:
   2466     with use_3d_backend(backend):
-> 2467         return _plot_stc(
   2468             stc,
   2469             overlay_alpha=alpha,
   2470             brain_alpha=alpha,
   2471             vector_alpha=alpha,
   2472             cortex=cortex,
   2473             foreground=foreground,
   2474             size=size,
   2475             scale_factor=None,
   2476             show_traces=show_traces,
   2477             src=src,
   2478             volume_options=volume_options,
   2479             view_layout=view_layout,
   2480             add_data_kwargs=add_data_kwargs,
   2481             brain_kwargs=brain_kwargs,
   2482             **kwargs,
   2483         )

File ~/anaconda3/envs/svwm/lib/python3.10/site-packages/mne/viz/_3d.py:2637, in _plot_stc(stc, subject, surface, hemi, colormap, time_label, smoothing_steps, subjects_dir, views, clim, figure, initial_time, time_unit, background, time_viewer, colorbar, transparent, brain_alpha, overlay_alpha, vector_alpha, cortex, foreground, size, scale_factor, show_traces, src, volume_options, view_layout, add_data_kwargs, brain_kwargs)
   2634 del kwargs
   2636 if time_viewer:
-> 2637     brain.setup_time_viewer(time_viewer=time_viewer, show_traces=show_traces)
   2638 else:
   2639     brain.show()

File ~/anaconda3/envs/svwm/lib/python3.10/site-packages/mne/viz/_brain/_brain.py:600, in Brain.setup_time_viewer(***failed resolving arguments***)
    598 self._configure_menu()
    599 self._configure_status_bar()
--> 600 self._configure_playback()
    601 self._configure_help()
    602 # show everything at the end

File ~/anaconda3/envs/svwm/lib/python3.10/site-packages/mne/viz/_brain/_brain.py:1101, in Brain._configure_playback(self)
   1100 def _configure_playback(self):
-> 1101     self._renderer._playback_initialize(
   1102         func=self._play,
   1103         timeout=self.refresh_rate_ms,
   1104         value=self._data["time_idx"],
   1105         rng=[0, len(self._data["time"]) - 1],
   1106         time_widget=self.widgets["time"],
   1107         play_widget=self.widgets["play"],
   1108     )

File ~/anaconda3/envs/svwm/lib/python3.10/site-packages/mne/viz/backends/_notebook.py:1342, in _IpyPlayback._playback_initialize(self, func, timeout, value, rng, time_widget, play_widget)
   1340 play.max = rng[1]
   1341 play.value = value
-> 1342 slider = time_widget._widget
   1343 jsdlink((play, "value"), (slider, "value"))
   1344 jsdlink((slider, "value"), (play, "value"))

AttributeError: 'NoneType' object has no attribute '_widget'

Hi!
I tried to reproduce the error but I got another error related to freesurfer BEM dataset. The solution was to get this dataset. Can you try to add this line

mne.datasets.fetch_fsaverage(subjects_dir=None,verbose=None)

below # Get dataset details in your example?
Tell me what you get

I also tried to reproduce (with current dev versions of MNE and MNE-NIRS) but I get a different error (about color limits not being monotonically increasing). But if I run this line instead:

brain = plot_glm_surface_projection(
    raw_haemo.copy().pick("hbo"),
    model_df,
    colorbar=True,
    clim=dict(kind="percent", pos_lims=(90, 95, 99)),  # <--- new line
)

then I get a plot:

so… maybe the bug you’re seeing is already fixed in MNE-NIRS 0.6, or in MNE-Python > 1.5.1?