def click_estimate_amplitudes(self): idx = self.trace_idx data = self.cf.get_trace_data(idx) tattrs = self.cf.get_trace_attrs(idx) data = process_data(data, tattrs, key="_log") fs = decode(tattrs["samplingrate"]) nlat = int((decode(tattrs["neg_peak_latency_ms"]) or 0) * fs / 1000) plat = int((decode(tattrs["pos_peak_latency_ms"]) or 0) * fs / 1000) # MEP negative trials if nlat == plat: print("MEP negative or identical latencies", nlat, plat) tattrs["neg_peak_latency_ms"] = encode(0) tattrs["pos_peak_latency_ms"] = encode(0) tattrs["neg_peak_magnitude_uv"] = encode(0) tattrs["pos_peak_magnitude_uv"] = encode(0) else: pre = decode(tattrs["samples_pre_event"]) shift = decode(tattrs["onset_shift"]) or 0 namp = float(data[nlat + pre + shift]) pamp = float(data[plat + pre + shift]) print("Estimating amplitudes to be", namp, pamp) tattrs["neg_peak_magnitude_uv"] = encode(namp) tattrs["pos_peak_magnitude_uv"] = encode(pamp) self.cf.set_trace_attrs(idx, tattrs) self.draw_hasmep_button() self.callback()
def __init__(self, cf: CacheFile, idx: int, *args, **kwargs): super(TattrWidget, self).__init__(*args, **kwargs) tattrs = self.get_cleaned_tattrs(cf, idx) layout = QtWidgets.QGridLayout() row = 0 for key in tattrs.keys(): label = QtWidgets.QLabel(text=key.replace("_", " ").capitalize()) if type(decode(tattrs[key])) == float: val = "{0:3.3f}".format(decode(tattrs[key])) line = QtWidgets.QLineEdit(val) else: line = QtWidgets.QLineEdit(tattrs[key]) trig = partial(save, cf=cf, idx=idx, key=key, read=line.text) line.textChanged.connect(trig) layout.addWidget(label, row, 0) layout.addWidget(line, row, 1) row += 1 key = "comment" tattrs = cf.get_trace_attrs(idx) label = QtWidgets.QLabel(text=key) line = VTextEdit(tattrs[key]) trig = partial(save, cf=cf, idx=idx, key=key, read=line.toPlainText) line.editingFinished.connect(trig) layout.addWidget(label, row, 0) layout.addWidget(line, row, 1) self.setLayout(layout)
def click_estimate_parameters(self): window = (15, 120) idx = self.trace_idx data = self.cf.get_trace_data(idx) tattrs = self.cf.get_trace_attrs(idx) data = process_data(data, tattrs, key="_log") pre = decode(tattrs["samples_pre_event"]) shift = decode(tattrs["onset_shift"]) or 0 fs = decode(tattrs["samplingrate"]) onset = pre - shift print(shift, fs) minlat = int(window[0] * fs / 1000) maxlat = int(window[1] * fs / 1000) a = onset + minlat b = onset + maxlat mep = data[a:b] nlat = mep.argmin() plat = mep.argmax() namp = float(mep[nlat]) pamp = float(mep[plat]) nlat = mep.argmin() * 1000 / fs plat = mep.argmax() * 1000 / fs print("Estimating latencies to be", nlat, plat) print("Estimating amplitudes to be", namp, pamp) tattrs["neg_peak_latency_ms"] = encode(float(nlat + window[0])) tattrs["neg_peak_magnitude_uv"] = encode(namp) tattrs["pos_peak_latency_ms"] = encode(float(plat + window[0])) tattrs["pos_peak_magnitude_uv"] = encode(pamp) self.cf.set_trace_attrs(idx, tattrs) self.draw_hasmep_button() self.callback()
def draw_hasmep_button(self): tattrs = self.cf.get_trace_attrs(self.trace_idx) pamp = decode(tattrs["pos_peak_magnitude_uv"]) or 0 namp = decode(tattrs["neg_peak_magnitude_uv"]) or 0 ptp = pamp - namp if ptp != 0: self.hasmep_button.setStyleSheet("background-color: green") self.hasmep_button.setText("MEP positive") else: self.hasmep_button.setStyleSheet("background-color: red") self.hasmep_button.setText("MEP negative")
def plot_trace(self, cf, idx: int = 0): data = cf.get_trace_data(idx) attrs = cf.get_trace_attrs(idx) pre = decode(attrs["samples_pre_event"]) post = decode(attrs["samples_post_event"]) fs = decode(attrs["samplingrate"]) shift = decode(attrs["onset_shift"]) shift = shift or 0 t0 = -float(pre) / float(fs) t1 = float(post) / float(fs) nlat = decode(attrs["neg_peak_latency_ms"]) or 0.0 plat = decode(attrs["pos_peak_latency_ms"]) or 1.0 namp = decode(attrs["neg_peak_magnitude_uv"]) or 0.0 pamp = decode(attrs["pos_peak_magnitude_uv"]) or 0.0 nlat = int(nlat * float(fs) / 1000) plat = int(plat * float(fs) / 1000) if nlat < plat: amps = (namp, pamp) lats = (nlat, plat) else: amps = (pamp, namp) lats = (plat, nlat) try: # perform preprocessing steps data = process_data(data, attrs, key="_log") plot_trace_on(self.canvas.axes, data, t0, t1, pre, post, lats, amps, shift) print(f"PLOT: Plotting trace number {idx+1} shifted by {shift} samples") except Exception as e: print(e)
def flip_reject_button(self): tattrs = self.cf.get_trace_attrs(self.trace_idx) reject = decode(tattrs["reject"]) reject = True if reject is None else not reject tattrs["reject"] = reject self.cf.set_trace_attrs(self.trace_idx, tattrs) self.draw_reject_button()
def rescale_coords(attrs: TraceAttributes, scaling_factor: float = 1.0) -> TraceAttributes: """scale the coordinates of this trace by a scaling factor""" coords = decode(attrs["xyz_coords"]) coords = [float * c for c in coords] attrs["xyz_coords"] = encode(coords) return attrs
def translate_coords( attrs: TraceAttributes, translation: List[float] = [0.0, 0.0, 0.0]) -> TraceAttributes: """move the coordinates of this trace by a translation""" coords = decode(attrs["xyz_coords"]) coords = [c - t for c, t in zip(coords, translation)] attrs["xyz_coords"] = encode(coords) return attrs
def draw_undo_button(self): _log = decode( self.cf.get_trace_attrs(self.trace_idx).get("_log", "[]")) if _log != []: log = "\n".join(_log) self.undo_button.setToolTip(log) self.undo_button.setStyleSheet("background-color: gray") else: self.undo_button.setToolTip("No processing steps in cache") self.undo_button.setStyleSheet("background-color: None")
def _draw(self, cf: CacheFile, idx: int, tmpdir): tattrs = cf.get_trace_attrs(idx) coords = decode(tattrs["xyz_coords"]) print(f"COORDS: Stimulation target was at {coords}") try: plot_glass_on(axes=self.canvas.axes, coords=coords, tmpdir=tmpdir) except Exception as e: InvalidCoordsDialog(cf=cf, idx=idx, message=str(e)) self.canvas.axes.axis("off") self.canvas.draw()
def draw_reject_button(self): tattrs = self.cf.get_trace_attrs(self.trace_idx) reject = decode(tattrs["reject"]) reject = False if reject is None else reject self.cf.set_trace_attrs(self.trace_idx, tattrs) if reject: self.reject_button.setStyleSheet("background-color: red") self.reject_button.setText("Rejected") else: self.reject_button.setStyleSheet("background-color: green") self.reject_button.setText("Accepted")
def draw_int(self, idx: int = 0): self.idx = idx tattr = self.cf.get_trace_attrs(self.idx) val = decode(tattr[self.key]) val = val or 0 if type(val) == str: val = 0 elif type(val) == float: val = int(val) val = "{0:3.0f}".format(val) print(f"TATTR: Loading {self.key}:{val} for {idx}") self.line.setText(val)
def log(self, event: str, idx: int): attrs = self.cf.get_trace_attrs(idx) if "_log" in attrs.keys(): log = decode(attrs["_log"]) else: log = [] happening = str(event) + " on " + datetime.now().strftime( "%Y-%m-%d %H:%M:%S") print("Logging", happening, "to", log) log.append(happening) attrs["_log"] = encode(log) self.cf.set_trace_attrs(self.trace_idx, attrs)
def undo(self, idx): attrs = self.cf.get_trace_attrs(idx) if "_log" in attrs.keys(): log = decode(attrs["_log"]) else: log = [] if len(log) > 0: event = log.pop() step, when = event.split(" on ") print("Undoing", step, "from", when) else: print("Nothing to undo") attrs["_log"] = encode(log) self.cf.set_trace_attrs(self.trace_idx, attrs)
def get_cleaned_tattrs(self, cf, idx): tattrs = cf.get_trace_attrs(idx) initialize_with_zero = [ "onset_shift", "neg_peak_latency_ms", "pos_peak_latency_ms", "neg_peak_magnitude_uv", "pos_peak_magnitude_uv", ] for key in initialize_with_zero: tattrs[key] = encode(decode(tattrs[key]) or 0) cf.set_trace_attrs(idx, tattrs) keys = get_valid_trace_keys(tattrs["readin"], tattrs["readout"]).copy() keys.remove("reject") keys.remove("onset_shift") keys.remove("comment") show_tattrs = dict() for key in sorted(keys): if key[0] != "_": show_tattrs[key] = tattrs[key] return show_tattrs
def __init__(self, cf: CacheFile, idx: int, *args, **kwargs): super(OattrWidget, self).__init__(*args, **kwargs) tattr = cf.get_trace_attrs(idx) layout = QtWidgets.QGridLayout() keys = sorted(valid_origin_keys).copy() keys.remove("global_comment") keys.remove("channel_labels") row = 0 for key in keys: label = QtWidgets.QLabel(text=key) line = QtWidgets.QLabel(tattr[key]) layout.addWidget(label, row, 0) layout.addWidget(line, row, 1) row += 1 key = "channel_labels" label = QtWidgets.QLabel(text=key) line = QtWidgets.QListWidget() entries = decode(tattr[key]) line.addItems(entries) line.setFlow(line.LeftToRight) line.setMaximumHeight(50) layout.addWidget(label, row, 0) layout.addWidget(line, row, 1) row += 1 key = "global_comment" label = QtWidgets.QLabel(text=key) line = VTextEdit(tattr[key]) trig = partial(save_global, cf=cf, idx=idx, key=key, read=line.toPlainText) line.editingFinished.connect(trig) layout.addWidget(label, row, 0) layout.addWidget(line, row, 1) self.setLayout(layout)