def getResults(self): global data, results, rpeaks, sample_rate if self.results_whole.isChecked(): filt, rpeaks = ecg(signal=data, sampling_rate=sample_rate, show=False)[1:3] self.plotPeaks(data, rpeaks) rpeaks = rpeaks / sample_rate nni = tools.nn_intervals(rpeaks=rpeaks) results = hrv(nni=nni, rpeaks=rpeaks, sampling_rate=sample_rate, interval=[0, int(len(data) / sample_rate)], show=False) self.showPlots() self.time_domain_txt() s = str(folder + '/time_domain.txt') text = open(s).read() self.time_txt.setPlainText(text) self.freq_domain_txt() s = str(folder + '/frequency_domain.txt') text = open(s).read() self.freq_txt.setPlainText(text) self.nonlin_domain_txt() s = str(folder + '/nonlinear_domain.txt') text = open(s).read() self.nonlin_txt.setPlainText(text) elif self.results_part.isChecked(): limits = self.lr.getRegion() x = int(limits[0] * sample_rate) y = int(limits[1] * sample_rate) if x < 0: signal_t = data[0:y] elif y > len(data): signal_t = data[x:] else: signal_t = data[x:y] filt, rpeaks = ecg(signal=signal_t, sampling_rate=sample_rate, show=False)[1:3] self.plotPeaks(signal_t, rpeaks) rpeaks = rpeaks / sample_rate nni = tools.nn_intervals(rpeaks=rpeaks) results = hrv(nni=nni, rpeaks=rpeaks, sampling_rate=sample_rate, interval=[0, int(len(signal_t) / sample_rate)], show=False) self.showPlots() else: self.showMsg( 'Please select if you want HRV parameters for whole signal or for selected part' )
def rri_test_recurrent(filelist=None): global shape_tmp for i in range(len(filelist)): # for i in range(10): with open(filelist[i], 'rb') as f: plk_tmp = pkl.load(f) ecg_re = ecg.ecg(signal=plk_tmp, sampling_rate=Fs, show=False) rpeaks_tmp = ecg_re['rpeaks'].tolist() nni = tools.nn_intervals(rpeaks=rpeaks_tmp) nni_tmp = nni.reshape((-1, int(nni.shape[0]))) # for 2d data type rp = RecurrencePlot(threshold='point', percentage=20) X_rp = rp.fit_transform(nni_tmp) dst = cv2.resize(X_rp[0], dsize=(135, 135), interpolation=cv2.INTER_AREA) shape_tmp.append(X_rp.shape) recurrence_tmp.append(X_rp) recur_resize.append(dst) # for pandas # shape_tmp = shape_tmp.append(pd.DataFrame(X_rp.shape)) # plot check plt.imshow(X_rp[0], cmap='binary', origin='lower') plt.plot(nni) plt.title('Recurrence Plot', fontsize=16) plt.tight_layout() plt.show() # np_tmp = np.column_stack([np_tmp, X_rp]) if i == 0: pass return shape_tmp, recurrence_tmp, np.asarray(recur_resize)
def extractRR(self, x): r = biosppy.signals.ecg.ecg(x, sampling_rate=self.fs, show=False)[2] r = r.astype(float) # Compute NNI or RR nni = tools.nn_intervals(r) return nni * 4
def heart_rate_variability(sample, lead, rpeak_method = 'string'): curdir = 'DATA\TrainData_FeatureExtraction' [all_data, header_data, BAD_LABELS] = data_read.data_files_load(curdir) data = all_data[sample][lead] """INITIALIZE DETECTOR CLASS WITH THE SAMPLING RATE:""" detectors = Detectors(500) """FIND RPEAK USING ONE OF THE METHODS BELOW--------------------""" if rpeak_method == 'hamilton' or rpeak_method == 'string': #Hamilton. r_peaks = detectors.hamilton_detector(data) elif rpeak_method == 'christov': #Christov r_peaks = detectors.christov_detector(data) elif rpeak_method == 'engelse': #Engelse and Zeelenberg r_peaks = detectors.engzee_detector(data) elif rpeak_method == 'pan': #Pan and Tompkins r_peaks = detectors.pan_tompkins_detector(data) elif rpeak_method == 'stationary_wavelet': #Stationary Wavelet Transform r_peaks = detectors.swt_detector(data) elif rpeak_method == 'two_moving_average': #Two Moving Average r_peaks = detectors.two_average_detector(data) #elif rpeak_method == 'matched_filter': #Matched Filter #go to pyhrv documentation to find the template file #r_peaks = detectors.matched_filter_detector(data,template_file) """COMPUTE NNI SERIES-------------------------------------------""" nn = nn_intervals(r_peaks) #nni seems to be off by a factor of 3 print("\n\n", nn, "\n\n") """PLOT ECG/TACHOGRAM-------------------------------------------""" #plot_ecg(data, sampling_rate = 500) #tachogram(nn, sampling_rate = 500) """COMPUTE HRV--------------------------------------------------""" results = hrv(nn, None, None, 500) """COMPUTE HR PARAMETERS--(SOMETHING IS WRONG HERE BPM TOO HIGH)""" hr = heart_rate(nn) """COMPUTE FREQUENCY ANALYSIS-----------------------------------""" freq_results = results['fft_bands'] return results, hr, freq_results
def extractRR(self, x): X, r = biosppy.signals.ecg.ecg(x, sampling_rate=self.fs, show=False)[1:3] r = biosppy.signals.ecg.correct_rpeaks(signal=X, rpeaks=r, sampling_rate=self.fs)[0] r = r.astype(float) # Compute NNI or RR nni = tools.nn_intervals(r) return nni
def get_bvp_metrics(x, metric, sampling_rate=64): if metric == 'hr_mean': hr = biosppy.signals.bvp.bvp(x, sampling_rate=sampling_rate, show=False)['heart_rate'] return np.mean(hr) if metric == 'hrv_mean': onsets = biosppy.signals.bvp.bvp(x, sampling_rate=sampling_rate, show=False)['onsets'] hrv = tools.nn_intervals(onsets) return np.mean(hrv) if metric == 'hr_std': hr = biosppy.signals.bvp.bvp(x, sampling_rate=sampling_rate, show=False)['heart_rate'] return np.std(hr) if metric == 'hrv_std': onsets = biosppy.signals.bvp.bvp(x, sampling_rate=sampling_rate, show=False)['onsets'] hrv = tools.nn_intervals(onsets) return np.std(hrv) if metric == 'tinn': onsets = biosppy.signals.bvp.bvp(x, sampling_rate=sampling_rate, show=False)['onsets'] hrv = tools.nn_intervals(onsets) return get_geometrical_features(hrv)['triangular_index'] if metric == 'rms': onsets = biosppy.signals.bvp.bvp(x, sampling_rate=sampling_rate, show=False)['onsets'] hrv = tools.nn_intervals(onsets) return np.sqrt((1 / len(hrv)) * sum([i**2 for i in hrv])) return ValueError(f"Unsupported Metric {metric}")
def update(self): global data, rpeaks, nni, sample_rate t = tools.time_vector(signal=data, sampling_rate=sample_rate) self.view_signal.clear() self.view_signal.plot(t, data, pen=pg.mkPen('r')) self.view_signal.setLimits(xMin=0, xMax=t[-1]) self.view_signal.setMouseEnabled(x=True, y=False) self.view_signal.setLabel('bottom', text='Time [s]') filt, rpeaks = ecg(signal=data, sampling_rate=sample_rate, show=False)[1:3] rpeaks = rpeaks / sample_rate nni = tools.nn_intervals(rpeaks=rpeaks) t = np.cumsum(nni) / 1000. self.tachogram_view.clear() self.tachogram_view.plot(t, nni, pen=pg.mkPen('r')) self.tachogram_view.setLimits(xMin=0, xMax=t[-1]) self.tachogram_view.setMouseEnabled(x=True, y=False) self.tachogram_view.setLabel('bottom', text='Time [s]')
def resp_features(resp_peaks): bvp = tools.nn_intervals(resp_peaks.tolist()) resp_features = {} #------時系列解析------# L = len(resp_peaks) resp_features['bvp_mean'] = np.mean(bvp) resp_features['bvp_max'] = np.max(bvp) resp_features['bvp_min'] = np.min(bvp) resp_features['bvp_sdnn'] = np.std(bvp) resp_features['bvp_sdsd'] = np.std(np.diff(bvp)) resp_features['bvp_rmssd'] = np.sqrt((1 / L) * sum(np.diff(bvp)**2)) resp_features['bvp_median'] = np.median(bvp) #-----ポアンカレプロット-----# _, resp_features['bvp_sd1'], resp_features['bvp_sd2'], resp_features[ 'bvp_sd_ratio'], resp_features['bvp_ellipse_area'] = nl.poincare( rpeaks=resp_peaks.astype(int).tolist(), show=False) #------MultiScaleEntropy-----# # 後で追加すること return resp_features
def _computeSignal(self, signal): obj = {} # Best min_dist & thres for sphygmogram signal peaks = peak.indexes(signal, min_dist=56, thres=0.16) # Ignore un normal signls (with no peaks) if (len(peaks) == 0): return obj nn = tools.nn_intervals(peaks) # Ignore un normal signls (with no NN) if (len(nn) == 0): return welch = {'welch': self._welch_psd(nn, peaks)} lomb = {'lomb': self._lomb_psd(nn, peaks)} ar = {'ar': self._ar_psd(nn, peaks)} obj['welch'] = self._walk_over(welch, 'welch') obj['lomb'] = self._walk_over(lomb, 'lomb') obj['ar'] = self._walk_over(ar, 'ar') return obj
def _computeSignal(self, signal): obj = {} # Best min_dist & thres for sphygmogram signal peaks = peak.indexes(signal, min_dist=56, thres=0.16) # Ignore un normal signls (with no peaks) if (len(peaks) == 0): return obj nn = tools.nn_intervals(peaks) # Ignore un normal signls (with no NN) if (len(nn) == 0): return # Poincare method poincare = {'poincare': self._poincare(nn, peaks)} obj['poincare'] = self._walk_over(poincare, 'poincare') # ACF acf = {'ACF': self._ACF(signal, int(len(signal) / 2))} obj['ACF'] = self._walk_over(acf, 'ACF') return obj
def compute_nni(hrdata, sample_rate=64, sliding_window=.5, prominence=0.1, dist_q1=50, dist_q2=120, std_window=6, std_th=130, method='remove', plot=False): hrdata_inv = hrdata * (-1) """Calcuamos a media movil""" roll_mean = savgol_filter(hrdata_inv, 81, 2) # plt.figure() # plt.plot(hrdata_inv) # plt.plot(roll_mean) """Create sliding window to calculate maximum signal over time""" windowsize = int(sliding_window * sample_rate) add = np.zeros(int(windowsize / 2)) add[:] = np.nan hrdata_ext = np.concatenate((add, hrdata_inv, add)) """Calculamos la envolvente superior """ roll_max = [] for i in range(len(hrdata)): roll_max.append(np.nanmax(hrdata_ext[i:i + windowsize])) """Suavizamos la envolvente superior """ sroll_max = savgol_filter(roll_max, 51, 2) mn = .3 * np.std(sroll_max) sroll_max = sroll_max + mn # plt.plot(sroll_max) """Calculamos una representación simplificada del heart rate""" simpleHR_1 = (hrdata_inv - roll_mean) * (hrdata_inv > roll_mean) envoltorio = minmax(sroll_max - roll_mean) simpleHR_2_raw = sigmoid(0, 2, 5, envoltorio) * simpleHR_1 simpleHR_2 = savgol_filter(simpleHR_2_raw, 31, 2) * (hrdata_inv > roll_mean) # plt.plot(simpleHR_2) """ Find the centers of the peaks of the signal """ peaksx = np.where((simpleHR_2 > 0))[0] peaksy = simpleHR_2[peaksx] peaks, a = find_peaks(peaksy, prominence=prominence) # plt.plot(peaksx[peaks],simpleHR_2[peaksx[peaks]],'*m') """ Create an array with the distances between peaks and filter the outlayers of missing beats (high or very low distances) """ nni = tools.nn_intervals((peaksx[peaks] / sample_rate) * 1000) hr = tools.heart_rate(nni) nni_revised = np.zeros_like(nni) nni_revised[:] = np.nan index = np.logical_and((hr >= dist_q1), (hr <= dist_q2)) nni_revised[index] = nni[index] nni_revised = nni_revised[~np.isnan(nni_revised)] std = std_convoluted(nni_revised, std_window) # plt.figure() # plt.plot(nni_revised) # plt.plot(nni) # plt.plot(std) index_std = [i for i in range(len(zscore(std))) if std[i] > std_th] groups = np.append(np.diff(index_std), 100) if groups[0] > 1: groups = groups[1:] index_diff = np.where(groups > 1)[0] if len(index_diff) > 1: start = 0 end = index_diff[0] for i in range(1, len(index_diff) - 1): index_hole = index_std[start:end] # # plt.figure() # plt.plot(nni_revised[index_hole]) if method == 'remove': aux = np.zeros(nni_revised[index_hole].shape) aux[:] = np.nan nni_revised[ index_hole] = aux #outliers_iqr_method(nni_revised[index_hole]) elif method == 'iqr': nni_revised[index_hole] = outliers_iqr_method( nni_revised[index_hole]) elif method == 'modified_z': nni_revised[index_hole] = outliers_modified_z( nni_revised[index_hole]) # plt.plot(nni_revised[index_hole]) start = index_diff[i - 1] end = index_diff[i] nni_revised = nni_revised[~np.isnan(nni_revised)] """Representamos las graficas necesarias para visualizar los datos""" if plot: fig, axes = plt.subplots(2, 2) axes[0, 0].plot(hrdata_inv) axes[0, 0].plot(roll_mean) axes[0, 0].plot(roll_max) axes[0, 1].plot(simpleHR_1) axes[0, 1].plot(simpleHR_2) axes[0, 1].plot(peaksx[peaks], peaksy[peaks], 'kx') if len(nni_revised) % 2 == 0: size = len(nni_revised) - 1 else: size = len(nni_revised) axes[1, 0].plot(nni) axes[1, 0].plot(nni_revised) axes[1, 0].plot(savgol_filter(nni_revised, min([101, size]), 2)) plt.legend(['original', 'revised', 'fit']) # axes[1, 1].plot(tools.heart_rate(nni_revised)) axes[1, 1].plot( savgol_filter(tools.heart_rate(nni_revised), min([101, size]), 2)) axes[1, 1].set_ylim([40, 120]) plt.legend(['Heart Rate']) # axes[1,1].plot((nni-np.nanmean(nni))/np.nanstd(nni)) # axes[1,1].plot((nni_revised-np.nanmean(nni))/np.nanstd(nni)) # axes[1,1].plot((std-np.nanmean(std))/np.nanstd(std) ) return nni_revised
import biosignal_plot path = r"C:\Users\akito\Desktop\test.txt" arc = OpenSignalsReader(path) # 心拍データからピークを取り出す ecg_result = signals.ecg.ecg(signal=arc.signal(['ECG']), sampling_rate=1000.0, show=False) # 呼吸周波数を取り出す resp_result = resp_analysis.resp(arc.signal('RESP'), show=False) # 描画設定 fig, axes = plt.subplots(2, 1, sharex=True, figsize=(16, 9)) axes[0].set_title(path) # Compute NNI series nni = tools.nn_intervals(ecg_result['rpeaks'].tolist()) filtered = biosignal_plot.detrend(nni, 500) # 心拍変動の描画 axes[0].plot(ecg_result['heart_rate_ts'].tolist(), filtered, 'b') axes[0].set_ylabel("HR[bpm]") # 呼吸の描画 axes[1].plot(resp_result['ts'], resp_result['filtered']) for ins, exp in zip(resp_result['inspiration'], resp_result['expiration']): axes[0].axvline(ins * 0.001, color='b') axes[0].axvline(exp * 0.001, color='r') plt.show()
def _computeSignal(self, signal): obj = {} # Best min_dist & thres for sphygmogram signal peaks = peak.indexes(signal, min_dist=56, thres=0.16) # Ignore un normal signls (with no peaks) if (len(peaks) == 0): return obj nn = tools.nn_intervals(peaks) # Ignore un normal signls (with no NN) if (len(nn) == 0): return # Standard obj = dict(td.nni_parameters(nn, peaks), **obj) obj = dict(td.nni_differences_parameters(nn, peaks), **obj) obj = dict(td.sdnn(nn, peaks), **obj) obj = dict(td.sdnn_index(nn, peaks), **obj) obj = dict(td.sdann(nn, peaks), **obj) obj = dict(td.rmssd(nn, peaks), **obj) obj = dict(td.sdsd(nn, peaks), **obj) obj = dict(td.nn50(nn, peaks), **obj) obj = dict(td.nn20(nn, peaks), **obj) obj = dict(td.geometrical_parameters(nn, peaks, plot=False), **obj) del obj['nni_histogram'] # Additional obj = dict({'cv': self._cv(obj['sdnn'], obj['nni_mean'])}, **obj) peaks_diff = tools.nni_diff(peaks) obj = dict({'MxDMn': max(peaks_diff) - min(peaks_diff)}, **obj) obj = dict({'MxRMn': max(peaks_diff) / min(peaks_diff)}, **obj) obj = dict({'Mo': stats.mode(peaks_diff)[0][0]}, **obj) counter = Counter(peaks_diff) idx = list(counter.keys()).index(obj["Mo"]) obj = dict({'AMo': list(counter.values())[idx]}, **obj) obj = dict({'SI': obj['AMo'] / (2 * obj['Mo'] * obj['MxDMn'])}, **obj) # Autocorrelation function # Frequency stats welch = frequency_domain(signal).stats['welch']['params'] bands = list(welch['fft_bands'].keys()) obj = dict({'TP': welch['fft_total']}, **obj) obj = dict({'HF': welch['fft_rel'][bands.index('hf')]}, **obj) obj = dict({'LF': welch['fft_rel'][bands.index('lf')]}, **obj) obj = dict({'VLF': welch['fft_rel'][bands.index('vlf')]}, **obj) obj = dict({'ULF': welch['fft_rel'][bands.index('ulf')]}, **obj) obj = dict({'HFav': welch['fft_abs'][bands.index('hf')]}, **obj) obj = dict({'LFav': welch['fft_abs'][bands.index('lf')]}, **obj) obj = dict({'VLFav': welch['fft_abs'][bands.index('vlf')]}, **obj) obj = dict({'ULFav': welch['fft_abs'][bands.index('ulf')]}, **obj) obj = dict({'(LF/HF)av': obj['LFav'] / obj['HFav']}, **obj) obj = dict({'IC': obj['LF'] / obj['VLF']}, **obj) for k in obj: if (math.isnan(obj[k])): obj[k] = 0 return obj
def metrics(self): import pyhrv.tools as tools intervalosNN = tools.nn_intervals(self.peaks_fpos) time_domain_features = get_time_domain_features( intervalosNN[intervalosNN != 0]) frecuency_domain_features = get_frequency_domain_features(intervalosNN) geometrical_features = get_geometrical_features(intervalosNN) self.ui.scrollAreaFeatures.setStyleSheet('background-color: white') layout = QHBoxLayout() label = QLabel('<h3>Time Domain Features<h3>') label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label.setStyleSheet("color: rgb(59,59,59)") label.setMaximumWidth(290) layout.addWidget(label) self.ui.verticalLayout_features.addLayout(layout) time_domain_features_to_show = { 'SDNN': time_domain_features['sdnn'], 'SDSD': time_domain_features['sdsd'], 'SDANN': self.sdann, 'RMSSD': time_domain_features['rmssd'] } time_domain_features_to_show2 = { 'NN20 Count': time_domain_features['nni_20'], 'NN50 Count': time_domain_features['nni_50'], 'PNN50 Count': time_domain_features['pnni_50'], 'PNN20 Count': time_domain_features['pnni_20'] } for key, value in time_domain_features_to_show.items(): layout = QVBoxLayout() label = QLabel('<h4>' + str(key) + ':</h4>') label.setStyleSheet("color: rgb(59,59,59)") label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label.setMaximumWidth(122) layout.addWidget(label) label1 = QLabel("{:.4f}".format(value)) label1.setStyleSheet( "padding: 5px; border: 1px solid #cccccc; border-radius: 5px; background-color:#cccccc;" ) label1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label1.setMaximumWidth(122) layout.addWidget(label1) self.ui.verticalLayout_features1.addLayout(layout) for key, value in time_domain_features_to_show2.items(): layout = QVBoxLayout() label = QLabel('<h4>' + str(key) + ':</h4>') label.setStyleSheet("color: rgb(59,59,59)") label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label.setMaximumWidth(122) layout.addWidget(label) label1 = QLabel("{:.4f}".format(value)) label1.setStyleSheet( "padding: 5px; border: 1px solid #cccccc; border-radius: 5px; background-color:#cccccc;" ) label1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label1.setMaximumWidth(122) layout.addWidget(label1) self.ui.verticalLayout_features2.addLayout(layout) frecuency_domain_features_to_show = { 'LF': frecuency_domain_features['lf'], 'HF': frecuency_domain_features['hf'], 'VLF': frecuency_domain_features['vlf'] } frecuency_domain_features_to_show2 = { 'LF norm': frecuency_domain_features['vlf'], 'HF norm': frecuency_domain_features['hfnu'], 'Total power': frecuency_domain_features['total_power'] } layout = QHBoxLayout() label = QLabel('<h3>Frecuency Domain Features</h3>') label.setStyleSheet("color: rgb(59,59,59)") label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label.setMaximumWidth(290) layout.addWidget(label) self.ui.verticalLayout_features3.addLayout(layout) for key, value in frecuency_domain_features_to_show.items(): layout = QVBoxLayout() label = QLabel('<h4>' + str(key) + ':</h4>') label.setStyleSheet("color: rgb(59,59,59)") label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label.setMaximumWidth(122) layout.addWidget(label) label1 = QLabel("{:.4f}".format(value)) label1.setStyleSheet( "padding: 5px; border: 1px solid #cccccc; border-radius: 5px; background-color:#cccccc;" ) label1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label1.setMaximumWidth(122) layout.addWidget(label1) self.ui.verticalLayout_features4.addLayout(layout) for key, value in frecuency_domain_features_to_show2.items(): layout = QVBoxLayout() label = QLabel('<h4>' + str(key) + ':</h4>') label.setStyleSheet("color: rgb(59,59,59)") label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label.setMaximumWidth(122) layout.addWidget(label) label1 = QLabel("{:.4f}".format(value)) label1.setStyleSheet( "padding: 5px; border: 1px solid #cccccc; border-radius: 5px; background-color:#cccccc;" ) label1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label1.setMaximumWidth(122) layout.addWidget(label1) self.ui.verticalLayout_features5.addLayout(layout) geometrical_features_to_show = {'TINN': geometrical_features['tinn']} geometrical_features_to_show2 = { 'Triangular Index': geometrical_features['triangular_index'] } layout = QHBoxLayout() label = QLabel('<h3>Geometrical Domain Features</h3>') label.setStyleSheet("color: rgb(59,59,59)") label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label.setMaximumWidth(290) layout.addWidget(label) self.ui.verticalLayout_features6.addLayout(layout) for key, value in geometrical_features_to_show2.items(): layout = QVBoxLayout() label = QLabel('<h4>' + str(key) + ':</h4>') label.setStyleSheet("color: rgb(59,59,59)") label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label.setMaximumWidth(122) layout.addWidget(label) label1 = QLabel("{:.4f}".format(value)) label1.setStyleSheet( "padding: 5px; border: 1px solid #cccccc; border-radius: 5px; background-color:#cccccc;" ) label1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label1.setMaximumWidth(122) layout.addWidget(label1) self.ui.verticalLayout_features7.addLayout(layout) for key, value in geometrical_features_to_show.items(): layout = QVBoxLayout() label = QLabel('<h4>' + str(key) + ':</h4>') label.setStyleSheet("color: rgb(59,59,59)") label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label.setMaximumWidth(122) layout.addWidget(label) label1 = QLabel(str(value)) label1.setStyleSheet( "padding: 5px; border: 1px solid #cccccc; border-radius: 5px; background-color:#cccccc;" ) label1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) label1.setMaximumWidth(122) layout.addWidget(label1) self.ui.verticalLayout_features8.addLayout(layout) from hrvanalysis import plot_psd