Inconsistent subthalamic local field potential beta activity amid in- and antiphasic neuronal bursts.
The 3 matches
- [1] § Methods › Beta peak detection ↔ feat_ex/beta/core.py, lines 1–51 · score 0.83 · 15–36 Hz, 10–36, 5–45, 6–14, 1–6, bin
- [2] § Results › Bilateral prevalence of STN-LFP beta power is 47.25% per patient ↔ eval/beta_prev_stats.py, lines 798–824 · score 0.74 · Unilateral prevalence, hemisphere prevalence, Bilateral prevalence, Beta peaks, LFP beta, artifact
- [3] § Methods › Anatomical reconstruction of microelectrode positions ↔ feat_ex/spatial/volumetric_screen.py, lines 229–246 · score 0.60 · MNI space, DBS lead, microelectrode, shift, trajectories, position
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 1,058 lines · 52 KB · no license · 1 match
- '''
- Created on Oct 28, 2024
- @author: voodoocode
- '''
- import os
- import finnpy.file_io.data_manager as dm
- import numpy as np
- import matplotlib
- matplotlib.use("Qtagg")
- import matplotlib.pyplot as plt
- import scipy.signal
- import functools
- import PyQt6.QtWidgets
- import multiprocessing
- import pyqtgraph
- pyqtgraph.setConfigOptions(antialias=True)
- import pandas
- PLOT_COLORS = ["lightblue", "green", "red", "orange", "purple"]
- PLOT_PATTERNS = ["solid", "dotted", "dashed"]
- TIMER_DELAY_MS = 1500
- PATH = "/mnt/data/Professional/LMU/data/Beta-prevalence/"
- MAX_PEAKS = 3
- SCALES = [[1, 6], [6, 14], [5, 45], [10, 36], [15, 36]]
- REFRESH_TIMER_DELAY_MS = 2000
- MRK_CNT_START = 3
- LEFT_HEMISPHERE = 0
- RIGHT_HEMISPHERE = 1
- ALPHA_COLUMN = 1
- BETA1_COLUMN = 3
- BETA2_COLUMN = 4
- PLOT_IDX = 0
- CANVAS_IDX = 1
- INSIGHT_GAIN = {"Strong" : 3, "Medium" : 2, "Low" : 1, "None" : 0}
- FREQ_BAND_CNT = 2
- MAX_FILT_BIN = 12
- def clicked_color_bttn(bttn, config_idx, hem_idx):
- global valid_chs;
- curr_color = bttn.styleSheet().split(": ")[1][:-1]
- curr_color_idx = PLOT_COLORS.index(curr_color)
- while(True):
- curr_color_idx += 1
- if (curr_color_idx == len(PLOT_COLORS)):
- curr_color_idx = 0
- if (curr_color_idx == len(valid_chs[hem_idx])):
- curr_color_idx = 0
- if (valid_chs[hem_idx][curr_color_idx]):
- break
- bttn.setStyleSheet("background-color: " + PLOT_COLORS[curr_color_idx] + ";")
- global box_color
- box_color[config_idx][0] = PLOT_COLORS[curr_color_idx]
- def get_line_edit(pos):
- global mrk_cnt
- txt = PyQt6.QtWidgets.QLineEdit()
- txt.setAlignment(PyQt6.QtCore.Qt.AlignmentFlag.AlignCenter)
- txt.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- if (pos == "la"):
- txt.setText(str(mrk_cnt[0][0]))
- if (pos == "ra"):
- txt.setText(str(mrk_cnt[1][0]))
- if (pos == "lb"):
- txt.setText(str(mrk_cnt[0][1]))
- if (pos == "rb"):
- txt.setText(str(mrk_cnt[1][1]))
- txt.setEnabled(False)
- return txt
- def clckd_box_peak(config_idx, mrk_idx, box):
- global box_peak
- if (box.isChecked()):
- box_peak[config_idx][mrk_idx] = True
- else:
- box_peak[config_idx][mrk_idx] = False
- def clckd_box_noise(config_idx, mrk_idx, box):
- global box_noise
- if (box.isChecked()):
- box_noise[config_idx][mrk_idx] = True
- else:
- box_noise[config_idx][mrk_idx] = False
- def clckd_box_depth(config_idx, mrk_idx, box):
- global box_depth
- if (box.isChecked()):
- box_depth[config_idx][mrk_idx] = True
- else:
- box_depth[config_idx][mrk_idx] = False
- def clckd_box_lim(config_idx, mrk_idx, box):
- global box_lim
- if (box.isChecked()):
- box_lim[config_idx][mrk_idx] = True
- else:
- box_lim[config_idx][mrk_idx] = False
- def clckd_box_depvar(config_idx, mrk_idx, box):
- global box_depvar
- if (box.isChecked()):
- box_depvar[config_idx][mrk_idx] = True
- else:
- box_depvar[config_idx][mrk_idx] = False
- def clckd_box_specstat(config_idx, mrk_idx, box):
- global box_specstat
- if (box.isChecked()):
- box_specstat[config_idx][mrk_idx] = True
- else:
- box_specstat[config_idx][mrk_idx] = False
- def clckd_box_no_harm(config_idx, mrk_idx, box):
- global box_no_harm
- if (box.isChecked()):
- box_no_harm[config_idx][mrk_idx] = True
- else:
- box_no_harm[config_idx][mrk_idx] = False
- def clckd_box_plausible(config_idx, mrk_idx, box):
- global box_plausible
- if (box.isChecked()):
- box_plausible[config_idx][mrk_idx] = True
- else:
- box_plausible[config_idx][mrk_idx] = False
- def clckd_box_unimod(config_idx, mrk_idx, box):
- global box_unimod
- if (box.isChecked()):
- box_unimod[config_idx][mrk_idx] = True
- else:
- box_unimod[config_idx][mrk_idx] = False
- def clckd_box_unique(config_idx, box):
- global box_unique
- if (box.isChecked()):
- box_unique[config_idx][0] = True
- else:
- box_unique[config_idx][0] = False
- def get_strong_mrk_frame(pos, mrk_idx, layout, show_text, db_name):
- if (show_text == True):
- box_2_6 = PyQt6.QtWidgets.QCheckBox(" Spatially unimodal"); layout.addWidget(box_2_6, 2, mrk_idx)
- box_2_4 = PyQt6.QtWidgets.QCheckBox(" Unique suggestion"); layout.addWidget(box_2_4, 1, mrk_idx)
- else:
- box_2_6 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_2_6, 2, mrk_idx)
- box_2_4 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_2_4, 1, mrk_idx)
- box_2_4.setVisible(False)
- if (db_name == "db1" or db_name == "db2"):
- box_2_6.setVisible(False)
- if (pos == "la"):
- config_idx = 0
- elif (pos == "ra"):
- config_idx = 1
- elif (pos == "lb"):
- config_idx = 2
- elif (pos == "rb"):
- config_idx = 3
- global box_unimod, box_unique
- box_unimod[config_idx][mrk_idx] = False
- box_unique[config_idx][0] = False
- box_2_6.stateChanged.connect(functools.partial(clckd_box_unimod, config_idx, mrk_idx, box_2_6))
- box_2_4.stateChanged.connect(functools.partial(clckd_box_unique, config_idx, box_2_4))
- def get_artifact_mrk_frame(pos, mrk_idx, layout, show_text, db_name):
- if (show_text == True):
- box_2_2 = PyQt6.QtWidgets.QCheckBox(" Visible in >1 depth"); layout.addWidget(box_2_2,10, mrk_idx)
- box_2_6 = PyQt6.QtWidgets.QCheckBox(" Spatially limited"); layout.addWidget(box_2_6, 9, mrk_idx)
- box_2_5 = PyQt6.QtWidgets.QCheckBox(" Depth variable amp."); layout.addWidget(box_2_5, 8, mrk_idx)
- box_2_3 = PyQt6.QtWidgets.QCheckBox(" Spectrally static"); layout.addWidget(box_2_3, 7, mrk_idx)
- #box_2_4 = PyQt6.QtWidgets.QCheckBox(" Spectrally wide"); layout.addWidget(box_2_4, 6, mrk_idx)
- box_2_1 = PyQt6.QtWidgets.QCheckBox(" Not a LF harmonic"); layout.addWidget(box_2_1, 5, mrk_idx)
- box_2_0 = PyQt6.QtWidgets.QCheckBox(" Inside the STN"); layout.addWidget(box_2_0, 4, mrk_idx)
- else:
- box_2_2 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_2_2,10, mrk_idx)
- box_2_6 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_2_6, 9, mrk_idx)
- box_2_5 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_2_5, 8, mrk_idx)
- box_2_3 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_2_3, 7, mrk_idx)
- #box_2_4 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_2_4, 6, mrk_idx)
- box_2_1 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_2_1, 5, mrk_idx)
- box_2_0 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_2_0, 4, mrk_idx)
- if (db_name == "db1" or db_name == "db2"):
- # box_2_5.setVisible(False)
- box_2_6.setVisible(False)
- box_2_2.setVisible(False)
- if (db_name != "db4" and db_name != "db6"):
- box_2_0.setVisible(False)
- #box_2_0.setVisible(False)
- if (pos == "la"):
- config_idx = 0
- elif (pos == "ra"):
- config_idx = 1
- elif (pos == "lb"):
- config_idx = 2
- elif (pos == "rb"):
- config_idx = 3
- global box_depth, box_lim, box_depvar, box_specstat, box_no_harm, box_plausible
- box_depth[config_idx][mrk_idx] = False
- box_lim[config_idx][mrk_idx] = False
- box_depvar[config_idx][mrk_idx] = False
- box_specstat[config_idx][mrk_idx] = False
- box_no_harm[config_idx][mrk_idx] = False
- box_plausible[config_idx][mrk_idx] = False
- box_2_2.stateChanged.connect(functools.partial(clckd_box_depth, config_idx, mrk_idx, box_2_2))
- box_2_6.stateChanged.connect(functools.partial(clckd_box_lim, config_idx, mrk_idx, box_2_6))
- box_2_5.stateChanged.connect(functools.partial(clckd_box_depvar, config_idx, mrk_idx, box_2_5))
- box_2_3.stateChanged.connect(functools.partial(clckd_box_specstat, config_idx, mrk_idx, box_2_3))
- box_2_1.stateChanged.connect(functools.partial(clckd_box_no_harm, config_idx, mrk_idx, box_2_1))
- box_2_0.stateChanged.connect(functools.partial(clckd_box_plausible, config_idx, mrk_idx, box_2_0))
- def get_anything_mrk_frame(pos, mrk_idx, layout, show_text):
- if (show_text == True):
- if (pos[1] == "a"):
- box_1_1 = PyQt6.QtWidgets.QCheckBox(" Alpha 8-12Hz"); layout.addWidget(box_1_1, 13, mrk_idx)
- else:
- box_1_1 = PyQt6.QtWidgets.QCheckBox(" Beta 12-32Hz"); layout.addWidget(box_1_1, 13, mrk_idx)
- box_1_2 = PyQt6.QtWidgets.QCheckBox(" Above noise level"); layout.addWidget(box_1_2, 12, mrk_idx)
- else:
- if (pos[1] == "a"):
- box_1_1 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_1_1, 13, mrk_idx)
- else:
- box_1_1 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_1_1, 13, mrk_idx)
- box_1_2 = PyQt6.QtWidgets.QCheckBox(); layout.addWidget(box_1_2, 12, mrk_idx)
- if (pos == "la"):
- config_idx = 0
- elif (pos == "ra"):
- config_idx = 1
- elif (pos == "lb"):
- config_idx = 2
- elif (pos == "rb"):
- config_idx = 3
- global box_peak, box_noise
- box_peak[config_idx][mrk_idx] = False
- box_noise[config_idx][mrk_idx] = False
- box_1_1.stateChanged.connect(functools.partial(clckd_box_peak, config_idx, mrk_idx, box_1_1))
- box_1_2.stateChanged.connect(functools.partial(clckd_box_noise, config_idx, mrk_idx, box_1_2))
- def get_config_tabs(pos, parent_layout, db_name):
- global mrk_cnt
- if (pos == "la"):
- loc_mrk_cnt = mrk_cnt[0][0]
- if (pos == "ra"):
- loc_mrk_cnt = mrk_cnt[1][0]
- if (pos == "lb"):
- loc_mrk_cnt = mrk_cnt[0][1]
- if (pos == "rb"):
- loc_mrk_cnt = mrk_cnt[1][1]
- main_wid = PyQt6.QtWidgets.QWidget(objectName = "config chkbxs")
- main_wid.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- main_layout = PyQt6.QtWidgets.QGridLayout(); main_wid.setLayout(main_layout)
- main_layout.setContentsMargins(0, 0, 0, 0); main_layout.setSpacing(5)
- for mrk_idx in range(loc_mrk_cnt):
- get_anything_mrk_frame(pos, mrk_idx, main_layout, True if (mrk_idx == (len(range(loc_mrk_cnt)) - 1)) else False)
- get_artifact_mrk_frame(pos, mrk_idx, main_layout, True if (mrk_idx == (len(range(loc_mrk_cnt)) - 1)) else False, db_name)
- get_strong_mrk_frame(pos, mrk_idx, main_layout, True if (mrk_idx == (len(range(loc_mrk_cnt)) - 1)) else False, db_name)
- for mrk_idx in range(loc_mrk_cnt):
- main_layout.addWidget(PyQt6.QtWidgets.QLabel(str(mrk_idx + 1)), 14, mrk_idx)
- border_wid0 = PyQt6.QtWidgets.QLabel("- Target identification -"); border_wid0.setEnabled(False); main_layout.addWidget(border_wid0, 0, 0, 1, 4)
- border_wid1 = PyQt6.QtWidgets.QLabel("- Artifact rejection -"); border_wid1.setEnabled(False); main_layout.addWidget(border_wid1, 3, 0, 1, 4)
- border_wid2 = PyQt6.QtWidgets.QLabel("- Peak detection -"); border_wid2.setEnabled(False); main_layout.addWidget(border_wid2, 11, 0, 1, 4)
- parent_layout.addWidget(main_wid)
- def info_bttn_clicked(bttn, config_idx):
- global box_insight
- if (bttn.text() == "Insight gain: None"):
- bttn.setText("Insight gain: Strong")
- box_insight[config_idx][0] = "Strong"
- elif (bttn.text() == "Insight gain: Strong"):
- bttn.setText("Insight gain: Medium")
- box_insight[config_idx][0] = "Medium"
- elif (bttn.text() == "Insight gain: Medium"):
- bttn.setText("Insight gain: Low")
- box_insight[config_idx][0] = "Low"
- elif (bttn.text() == "Insight gain: Low"):
- bttn.setText("Insight gain: None")
- box_insight[config_idx][0] = "None"
- def get_mrk_result(pos,
- parent_layout):
- global box_insight
- main_wid = PyQt6.QtWidgets.QWidget(objectName = "Insights")
- layout = PyQt6.QtWidgets.QVBoxLayout(); main_wid.setLayout(layout)
- if (pos == "la"):
- config_idx = 0
- elif (pos == "ra"):
- config_idx = 1
- elif (pos == "lb"):
- config_idx = 2
- elif (pos == "rb"):
- config_idx = 3
- layout.addWidget(get_line_edit(pos))
- bttn = PyQt6.QtWidgets.QPushButton("Insight gain: None");
- bttn.clicked.connect(functools.partial(info_bttn_clicked, bttn, config_idx))
- box_insight[config_idx][0] = "None"
- layout.addWidget(bttn)
- layout.setContentsMargins(0, 0, 0, 0); layout.setSpacing(5)
- parent_layout.addWidget(main_wid)
- def get_bttns(pos,
- parent_layout):
- bttn_wid = PyQt6.QtWidgets.QWidget(objectName = "config bttns")
- bttn_layout = PyQt6.QtWidgets.QHBoxLayout(); bttn_wid.setLayout(bttn_layout)
- bttn_layout.setContentsMargins(0, 0, 0, 0); bttn_layout.setSpacing(5)
- global mrk_cnt, box_color
- if (pos == "la"):
- for mrk_idx in range(mrk_cnt[0][0]):
- bttn = PyQt6.QtWidgets.QToolButton()
- bttn.setText(str(mrk_idx + 1))
- bttn.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- bttn.setStyleSheet("background-color: " + PLOT_COLORS[valid_chs[0].index(True)] + ";")
- bttn.clicked.connect(functools.partial(clicked_color_bttn, bttn, 0, 0))
- box_color[0][mrk_idx] = PLOT_COLORS[valid_chs[0].index(True)]
- bttn_layout.addWidget(bttn)
- if (pos == "ra"):
- for mrk_idx in range(mrk_cnt[1][0]):
- bttn = PyQt6.QtWidgets.QToolButton()
- bttn.setText(str(mrk_idx + 1))
- bttn.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- bttn.setStyleSheet("background-color: " + PLOT_COLORS[valid_chs[1].index(True)] + ";")
- bttn.clicked.connect(functools.partial(clicked_color_bttn, bttn, 1, 1))
- box_color[1][mrk_idx] = PLOT_COLORS[valid_chs[1].index(True)]
- bttn_layout.addWidget(bttn)
- if (pos == "lb"):
- for mrk_idx in range(mrk_cnt[0][1]):
- bttn = PyQt6.QtWidgets.QToolButton()
- bttn.setText(str(mrk_idx + 1))
- bttn.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- bttn.setStyleSheet("background-color: " + PLOT_COLORS[valid_chs[0].index(True)] + ";")
- bttn.clicked.connect(functools.partial(clicked_color_bttn, bttn, 2, 0))
- box_color[2][mrk_idx] = PLOT_COLORS[valid_chs[0].index(True)]
- bttn_layout.addWidget(bttn)
- if (pos == "rb"):
- for mrk_idx in range(mrk_cnt[1][1]):
- bttn = PyQt6.QtWidgets.QToolButton()
- bttn.setText(str(mrk_idx + 1))
- bttn.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- bttn.setStyleSheet("background-color: " + PLOT_COLORS[valid_chs[1].index(True)] + ";")
- bttn.clicked.connect(functools.partial(clicked_color_bttn, bttn, 3, 1))
- box_color[3][mrk_idx] = PLOT_COLORS[valid_chs[1].index(True)]
- bttn_layout.addWidget(bttn)
- parent_layout.addWidget(bttn_wid)
- def get_config_block(pos,
- parent_layout = None,
- config_wid = None,
- db_name = ""):
- if (config_wid is None):
- config_wid = PyQt6.QtWidgets.QWidget(objectName = "config panel")
- parent_layout.addWidget(config_wid)
- config_wid.setMinimumWidth(196)
- layout = PyQt6.QtWidgets.QVBoxLayout()
- config_wid.setLayout(layout)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(5)
- freq_label = PyQt6.QtWidgets.QLabel("Alpha" if (pos[1] == "a") else "Beta")
- freq_label.setAlignment(PyQt6.QtCore.Qt.AlignmentFlag.AlignCenter)
- layout.addWidget(freq_label)
- get_mrk_result(pos, layout)
- get_bttns(pos, layout)
- get_config_tabs(pos, layout, db_name)
- global config_wids
- if (pos == "la"):
- config_wids[0][0] = config_wid
- if (pos == "ra"):
- config_wids[1][0] = config_wid
- if (pos == "lb"):
- config_wids[0][1] = config_wid
- if (pos == "rb"):
- config_wids[1][1] = config_wid
- def get_config_panel(hem_idx,
- parent_layout):
- main_wid = PyQt6.QtWidgets.QWidget(objectName = "config panels")
- layout = PyQt6.QtWidgets.QVBoxLayout()
- main_wid.setLayout(layout)
- get_config_block("la" if (hem_idx == 0) else "ra", layout)
- a_space = PyQt6.QtWidgets.QWidget(objectName = "config panel separator")
- a_space.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Expanding)
- layout.addWidget(a_space)
- get_config_block("lb" if (hem_idx == 0) else "rb", layout)
- parent_layout.addWidget(main_wid)
- def get_psds(raw_data, fs, win_szs, depth_cnt, ch_cnt, db_name, scale_db):
- hem_cnt = len(raw_data)
- bins = [[[[np.ones((int(win_sz * fs / 2 + 1))) * np.nan for _ in range(depth_cnt[hem_idx])] for _ in range(ch_cnt[hem_idx])] for hem_idx in range(hem_cnt)] for win_sz in win_szs]
- pwrs = [[[[np.ones((int(win_sz * fs / 2 + 1))) * np.nan for _ in range(depth_cnt[hem_idx])] for _ in range(ch_cnt[hem_idx])] for hem_idx in range(hem_cnt)] for win_sz in win_szs]
- ref_bins = [None for _ in range(len(win_szs))]
- for hem_idx in range(hem_cnt):
- for ch_idx in range(ch_cnt[hem_idx]):
- for depth_idx in range(depth_cnt[hem_idx]):
- for (win_sz_idx, win_sz) in enumerate(win_szs):
- if (raw_data[hem_idx][ch_idx][depth_idx] is None):
- continue
- (bins[win_sz_idx][hem_idx][ch_idx][depth_idx], pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx]) = scipy.signal.welch(raw_data[hem_idx][ch_idx][depth_idx], fs, "hann", nperseg = int(fs * win_sz), noverlap = int(fs//2 * win_sz), nfft = int(fs * win_sz), detrend = "linear", return_onesided = True)
- #===========================================================
- # if (db_name == "db4"):#Remove a filter starting at 10 Hz
- # loc_bins = bins[win_sz_idx][hem_idx][ch_idx][depth_idx]
- # loc_pwrs = pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx]
- #
- # def _db4_filter_func(x):
- # r = 5.6*1e3; c = 1*1e-6
- # f_cutoff = 1/(2 * np.pi * r * c)
- # order = 1
- #
- # return 1/(1 + np.power(f_cutoff/x, 2*order))
- # corr_fctr = 1/_db4_filter_func(loc_bins[1:])
- #
- # loc_pwrs[1:] *= corr_fctr
- #
- # bins[win_sz_idx][hem_idx][ch_idx][depth_idx] = loc_bins
- # pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx] = loc_pwrs
- #
- # if (db_name == "db6"):#Remove a filter starting at 200 Hz
- # loc_bins = bins[win_sz_idx][hem_idx][ch_idx][depth_idx]
- # loc_pwrs = pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx]
- #
- # def _db6_filter_func(x, f_cutoff = 200, order = 1):
- # return 1/(1 + np.power(f_cutoff/x, 2*order))
- # corr_fctr = 1/_db6_filter_func(loc_bins[1:])
- #
- # #=======================================================
- # # plt.plot(_db6_filter_func(loc_bin[1:(max_filt_bin_idx + 1)]))
- # # plt.show(block = True)
- # #=======================================================
- #
- # loc_pwrs[1:] *= corr_fctr
- #
- # bins[win_sz_idx][hem_idx][ch_idx][depth_idx] = loc_bins
- # pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx] = loc_pwrs
- #===========================================================
- if (ref_bins[win_sz_idx] is None and bins[win_sz_idx][hem_idx][ch_idx][depth_idx] is not None):
- ref_bins[win_sz_idx] = bins[win_sz_idx][hem_idx][ch_idx][depth_idx]
- if (scale_db):
- for hem_idx in range(hem_cnt):
- for ch_idx in range(ch_cnt[hem_idx]):
- for depth_idx in range(depth_cnt[hem_idx]):
- for (win_sz_idx, win_sz) in enumerate(win_szs):
- pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx] = 20 * np.log10(pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx])
- #===========================================================================
- # #Normalization is here
- # for (win_sz_idx, win_sz) in enumerate(win_szs):
- # for hem_idx in range(hem_cnt):
- # for ch_idx in range(ch_cnt[hem_idx]):
- # loc_pwr = pwrs[win_sz_idx][hem_idx][ch_idx]
- # loc_pwr = np.asarray(loc_pwr)
- #
- # ref_data = list()
- # for depth_idx in range(depth_cnt[hem_idx]):
- # ref_data.append(pandas.Series(loc_pwr[depth_idx]).rolling(window = 5, center = True).mean())
- # ref_data = np.asarray(ref_data)
- # loc_pwr /= np.nanmedian(ref_data, axis = 0)
- # loc_pwr = np.nan_to_num(loc_pwr)
- #
- # #loc_pwr /= np.nanmedian(loc_pwr, axis = 0)
- #
- # loc_pwr = loc_pwr.tolist()
- # pwrs[win_sz_idx][hem_idx][ch_idx] = loc_pwr
- #===========================================================================
- for (win_sz_idx, win_sz) in enumerate(win_szs):
- for hem_idx in range(hem_cnt):
- for ch_idx in range(ch_cnt[hem_idx]):
- for depth_idx in range(depth_cnt[hem_idx]):
- if (np.isnan(pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx][0])):
- bins[win_sz_idx][hem_idx][ch_idx][depth_idx] = None
- pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx] = None
- ref_indices = [[None for _ in range(len(win_szs))] for _ in range(len(SCALES))]
- for scale_idx in range(len(SCALES)):
- for win_sz_idx in range(len(win_szs)):
- start = np.argmin(np.abs(ref_bins[win_sz_idx] - SCALES[scale_idx][0]))
- end = np.argmin(np.abs(ref_bins[win_sz_idx] - SCALES[scale_idx][1]))
- ref_indices[scale_idx][win_sz_idx] = [start, end]
- return (bins, pwrs, ref_indices)
- class Custom_plot_widget(pyqtgraph.PlotWidget):
- def __init__(self, lab_wid, db_name, f_name, pat_name, scale_idx, depth_idx, hem_idx, hem_wid):
- super().__init__()
- self.lab_wid = lab_wid
- self.db_name = db_name
- self.f_name = f_name
- self.pat_name = pat_name
- self.scale_idx = scale_idx
- self.depth_idx = depth_idx
- self.hem_idx = hem_idx
- self.hem_wid = hem_wid
- def mouseMoveEvent(self, ev):
- pos = self.plotItem.vb.mapSceneToView(PyQt6.QtCore.QPointF(ev.pos().x(), ev.pos().y()))
- x_pos = pos.x()
- y_pos = pos.y()
- self.lab_wid.setText("Database: %s File: %s Patient: %s X-Pos: %2.2f Y-Pos: %f" % (self.db_name, self.f_name, self.pat_name, x_pos, y_pos))
- #return pyqtgraph.PlotWidget.mouseMoveEvent(self, ev)
- def update_mrk(self, x_pos):
- freq_idx = 0 if (self.scale_idx == 1) else 1
- global mrk_cnt; global mrk_pos; global mrk_depth; global scatters; global plotters
- mrk_cnt[self.hem_idx][freq_idx] += 1
- if (mrk_cnt[self.hem_idx][freq_idx] > MAX_PEAKS):
- mrk_cnt[self.hem_idx][freq_idx] = 0
- for plot_idx in range(MAX_PEAKS)[::-1]:
- for sub_idx in range(len(scatters[self.hem_idx][freq_idx][plot_idx])):
- parent = scatters[self.hem_idx][freq_idx][plot_idx][sub_idx][0]
- scttr = scatters[self.hem_idx][freq_idx][plot_idx][sub_idx][1]
- annot = scatters[self.hem_idx][freq_idx][plot_idx][sub_idx][2]
- parent.removeItem(scttr); parent.removeItem(annot)
- return
- mrk_pos[self.hem_idx][freq_idx][mrk_cnt[self.hem_idx][freq_idx] - 1] = x_pos
- mrk_depth[self.hem_idx][freq_idx][mrk_cnt[self.hem_idx][freq_idx] - 1] = self.depth_idx
- scatters[self.hem_idx][freq_idx][mrk_cnt[self.hem_idx][freq_idx] - 1] = list()
- if (freq_idx == 0):
- y_pos = (plotters[self.hem_idx][self.depth_idx][1].plotItem.viewRange()[1][0] + plotters[self.hem_idx][self.depth_idx][1].plotItem.viewRange()[1][1])/2
- ax = plotters[self.hem_idx][self.depth_idx][1]
- scttr = ax.plot([x_pos, x_pos], [y_pos, y_pos], color = "red", symbol = "o", symbolPen = pyqtgraph.mkPen("red"), symbolBrush = pyqtgraph.mkBrush("red"))
- annot = pyqtgraph.TextItem(str(mrk_cnt[self.hem_idx][freq_idx])); ax.addItem(annot); annot.setPos(x_pos, y_pos)
- scatters[self.hem_idx][freq_idx][mrk_cnt[self.hem_idx][freq_idx] - 1].append((ax, scttr, annot))
- else:
- y_pos = (plotters[self.hem_idx][self.depth_idx][3].plotItem.viewRange()[1][0] + plotters[self.hem_idx][self.depth_idx][3].plotItem.viewRange()[1][1])/2
- ax = plotters[self.hem_idx][self.depth_idx][3]
- scttr = ax.plot([x_pos, x_pos], [y_pos, y_pos], color = "red", symbol = "o", symbolPen = pyqtgraph.mkPen("red"), symbolBrush = pyqtgraph.mkBrush("red"))
- annot = pyqtgraph.TextItem(str(mrk_cnt[self.hem_idx][freq_idx])); ax.addItem(annot); annot.setPos(x_pos, y_pos)
- scatters[self.hem_idx][freq_idx][mrk_cnt[self.hem_idx][freq_idx] - 1].append((ax, scttr, annot))
- y_pos = (plotters[self.hem_idx][self.depth_idx][4].plotItem.viewRange()[1][0] + plotters[self.hem_idx][self.depth_idx][4].plotItem.viewRange()[1][1])/2
- ax = plotters[self.hem_idx][self.depth_idx][4]
- scttr = ax.plot([x_pos, x_pos], [y_pos, y_pos], color = "red", symbol = "o", symbolPen = pyqtgraph.mkPen("red"), symbolBrush = pyqtgraph.mkBrush("red"))
- annot = pyqtgraph.TextItem(str(mrk_cnt[self.hem_idx][freq_idx])); ax.addItem(annot); annot.setPos(x_pos, y_pos)
- scatters[self.hem_idx][freq_idx][mrk_cnt[self.hem_idx][freq_idx] - 1].append((ax, scttr, annot))
- def mousePressEvent(self, ev):
- if (ev.button() != PyQt6.QtCore.Qt.MouseButton.LeftButton):
- return
- pos_xy = self.plotItem.vb.mapSceneToView(PyQt6.QtCore.QPointF(ev.pos().x(), ev.pos().y()))
- x_pos = pos_xy.x()
- if (self.scale_idx == 1):
- if (x_pos > 12 or x_pos < 8):
- return
- if (self.scale_idx == 3 or self.scale_idx == 4):
- if (x_pos > 32 or x_pos < 12):
- return
- if (self.scale_idx == 0 or self.scale_idx == 2):
- return
- self.update_mrk(x_pos)
- if (self.hem_idx == 0):
- config_type = "la" if (self.scale_idx == 1) else "lb"
- else:
- config_type = "ra" if (self.scale_idx == 1) else "rb"
- global config_wids
- if (self.hem_idx == 0):
- old_config_wid = config_wids[0][0] if (self.scale_idx == 1) else config_wids[0][1]
- else:
- old_config_wid = config_wids[1][0] if (self.scale_idx == 1) else config_wids[1][1]
- new_config_wid = PyQt6.QtWidgets.QWidget(objectName = "config panel")
- get_config_block(config_type, config_wid = new_config_wid, db_name = self.db_name)
- parent = old_config_wid.parent()
- parent.layout().replaceWidget(old_config_wid, new_config_wid)
- old_config_wid.close()
- parent.update()
- #return pyqtgraph.PlotWidget.mousePressEvent(self, ev)
- def get_central_plots(hem_idx, depth_cnt, ch_cnt, win_szs, bins, pwrs, ref_indices,
- lab_wid, db_name, f_name, pat_name,
- parent_layout, hem_wid):
- global plotters
- bttns = [[None for _ in range(len(SCALES))] for _ in range(depth_cnt)]
- main_wid = PyQt6.QtWidgets.QScrollArea()
- inner_wid = PyQt6.QtWidgets.QWidget()
- main_wid.setWidgetResizable(True)
- main_wid.setWidget(inner_wid)
- layout = PyQt6.QtWidgets.QGridLayout()
- layout.setSpacing(0)
- layout.setContentsMargins(0, 0, 0, 0)
- refresh_timer = PyQt6.QtCore.QTimer()
- inner_wid.setLayout(layout)
- for depth_idx in range(depth_cnt):
- for (scale_idx, _) in enumerate(SCALES):
- data_wid = PyQt6.QtWidgets.QWidget()
- data_wid.setFixedHeight(100)
- data_layout = PyQt6.QtWidgets.QHBoxLayout()
- data_wid.setLayout(data_layout)
- data_layout.setSpacing(0)
- data_layout.setContentsMargins(0, 0, 0, 0)
- data_wid.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Expanding, PyQt6.QtWidgets.QSizePolicy.Policy.Expanding)
- plotter = Custom_plot_widget(lab_wid, db_name, f_name, pat_name, scale_idx, depth_idx, hem_idx, hem_wid)
- plotter.setDragMode(PyQt6.QtWidgets.QGraphicsView.DragMode.NoDrag)
- data_layout.addWidget(plotter)
- plotters[hem_idx][depth_idx][scale_idx] = plotter
- plotter.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Expanding, PyQt6.QtWidgets.QSizePolicy.Policy.Expanding)
- plotter.setContentsMargins(0, 0, 0, 0);
- plotter.getAxis("left").hide()
- plotter.getAxis("bottom").hide()
- plotter.setFixedHeight(100)
- bttn = PyQt6.QtWidgets.QToolButton(); data_layout.addWidget(bttn); bttn.setText("X")
- bttns[depth_idx][scale_idx] = bttn
- bttn.clicked.connect(functools.partial(bttn_clicked, bttn, refresh_timer))
- bttn.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- layout.addWidget(data_wid, depth_idx, scale_idx)
- refresh_timer.timeout.connect(functools.partial(refresh_timer_expires, plotters, bttns, ch_cnt, depth_cnt, win_szs, bins, pwrs, ref_indices, hem_idx))
- refresh_timer.setSingleShot(True)
- parent_layout.addWidget(main_wid)
- return bttns
- def get_central_area(depth_cnt, db_name, f_name, pat_name, hem_idx,
- ch_cnt, win_szs, bins, pwrs, ref_indices,
- parent_layout, hem_wid):
- global is_valid
- wid = PyQt6.QtWidgets.QWidget()
- layout = PyQt6.QtWidgets.QVBoxLayout()
- wid.setLayout(layout)
- settings_wid = PyQt6.QtWidgets.QWidget()
- settings_layout = PyQt6.QtWidgets.QHBoxLayout()
- settings_wid.setLayout(settings_layout)
- cursor_pos_wid = PyQt6.QtWidgets.QLabel("Database: %s File: %s Patient: %s X-Pos: Y-Pos: " % (db_name, f_name, pat_name))
- cursor_pos_wid.setAlignment(PyQt6.QtCore.Qt.AlignmentFlag.AlignCenter)
- cursor_pos_wid.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Expanding, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- valid_bttn = PyQt6.QtWidgets.QPushButton(("valid" if (is_valid[hem_idx] == True) else "invalid"))
- valid_bttn.pressed.connect(functools.partial(valid_bttn_clicked, valid_bttn, hem_idx))
- valid_bttn.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- #valid_bttn.setMaximumWidth(60)
- settings_layout.addWidget((cursor_pos_wid))
- settings_layout.addWidget((valid_bttn))
- settings_layout.setContentsMargins(0, 0, 0, 0)
- layout.addWidget((settings_wid))
- bttns = get_central_plots(hem_idx, depth_cnt, ch_cnt, win_szs, bins, pwrs, ref_indices,
- cursor_pos_wid, db_name, f_name, pat_name,
- layout, hem_wid)
- parent_layout.addWidget(wid)
- return (bttns, cursor_pos_wid)
- def bttn_clicked(bttn, refresh_timer):
- if (bttn.text() == "X"):
- bttn.setText("-")
- else:
- bttn.setText("X")
- refresh_timer.stop()
- refresh_timer.start(REFRESH_TIMER_DELAY_MS)
- #===============================================================================
- # def mouse_moved(lab_wid, db_name, f_name, pat_name, event):
- # print("A")
- #
- # try:
- # x_pos = float(event.xdata)
- # y_pos = float(event.ydata)
- # except:
- # return
- #
- # lab_wid.setText("Database: %s File: %s Patient: %s X-Pos: %2.2f Y-Pos: %f" % (db_name, f_name, pat_name, x_pos, y_pos))
- # #lab_wid.setText("X-Pos: %2.2f Y-Pos: %f" % (x_pos, y_pos))
- #
- # #===========================================================================
- # # lab_wid.setText("X-Pos: %2.2f" % (event.xdata,))
- # #===========================================================================
- #===============================================================================
- def draw_data(plotter, bttns, hem_cnt, ch_cnt, depth_cnt, win_szs, bins, pwrs, ref_indices, scale_db):
- zoom_scales_min = [[999,999,999,999,999], [999,999,999,999,999]]
- zoom_scales_max = [[-999,-999,-999,-999,-999], [-999,-999,-999,-999,-999]]
- for hem_idx in range(hem_cnt):
- for depth_idx in range(depth_cnt[hem_idx]):
- for (scale_idx, _) in enumerate(SCALES):
- ax = plotter[hem_idx][depth_idx][scale_idx]
- ax.clear()
- ax.setXRange(SCALES[scale_idx][0], SCALES[scale_idx][1])
- for ch_idx in range(ch_cnt[hem_idx]):
- for win_sz_idx in range(len(win_szs)):
- if (bins[win_sz_idx][hem_idx][ch_idx][depth_idx] is not None):
- x_vals = bins[win_sz_idx][hem_idx][ch_idx][depth_idx][ref_indices[scale_idx][win_sz_idx][0]:ref_indices[scale_idx][win_sz_idx][1]]
- y_vals = pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx][ref_indices[scale_idx][win_sz_idx][0]:ref_indices[scale_idx][win_sz_idx][1]]
- loc_y_vals = np.copy(y_vals)
- loc_y_vals = np.pad(loc_y_vals, 2, mode = "edge")
- loc_y_vals = np.asarray(pandas.Series(loc_y_vals).rolling(window = 3, center = True).mean())
- loc_y_vals = loc_y_vals[2:-2]
- ax.plot(x_vals, y_vals, pen = pyqtgraph.mkPen(PLOT_COLORS[ch_idx], width = 0.75))
- ax.plot(x_vals, loc_y_vals, pen = pyqtgraph.mkPen(PLOT_COLORS[ch_idx], width = 0.75), linestyle = "--")
- if (scale_db):
- if (bttns[hem_idx][depth_idx][scale_idx].text() == "X"):
- if (np.abs(np.min(y_vals)) > 1e-5):
- zoom_scales_min[hem_idx][scale_idx] = np.min([zoom_scales_min[hem_idx][scale_idx], np.min(y_vals)])
- zoom_scales_max[hem_idx][scale_idx] = np.max([zoom_scales_max[hem_idx][scale_idx], np.max(y_vals)])
- else:
- if (bttns[hem_idx][depth_idx][scale_idx].text() == "X"):
- zoom_scales_min[hem_idx][scale_idx] = np.min([zoom_scales_min[hem_idx][scale_idx], np.min(y_vals)])
- zoom_scales_max[hem_idx][scale_idx] = np.max([zoom_scales_max[hem_idx][scale_idx], np.max(y_vals)])
- for hem_idx in range(hem_cnt):
- for depth_idx in range(depth_cnt[hem_idx]):
- for (scale_idx, _) in enumerate(SCALES):
- ax = plotter[hem_idx][depth_idx][scale_idx]
- ax.setYRange(zoom_scales_min[hem_idx][scale_idx], zoom_scales_max[hem_idx][scale_idx])
- def refresh_timer_expires(plotters, bttns, ch_cnt, depth_cnt, win_szs,
- bins, pwrs, ref_indices, hem_idx):
- zoom_scales_max = [-999, -999, -999, -999, -999]
- zoom_scales_min = [999, 999, 999, 999, 999]
- for depth_idx in range(depth_cnt):
- for (scale_idx, _) in enumerate(SCALES):
- ax = plotters[hem_idx][depth_idx][scale_idx]
- ax.clear()
- ax.setXRange(SCALES[scale_idx][0], SCALES[scale_idx][1])
- for ch_idx in range(ch_cnt):
- for win_sz_idx in range(len(win_szs)):
- if (bins[win_sz_idx][hem_idx][ch_idx][depth_idx] is not None):
- x_vals = bins[win_sz_idx][hem_idx][ch_idx][depth_idx][ref_indices[scale_idx][win_sz_idx][0]:ref_indices[scale_idx][win_sz_idx][1]]
- y_vals = pwrs[win_sz_idx][hem_idx][ch_idx][depth_idx][ref_indices[scale_idx][win_sz_idx][0]:ref_indices[scale_idx][win_sz_idx][1]]
- #ax.plot(x_vals, y_vals, pen = pyqtgraph.mkPen(PLOT_COLORS[ch_idx], width = 0.75))
- loc_y_vals = np.copy(y_vals)
- loc_y_vals = np.pad(loc_y_vals, 2, mode = "edge")
- loc_y_vals = np.asarray(pandas.Series(loc_y_vals).rolling(window = 3, center = True).mean())
- loc_y_vals = loc_y_vals[2:-2]
- ax.plot(x_vals, y_vals, pen = pyqtgraph.mkPen(PLOT_COLORS[ch_idx], width = 0.75))
- ax.plot(x_vals, loc_y_vals, pen = pyqtgraph.mkPen(PLOT_COLORS[ch_idx], width = 0.75), linestyle = "--")
- if (bttns[depth_idx][scale_idx].text() == "X"):
- zoom_scales_min[scale_idx] = np.min([zoom_scales_min[scale_idx], np.min(y_vals)])
- zoom_scales_max[scale_idx] = np.max([zoom_scales_max[scale_idx], np.max(y_vals)])
- for depth_idx in range(depth_cnt):
- for (scale_idx, _) in enumerate(SCALES):
- ax = plotters[hem_idx][depth_idx][scale_idx]
- ax.setYRange(zoom_scales_min[scale_idx], zoom_scales_max[scale_idx])
- global mrk_cnt; global mrk_pos; global mrk_depth; global scatters
- for freq_band_idx in range(FREQ_BAND_CNT):
- for mrk_idx in range(mrk_cnt[hem_idx][freq_band_idx]):
- x_pos = mrk_pos[hem_idx][freq_band_idx][mrk_idx]
- scatters[hem_idx][freq_band_idx][mrk_idx] = list()
- if (freq_band_idx == 0):
- y_pos = (plotters[hem_idx][mrk_depth[hem_idx][freq_band_idx][mrk_idx]][1].plotItem.viewRange()[1][0]+plotters[hem_idx][mrk_depth[hem_idx][freq_band_idx][mrk_idx]][1].plotItem.viewRange()[1][1])/2
- ax = plotters[hem_idx][mrk_depth[hem_idx][freq_band_idx][mrk_idx]][1]
- scttr = ax.plot([x_pos, x_pos], [y_pos, y_pos], color = "red", symbol = "o", symbolPen = pyqtgraph.mkPen("red"), symbolBrush = pyqtgraph.mkBrush("red"))
- annot = pyqtgraph.TextItem(str(mrk_idx + 1)); ax.addItem(annot); annot.setPos(x_pos, y_pos)
- scatters[hem_idx][freq_band_idx][mrk_idx].append((ax, scttr, annot))
- else:
- y_pos = (plotters[hem_idx][mrk_depth[hem_idx][freq_band_idx][mrk_idx]][3].plotItem.viewRange()[1][0]+plotters[hem_idx][mrk_depth[hem_idx][freq_band_idx][mrk_idx]][3].plotItem.viewRange()[1][1])/2
- ax = plotters[hem_idx][mrk_depth[hem_idx][freq_band_idx][mrk_idx]][3]
- scttr = ax.plot([x_pos, x_pos], [y_pos, y_pos], color = "red", symbol = "o", symbolPen = pyqtgraph.mkPen("red"), symbolBrush = pyqtgraph.mkBrush("red"))
- annot = pyqtgraph.TextItem(str(mrk_idx + 1)); ax.addItem(annot); annot.setPos(x_pos, y_pos)
- scatters[hem_idx][freq_band_idx][mrk_idx].append((ax, scttr, annot))
- y_pos = (plotters[hem_idx][mrk_depth[hem_idx][freq_band_idx][mrk_idx]][4].plotItem.viewRange()[1][0]+plotters[hem_idx][mrk_depth[hem_idx][freq_band_idx][mrk_idx]][4].plotItem.viewRange()[1][1])/2
- ax = plotters[hem_idx][mrk_depth[hem_idx][freq_band_idx][mrk_idx]][4]
- scttr = ax.plot([x_pos, x_pos], [y_pos, y_pos], color = "red", symbol = "o", symbolPen = pyqtgraph.mkPen("red"), symbolBrush = pyqtgraph.mkBrush("red"))
- annot = pyqtgraph.TextItem(str(mrk_idx + 1)); ax.addItem(annot); annot.setPos(x_pos, y_pos)
- scatters[hem_idx][freq_band_idx][mrk_idx].append((ax, scttr, annot))
- def on_close(wid, f_name, pat_name, db_name, cursor_pos_wid, hem_cnt):
- HEM_TO_STR = {0 : "l", 1 : "r"}
- for hem_idx in range(hem_cnt):
- wid.setCurrentIndex(hem_idx)
- cursor_pos_wid[hem_idx].setText("Database: %s X-Pos: Y-Pos: " % (db_name,))
- os.makedirs(PATH + "beta_pictures/" + db_name + "/", exist_ok = True)
- if (f_name == "n/a"):
- wid.grab().save(PATH + "beta_pictures/" + db_name + "/" + pat_name + "_" + HEM_TO_STR[hem_idx] + ".png")
- elif(pat_name == "n/a"):
- wid.grab().save(PATH + "beta_pictures/" + db_name + "/" + f_name + "_" + HEM_TO_STR[hem_idx] + ".png")
- else:
- wid.grab().save(PATH + "beta_pictures/" + db_name + "/" + pat_name + "_" + f_name + "_" + HEM_TO_STR[hem_idx] + ".png")
- print_output(f_name, pat_name, db_name)
- def get_pos_output(pos):
- global mrk_cnt; global mrk_pos; global mrk_depth; global config_wids
- if (pos == "la"):
- loc_mrk_cnt = mrk_cnt[0][0]
- loc_mrk_pos = mrk_pos[0][0]
- loc_mrk_depth = mrk_depth[0][0]
- loc_conf = 0
- elif (pos == "ra"):
- loc_mrk_cnt = mrk_cnt[1][0]
- loc_mrk_pos = mrk_pos[1][0]
- loc_mrk_depth = mrk_depth[1][0]
- loc_conf = 1
- elif (pos == "lb"):
- loc_mrk_cnt = mrk_cnt[0][1]
- loc_mrk_pos = mrk_pos[0][1]
- loc_mrk_depth = mrk_depth[0][1]
- loc_conf = 2
- elif (pos == "rb"):
- loc_mrk_cnt = mrk_cnt[1][1]
- loc_mrk_pos = mrk_pos[1][1]
- loc_mrk_depth = mrk_depth[1][1]
- loc_conf = 3
- global box_color, box_peak, box_noise, box_depth, box_lim, box_depvar, box_specstat, box_specwide, box_no_harm, box_unimod, box_plausible, box_unique, box_insight
- mrk_chs = [-1 for _ in range(3)]
- for loc_mrk_idx in range(loc_mrk_cnt):
- mrk_chs[loc_mrk_idx] = PLOT_COLORS.index(box_color[loc_conf][loc_mrk_idx])
- return ([INSIGHT_GAIN[box_insight[loc_conf][0]], loc_mrk_cnt, box_unique[loc_conf][0]], [loc_mrk_pos, loc_mrk_depth, mrk_chs,
- box_peak[loc_conf], box_noise[loc_conf], box_depth[loc_conf],
- box_lim[loc_conf], box_depvar[loc_conf], box_specstat[loc_conf],
- box_specwide[loc_conf], box_no_harm[loc_conf], box_plausible[loc_conf],
- box_unimod[loc_conf]])
- def print_output(f_name, pat_name, db_name):
- global is_valid
- (la_file_stats, la_mrk_stats) = get_pos_output("la")
- (ra_file_stats, ra_mrk_stats) = get_pos_output("ra")
- (lb_file_stats, lb_mrk_stats) = get_pos_output("lb")
- (rb_file_stats, rb_mrk_stats) = get_pos_output("rb")
- file = open(PATH + "beta_pictures/" + "0_per_file_lfp_beta.txt", "a")
- line = "\t".join([f_name, pat_name, db_name,
- str(la_file_stats[0]), str(la_file_stats[1]), str(la_file_stats[2]),
- str(ra_file_stats[0]), str(ra_file_stats[1]), str(ra_file_stats[2]),
- str(lb_file_stats[0]), str(lb_file_stats[1]), str(lb_file_stats[2]),
- str(rb_file_stats[0]), str(rb_file_stats[1]), str(rb_file_stats[2])])
- line += "\t" + str(is_valid[0]) + "\t" + str(is_valid[1])
- file.write(line + "\n")
- file.close()
- file = open(PATH + "beta_pictures/" + "0_per_peak_lfp_beta.txt", "a")
- for mrk_idx in range(la_file_stats[1]):
- line = "\t".join([f_name, pat_name, db_name, "la",
- str(la_mrk_stats[ 0][mrk_idx]), str(la_mrk_stats[ 1][mrk_idx]), str(la_mrk_stats[ 2][mrk_idx]), str(la_mrk_stats[ 3][mrk_idx]),
- str(la_mrk_stats[ 4][mrk_idx]), str(la_mrk_stats[ 5][mrk_idx]), str(la_mrk_stats[ 6][mrk_idx]), str(la_mrk_stats[ 7][mrk_idx]),
- str(la_mrk_stats[ 8][mrk_idx]), str(la_mrk_stats[ 9][mrk_idx]), str(la_mrk_stats[10][mrk_idx]), str(la_mrk_stats[11][mrk_idx]),
- str(la_mrk_stats[12][mrk_idx])])
- file.write(line + "\n")
- for mrk_idx in range(ra_file_stats[1]):
- line = "\t".join([f_name, pat_name, db_name, "ra",
- str(ra_mrk_stats[ 0][mrk_idx]), str(ra_mrk_stats[ 1][mrk_idx]), str(ra_mrk_stats[ 2][mrk_idx]), str(ra_mrk_stats[ 3][mrk_idx]),
- str(ra_mrk_stats[ 4][mrk_idx]), str(ra_mrk_stats[ 5][mrk_idx]), str(ra_mrk_stats[ 6][mrk_idx]), str(ra_mrk_stats[ 7][mrk_idx]),
- str(ra_mrk_stats[ 8][mrk_idx]), str(ra_mrk_stats[ 9][mrk_idx]), str(ra_mrk_stats[10][mrk_idx]), str(ra_mrk_stats[11][mrk_idx]),
- str(ra_mrk_stats[12][mrk_idx])])
- file.write(line + "\n")
- for mrk_idx in range(lb_file_stats[1]):
- line = "\t".join([f_name, pat_name, db_name, "lb",
- str(lb_mrk_stats[ 0][mrk_idx]), str(lb_mrk_stats[ 1][mrk_idx]), str(lb_mrk_stats[ 2][mrk_idx]), str(lb_mrk_stats[ 3][mrk_idx]),
- str(lb_mrk_stats[ 4][mrk_idx]), str(lb_mrk_stats[ 5][mrk_idx]), str(lb_mrk_stats[ 6][mrk_idx]), str(lb_mrk_stats[ 7][mrk_idx]),
- str(lb_mrk_stats[ 8][mrk_idx]), str(lb_mrk_stats[ 9][mrk_idx]), str(lb_mrk_stats[10][mrk_idx]), str(lb_mrk_stats[11][mrk_idx]),
- str(lb_mrk_stats[12][mrk_idx])])
- file.write(line + "\n")
- for mrk_idx in range(rb_file_stats[1]):
- line = "\t".join([f_name, pat_name, db_name, "rb",
- str(rb_mrk_stats[ 0][mrk_idx]), str(rb_mrk_stats[ 1][mrk_idx]), str(rb_mrk_stats[ 2][mrk_idx]), str(rb_mrk_stats[ 3][mrk_idx]),
- str(rb_mrk_stats[ 4][mrk_idx]), str(rb_mrk_stats[ 5][mrk_idx]), str(rb_mrk_stats[ 6][mrk_idx]), str(rb_mrk_stats[ 7][mrk_idx]),
- str(rb_mrk_stats[ 8][mrk_idx]), str(rb_mrk_stats[ 9][mrk_idx]), str(rb_mrk_stats[10][mrk_idx]), str(rb_mrk_stats[11][mrk_idx]),
- str(rb_mrk_stats[12][mrk_idx])])
- file.write(line + "\n")
- file.close()
- HEM_NAMES = ["left hemisphere", "right hemisphere"]
- def valid_bttn_clicked(bttn, hem_idx):
- global is_valid;
- if (is_valid[hem_idx]):
- is_valid[hem_idx] = False
- bttn.setText("invalid")
- else:
- is_valid[hem_idx] = True
- bttn.setText("valid")
- def run_internal(f_name, pat_name, db_name, raw_data, fs, win_szs, scale_db):
- hem_cnt = len(raw_data)
- freq_cnt = 2
- ch_cnt = [0, 0]; depth_cnt = [0, 0]
- if (raw_data[0] is not None):
- ch_cnt[0] = len(raw_data[0])
- if (raw_data[0][0] is not None):
- depth_cnt[0] = len(raw_data[0][0])
- if (raw_data[1] is not None):
- ch_cnt[1] = len(raw_data[1])
- if (raw_data[1][0] is not None):
- depth_cnt[1] = len(raw_data[1][0])
- global mrk_cnt; mrk_cnt = [[0 for _ in range(freq_cnt)] for _ in range (hem_cnt)]
- global mrk_pos; mrk_pos = [[[0 for _ in range(MAX_PEAKS)] for _ in range(freq_cnt)] for _ in range(hem_cnt)]
- global mrk_depth; mrk_depth = [[[-1 for _ in range(MAX_PEAKS)] for _ in range(freq_cnt)] for _ in range(hem_cnt)]
- global scatters; scatters = [[[None for _ in range(MAX_PEAKS)] for _ in range(freq_cnt)] for _ in range(hem_cnt)]
- global config_wids; config_wids = [[None for _ in range(freq_cnt)] for _ in range(hem_cnt)]
- global plotters; plotters = [[[None for _ in range(len(SCALES))] for _ in range(depth_cnt[hem_idx])] for hem_idx in range(hem_cnt)]
- global valid_chs; valid_chs = [[np.asarray([(raw_data[hem_idx][ch_idx][depth_idx] is not None) for depth_idx in range(depth_cnt[hem_idx])]).any() for ch_idx in range(ch_cnt[hem_idx])] for hem_idx in range(hem_cnt)]
- global is_valid; is_valid = [True, True]
- global box_color; box_color = [[-1 for _ in range(3)] for _ in range(4)]
- global box_peak; box_peak = [[-1 for _ in range(3)] for _ in range(4)]; global box_noise; box_noise = [[-1 for _ in range(3)] for _ in range(4)];
- global box_depth; box_depth = [[-1 for _ in range(3)] for _ in range(4)]; global box_lim; box_lim = [[-1 for _ in range(3)] for _ in range(4)];
- global box_depvar; box_depvar = [[-1 for _ in range(3)] for _ in range(4)]; global box_specstat; box_specstat = [[-1 for _ in range(3)] for _ in range(4)]
- global box_specwide; box_specwide = [[-1 for _ in range(3)] for _ in range(4)]; global box_no_harm; box_no_harm = [[-1 for _ in range(3)] for _ in range(4)];
- global box_unimod; box_unimod = [[-1 for _ in range(3)] for _ in range(4)]; global box_plausible; box_plausible = [[-1 for _ in range(3)] for _ in range(4)];
- global box_unique; box_unique = [[-1 for _ in range(1)] for _ in range(4)]; global box_insight; box_insight = [[-1 for _ in range(1)] for _ in range(4)]
- qapp = PyQt6.QtWidgets.QApplication([])
- app = PyQt6.QtWidgets.QMainWindow()
- (bins, pwrs, ref_indices) = get_psds(raw_data, fs, win_szs, depth_cnt, ch_cnt, db_name, scale_db)
- main_wid = PyQt6.QtWidgets.QWidget()
- layout = PyQt6.QtWidgets.QVBoxLayout()
- main_wid.setLayout(layout)
- #===========================================================================
- # settings_wid = PyQt6.QtWidgets.QWidget()
- # layout.addWidget(settings_wid)
- # settings_layout = PyQt6.QtWidgets.QHBoxLayout()
- # settings_layout.setContentsMargins(0, 0, 0, 0)
- # settings_layout.setSpacing(0)
- # settings_wid.setLayout(settings_layout)
- # settings_buffer = PyQt6.QtWidgets.QWidget()
- # settings_buffer.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Expanding, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- # valid_bttn = PyQt6.QtWidgets.QPushButton("valid" if (is_valid) else "invalid")
- # valid_bttn.pressed.connect(functools.partial(valid_bttn_clicked, valid_bttn))
- # valid_bttn.setSizePolicy(PyQt6.QtWidgets.QSizePolicy.Policy.Minimum, PyQt6.QtWidgets.QSizePolicy.Policy.Minimum)
- # valid_bttn.setMaximumWidth(100)
- # settings_layout.addWidget(settings_buffer, PyQt6.QtCore.Qt.AlignmentFlag.AlignRight)
- # settings_layout.addWidget(valid_bttn, PyQt6.QtCore.Qt.AlignmentFlag.AlignRight)
- #===========================================================================
- tab_wid = PyQt6.QtWidgets.QTabWidget(); app.setCentralWidget(main_wid)
- layout.addWidget(tab_wid)
- bttns = [None for _ in range(hem_cnt)]; cursor_pos_wids = [None for _ in range(hem_cnt)]
- for hem_idx in range(hem_cnt):
- hem_wid = PyQt6.QtWidgets.QWidget(objectName = "hem_wid")
- hem_layout = PyQt6.QtWidgets.QHBoxLayout()
- hem_wid.setLayout(hem_layout)
- get_config_panel(hem_idx, hem_layout)
- (bttns[hem_idx], cursor_pos_wids[hem_idx]) = get_central_area(depth_cnt[hem_idx], db_name, f_name, pat_name, hem_idx,
- ch_cnt[hem_idx], win_szs, bins, pwrs, ref_indices,
- hem_layout, hem_wid)
- tab_wid.addTab(hem_wid, HEM_NAMES[hem_idx])
- draw_data(plotters, bttns, hem_cnt, ch_cnt, depth_cnt, win_szs, bins, pwrs, ref_indices, scale_db)
- app.showMaximized()
- app.activateWindow()
- app.raise_()
- for hem_idx in range(hem_cnt):
- for depth_idx in range(depth_cnt[hem_idx]):
- for (scale_idx, _) in enumerate(SCALES):
- bttns[hem_idx][depth_idx][scale_idx].setFixedHeight(30)
- bttns[hem_idx][depth_idx][scale_idx].setFixedWidth(25)
- qapp.aboutToQuit.connect(functools.partial(on_close, tab_wid, f_name, pat_name, db_name, cursor_pos_wids, hem_cnt))
- qapp.exec()
- def run(f_name, pat_name, db_name, raw_data, fs, win_szs, scale_db = True, mode = "release"):
- if (mode == "release"):
- thread = multiprocessing.Process(target = run_internal, args = (f_name, pat_name, db_name, raw_data, fs, win_szs, scale_db))
- thread.start()
- thread.join()
- if (mode == "debug"):
- run_internal(f_name, pat_name, db_name, raw_data, fs, win_szs, scale_db)
core.py at commit 7c9f1e9, no license · at the source
Overview
- Department of Neurology, LMU University Hospital, LMU Munich, Munich, Germany
- Department of Neurology, Rostock University Medical Center, Rostock, Germany
- German Center for Neurodegenerative Diseases (DZNE) Rostock/Greifswald, Rostock, Germany
- Department of Neurosurgery, Rostock University Medical Center, Rostock, Germany
- Institute and Policlinic of Radiology, Pediatric Radiology and Neuroradiology, Rostock University Medical Center, Rostock, Germany
- Department of Neurosurgery, LMU University Hospital, LMU Munich, Munich, Germany
- Department of Translational Brain Research, German Center for Neurodegenerative Diseases (DZNE), Munich, Germany
Abstract
Elevated subthalamic (STN) beta (12–32 Hz) local field potentials (LFP) are a hallmark of Parkinson’s disease and closely tied to synchronized spiking. The biomarker guides deep brain stimulation (DBS) lead implantation and is under investigation to inform DBS programming and adaptive DBS, yet its prevalence has not been independently assessed. This study assesses the biomarkers prevalence and investigating its relationship to synchronized beta-bursting neurons. STN LFPs and spiking activity of n = 156 patients with Parkinson’s disease from seven DBS centers recorded via microelectrodes were examined and spectral LFP peaks classified. The distribution of phase angles between beta LFP and beta-bursting neurons was explored. Beta LFPs were bilaterally expressed in 47.25% of patients (65.59% of hemispheres). LFP-synchronized neuronal spiking clustered in two peaks, 182.84° phase shifted. This applied on the group level and for individual patients. Beta-LFP-informed approaches mandate reliable biomarker expression, a requirement not met by 52.75% of patients. This is particularly troublesome for intraoperative guidance wherein the cause of biomarker absence, including DBS lead misplacement or a balanced ratio of phasic and antiphasic spiking neurons, cannot be determined. While STN-LFP beta remains a valuable biomarker, multiple biomarkers should be evaluated simultaneously to increase robustness.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 3 matches between paragraphs and lines of code.
MaximilianScherer/2026_MS_beta_prevalence
7c9f1e9088ffed9e8d845ccf5034c349fa39cb4f, 15 December 2025Availability: 1 check, the latest on 26 September 2026: the link answers
- 26 September 2026: the link answers
36 files
- eval/
__init__.py , Python, 1 line - eval/
beta_prev_stats.py , Python, 833 lines, 1 match - eval/
pac_stats.py , Python, 589 lines - extract_coords_mni.m, MATLAB, 37 lines
- extract_coords_native.m, MATLAB, 29 lines
- feat_ex/
__init__.py , Python, 1 line - feat_ex/
beta/ , Python, 1 line__init__.py - feat_ex/
beta/ , Python, 1,058 lines, 1 matchcore.py - feat_ex/
beta/ , Python, 67 linesinterface.py - feat_ex/
spatial/ , Python, 1 line__init__.py - feat_ex/
spatial/ , Python, 481 lines, 1 matchvolumetric_screen.py - feat_ex/
spiking/ , Python, 1 line__init__.py - feat_ex/
spiking/ , Python, 522 linescore.py - feat_ex/
spiking/ , Python, 124 linesinterface.py - feat_ex/
spiking/ , Python, 65 linesspike_rating.py - filter_matching/
AD_conv.py , Python, 70 lines - filter_matching/
__init__.py , Python, 1 line - filter_matching/
demo.py , Python, 129 lines - filter_matching/
manual_matching.py , Python, 62 lines - misc/
__init__.py , Python, 1 line - misc/
meta_reader.py , Python, 142 lines - scrubber/
__init__.py , Python, 1 line - scrubber/
add_coords_to_db4_meta.p , Python, 55 linesy - scrubber/
add_depth_ch_ids.py , Python, 239 lines - scrubber/
core.py , Python, 180 lines - scrubber/
database1.py , Python, 150 lines - scrubber/
database2.py , Python, 173 lines - scrubber/
database3.py , Python, 225 lines - scrubber/
database4.py , Python, 469 lines - scrubber/
database6.py , Python, 267 lines - spatial/
__init__.py , Python, 1 line - spatial/
blender_code.py , Python, 158 lines - spatial/
calculate_rigid_trans.py , Python, 54 lines - spatial/
expl_nifti_trans.py , Python, 81 lines - spatial/
plotting.py , Python, 265 lines - spatial/
test2.py , Python, 47 lines
Zenodo 17951551
Availability: 1 check, the latest on 26 September 2026: the link answers (HTTP 200)
- 26 September 2026: the link answers (HTTP 200)
Zenodo 17940236
Availability: 1 check, the latest on 26 September 2026: the link answers (HTTP 200)
- 26 September 2026: the link answers (HTTP 200)
36 files
- eval/
__init__.py , Python, 1 line - eval/
beta_prev_stats.py , Python, 833 lines - eval/
pac_stats.py , Python, 589 lines - extract_coords_mni.m, MATLAB, 37 lines
- extract_coords_native.m, MATLAB, 29 lines
- feat_ex/
__init__.py , Python, 1 line - feat_ex/
beta/ , Python, 1 line__init__.py - feat_ex/
beta/ , Python, 1,058 linescore.py - feat_ex/
beta/ , Python, 67 linesinterface.py - feat_ex/
spatial/ , Python, 1 line__init__.py - feat_ex/
spatial/ , Python, 481 linesvolumetric_screen.py - feat_ex/
spiking/ , Python, 1 line__init__.py - feat_ex/
spiking/ , Python, 522 linescore.py - feat_ex/
spiking/ , Python, 124 linesinterface.py - feat_ex/
spiking/ , Python, 65 linesspike_rating.py - filter_matching/
AD_conv.py , Python, 70 lines - filter_matching/
__init__.py , Python, 1 line - filter_matching/
demo.py , Python, 129 lines - filter_matching/
manual_matching.py , Python, 62 lines - misc/
__init__.py , Python, 1 line - misc/
meta_reader.py , Python, 142 lines - scrubber/
__init__.py , Python, 1 line - scrubber/
add_coords_to_db4_meta.p , Python, 55 linesy - scrubber/
add_depth_ch_ids.py , Python, 239 lines - scrubber/
core.py , Python, 180 lines - scrubber/
database1.py , Python, 150 lines - scrubber/
database2.py , Python, 173 lines - scrubber/
database3.py , Python, 225 lines - scrubber/
database4.py , Python, 469 lines - scrubber/
database6.py , Python, 267 lines - spatial/
__init__.py , Python, 1 line - spatial/
blender_code.py , Python, 158 lines - spatial/
calculate_rigid_trans.py , Python, 54 lines - spatial/
expl_nifti_trans.py , Python, 81 lines - spatial/
plotting.py , Python, 265 lines - spatial/
test2.py , Python, 47 lines
Code availability
Python code written to support this evaluation has been made available at: https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 3 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 72 scripts, each with its path and the digest of its content;
- 3 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
- doi:10.18112/
openneuro.ds004998.v1.1. , at OpenNeuro; found in the references0
Data availability
Data from cohorts 1 to 3 are publicly available33,46,51. Data from cohorts 4 & 5 may be shared upon request. Graphical documentations for all LFP/
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 3, 28 September 2026
- Funding: added Alexander von Humboldt-Stiftung
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 9 authors, 3 keywords, 57 references.
Cite
This paper
Scherer, M., Wiedemann, N., Bötzel, K., Löhle, M., Kriesen, T., Cantré, D., Mehrkens, J. H., Reese, R., & Koeglsperger, T. (2026). Inconsistent subthalamic local field potential beta activity amid in- and antiphasic neuronal bursts. NPJ Parkinson's disease, 12(1), 222. https://
BibTeX
@article{scherer2026inco
author = {Scherer, Maximilian and Wiedemann, Nina and Bötzel, Kai and Löhle, Matthias and Kriesen, Thomas and Cantré, Daniel and Mehrkens, Jan Hinnerk and Reese, René and Koeglsperger, Thomas},
title = {{Inconsistent subthalamic local field potential beta activity amid in- and antiphasic neuronal bursts}},
journal = {NPJ Parkinson's disease},
year = {2026},
month = sep,
volume = {12},
number = {1},
pages = {222},
publisher = {Nature Publishing Group},
issn = {2373-8057},
doi = {10.1038/
url = {https://
pmid = {42749741},
pmcid = {PMC13582961}
}
RIS
TY - JOUR
AU - Scherer, Maximilian
AU - Wiedemann, Nina
AU - Bötzel, Kai
AU - Löhle, Matthias
AU - Kriesen, Thomas
AU - Cantré, Daniel
AU - Mehrkens, Jan Hinnerk
AU - Reese, René
AU - Koeglsperger, Thomas
TI - Inconsistent subthalamic local field potential beta activity amid in- and antiphasic neuronal bursts
T2 - NPJ Parkinson's disease
J2 - NPJ Parkinsons Dis
PY - 2026
DA - 2026/
VL - 12
IS - 1
SP - 222
SN - 2373-8057
PB - Nature Publishing Group
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "Inconsistent subthalamic local field potential beta activity amid in- and antiphasic neuronal bursts",
"container-title": "NPJ Parkinson's disease",
"author": [
{
"family": "Scherer",
"given": "Maximilian"
},
{
"family": "Wiedemann",
"given": "Nina"
},
{
"family": "Bötzel",
"given": "Kai"
},
{
"family": "Löhle",
"given": "Matthias"
},
{
"family": "Kriesen",
"given": "Thomas"
},
{
"family": "Cantré",
"given": "Daniel"
},
{
"family": "Mehrkens",
"given": "Jan Hinnerk"
},
{
"family": "Reese",
"given": "René"
},
{
"family": "Koeglsperger",
"given": "Thomas"
}
],
"container-title-short":
"volume": "12",
"issue": "1",
"page": "222",
"DOI": "10.1038/
"PMID": "42749741",
"PMCID": "PMC13582961",
"ISSN": "2373-8057",
"publisher": "Nature Publishing Group",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
9,
16
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41531-026-01380-1 [code]
- Identifying maximal beta power from directional subthalamic local field potentials in Parkinson's disease.Journal: NPJ Parkinson's diseaseIn common: MNE-Python, scikit-learn, pandas, 3 other tools, extracellular electrophysiology (units, LFP), Parkinson's, clinical / translational, 4 references
- [2] doi:10.1038/s41591-026-04432-4 [code]
- Activity-dependent adaptive deep brain stimulation improves gait in Parkinson's disease.Journal: Nature medicineIn common: MNE-Python, h5py, scikit-learn, 3 other tools, Parkinson's, clinical / translational, 4 references
- [3] doi:10.1002/ana.78206 [code]
- Multimodal Image Guidance in Subthalamic Deep Brain Stimulation for Parkinson's Disease.Journal: Annals of neurologyIn common: h5py, NiBabel, pandas, 3 other tools, Parkinson's, clinical / translational, 3 references
- [4] doi:10.1016/j.cnp.2026.08.008 [code]
- Subthalamic beta activity and neuroimaging concordance in deep brain stimulation: electrode placement and clinical outcomes.Journal: Clinical neurophysiology practiceIn common: pandas, SciPy, Matplotlib, 1 other tool, extracellular electrophysiology (units, LFP), clinical / translational, 4 references
- [5] doi:10.1093/braincomms/fcag328 [code]
- Subthalamic stimulation modulates working memory-related cortical dynamics in Parkinson's disease.Journal: Brain communicationsIn common: MNE-Python, pandas, SciPy, 2 other tools, Parkinson's, 3 references
- [6] doi:10.7554/elife.110588 [code]
- Opening the black box toward a modular approach to spike sorting.Journal: eLifeIn common: Neo, scikit-image, h5py, 5 other tools, extracellular electrophysiology (units, LFP)
- [7] doi:10.1038/s42003-026-10011-7 [code]
- Learning brain dynamics across distinct scaling regimes reveals psychiatric signatures.Journal: Communications biologyIn common: LMFIT, scikit-image, NiBabel, 5 other tools
- [8] doi:10.1007/s12021-026-09803-3 [code]
- NeuroFusion: A Unified Framework for Generalized Visual Stimulus Decoding from fMRI Across Datasets and Subjects.Journal: NeuroinformaticsIn common: MNE-Python, scikit-image, h5py, 6 other tools
- [9] doi:10.1117/1.nph.13.2.025001 [code]
- Surface-based image reconstruction optimization for high-density functional near-infrared spectroscopy.Journal: NeurophotonicsIn common: MNE-Python, scikit-image, h5py, 6 other tools
- [10] doi:10.1038/s41593-026-02228-w [code]
- Circuit response to neuromodulation characterized with simultaneous deep brain stimulation and precision neuroimaging in humans.Journal: Nature neuroscienceIn common: NiBabel, scikit-learn, pandas, 3 other tools, Parkinson's, 2 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 3 repositories of the authors' code, each at its verified commit and with its license, 72 scripts, and 3 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:e209fa6377faa76f…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[.
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
