def get_clipped_heartbeat_signals(self, i, start, interval,
                                      composite_start, composite_end):
        # Center signals in current interval at the R peak
        heartbeat_time = self.peaks.time[interval] - self.peaks.time[
            self.peaks.R.data[start + 1 + i]]
        heartbeat_signal = self.peaks.signal[interval] - self.peaks.signal[
            self.peaks.R.data[start + 1 + i]]
        heartbeat_seis = self.peaks.seis[interval] - self.peaks.signal[
            self.peaks.R.data[start + 1 + i]]
        heartbeat_phono = self.peaks.phono[interval] - self.peaks.signal[
            self.peaks.R.data[start + 1 + i]]

        # Clip Front
        remove_from_start = int(
            np.where(heartbeat_time == 0)[0] - composite_start)
        if remove_from_start != 0:
            heartbeat_time = np.delete(heartbeat_time,
                                       range(remove_from_start))
            heartbeat_signal = np.delete(heartbeat_signal,
                                         range(remove_from_start))
            heartbeat_seis = np.delete(heartbeat_seis,
                                       range(remove_from_start))
            heartbeat_phono = np.delete(heartbeat_phono,
                                        range(remove_from_start))

        # Clip Back
        remove_from_end = int((len(heartbeat_time) -
                               np.where(heartbeat_time == 0)[0]) -
                              composite_end)
        if remove_from_end != 0:
            heartbeat_time = np.delete(
                heartbeat_time,
                range(
                    len(heartbeat_time) - remove_from_end,
                    len(heartbeat_time)))
            heartbeat_signal = np.delete(
                heartbeat_signal,
                range(
                    len(heartbeat_time) - remove_from_end,
                    len(heartbeat_time)))
            heartbeat_seis = np.delete(
                heartbeat_seis,
                range(
                    len(heartbeat_time) - remove_from_end,
                    len(heartbeat_time)))
            heartbeat_phono = np.delete(
                heartbeat_phono,
                range(
                    len(heartbeat_time) - remove_from_end,
                    len(heartbeat_time)))

        # Normalize
        heartbeat_signal = hb.normalize(heartbeat_signal)
        heartbeat_seis = hb.normalize(heartbeat_seis)
        heartbeat_phono = hb.normalize(heartbeat_phono)

        return heartbeat_time, heartbeat_signal, heartbeat_seis, heartbeat_phono
Exemple #2
0
    def update_plot(self):
        # Update index
        self.i_text.set_text("Heartbeat: " + str(self.index + 1) + "/" + str(len(self.peaks.R.data) - 1))

        self.signal = hb.normalize(self.peaks.signal[range(self.peaks.P.data[self.index], self.peaks.R.data[self.index + 1])])

        # Pass through a Low pass
        self.smoothed_signal = hb.lowpass_filter(signal = self.signal,
                                            cutoff_freq = self.cutoff_freq)

        # Calculate first derivative
        self.first, _ = hb.get_derivatives(self.smoothed_signal)

        # Update cross hairs
        self.switch_signal(None)

        # Plot ECG, Phono and Seismo
        self.signal_line.set_data(range(len(self.signal)), self.signal_amp_slider.val * self.signal)
        self.smooth_signal_line.set_data(range(len(self.signal)), self.signal_amp_slider.val * self.smoothed_signal)
        self.first_line.set_data(range(len(self.signal)), (self.first_amp_slider.val * 5*self.first) + self.first_height_slider.val + 1)
       
        self.ax.set_xlim(0, len(self.signal))

        # T Peak
        self.T_point.set_offsets((self.peaks.T.data[self.index] - self.peaks.P.data[self.index], self.signal_amp_slider.val * self.smoothed_signal[self.peaks.T.data[self.index] - self.peaks.P.data[self.index]]))
        self.T_text.set_position((self.peaks.T.data[self.index] - self.peaks.P.data[self.index], self.signal_amp_slider.val * self.smoothed_signal[self.peaks.T.data[self.index] - self.peaks.P.data[self.index]] + 0.2))

        # ST Start Peak
        self.ST_start_point.set_offsets((self.peaks.ST_start.data[self.index] - self.peaks.P.data[self.index], self.signal_amp_slider.val * self.smoothed_signal[self.peaks.ST_start.data[self.index] - self.peaks.P.data[self.index]]))
        self.ST_start_text.set_position((self.peaks.ST_start.data[self.index] - self.peaks.P.data[self.index], self.signal_amp_slider.val * self.smoothed_signal[self.peaks.ST_start.data[self.index] - self.peaks.P.data[self.index]] + 0.2))

        # T''max Peak
        self.dT_point.set_offsets((self.peaks.dT.data[self.index] - self.peaks.P.data[self.index], self.signal_amp_slider.val * self.smoothed_signal[self.peaks.dT.data[self.index] - self.peaks.P.data[self.index]]))
        self.dT_text.set_position((self.peaks.dT.data[self.index] - self.peaks.P.data[self.index], self.signal_amp_slider.val * self.smoothed_signal[self.peaks.dT.data[self.index] - self.peaks.P.data[self.index]] + 0.2))
        
        # # T''max Peak
        # self.ddT_point.set_offsets((self.peaks.ddT.data[self.index] - self.peaks.P.data[self.index], self.signal_amp_slider.val * self.smoothed_signal[self.peaks.ddT.data[self.index] - self.peaks.P.data[self.index]]))
        # self.ddT_text.set_position((self.peaks.ddT.data[self.index] - self.peaks.P.data[self.index], self.signal_amp_slider.val * self.smoothed_signal[self.peaks.ddT.data[self.index] - self.peaks.P.data[self.index]] + 0.2))

        self.fig.canvas.draw()
    def get_N_composite_signal_dataset(self,
                                       N,
                                       slide_step_size,
                                       display=False,
                                       dosage=None):
        # Get all heartbeats in composite
        composite_endpoints = self.get_N_composite_endpoints(
            N, slide_step_size)

        composites = []
        count = 0
        for start, end in composite_endpoints:
            count += 1
            # Find bounds for composite endpoints
            composite_start, composite_end = self.get_composite_bounds(
                start, end)

            # Clip all heartbeats to same length
            for i in range(N):
                # Define current interval
                interval = range(self.peaks.T.data[start + i],
                                 self.peaks.P.data[start + i + 2])

                # Clip signals and center them based off R peak
                heartbeat_time, heartbeat_signal, heartbeat_seis, heartbeat_phono = self.get_clipped_heartbeat_signals(
                    i, start, interval, composite_start, composite_end)

                # Cumulative sum
                composite_time = heartbeat_time if i == 0 else composite_time + heartbeat_time
                composite_signal = heartbeat_signal if i == 0 else composite_signal + heartbeat_signal
                composite_seis = heartbeat_seis if i == 0 else composite_seis + heartbeat_seis
                composite_phono = heartbeat_phono if i == 0 else composite_phono + heartbeat_phono

            # Divide by sample size
            composite_time /= N
            composite_signal /= N
            composite_seis /= N
            composite_phono /= N

            composites.append([
                composite_time, composite_signal, composite_seis,
                composite_phono
            ])

            if display:
                # Display
                fig, axes2d = plt.subplots(nrows=N, ncols=3)
                signal_lay_over_cell = fig.add_subplot(3, 3, 2)
                seis_lay_over_cell = fig.add_subplot(3, 3, 5)
                phono_lay_over_cell = fig.add_subplot(3, 3, 8)
                composite_cell = fig.add_subplot(1, 3, 3)

                if dosage is None:
                    plt.suptitle(
                        str(count) + " of " + str(len(composite_endpoints)) +
                        " INO Composites given " + str(N) +
                        " Heartbeats w/ Step Size of " + str(slide_step_size),
                        fontsize=20)
                else:
                    plt.suptitle(
                        str(count) + " of " + str(len(composite_endpoints)) +
                        " INO Composites for Dosage " + str(dosage) +
                        " given " + str(N) + " Heartbeats w/ Step Size of " +
                        str(slide_step_size),
                        fontsize=20)

                for i, row in enumerate(axes2d):
                    for j, cell in enumerate(row):
                        interval = range(self.peaks.T.data[start + i],
                                         self.peaks.P.data[start + i + 2])
                        cell.set_xticks([])
                        cell.set_yticks([])

                        if j == 0:
                            if i == 0:
                                cell.set_title("Individual Signals")
                            cell.plot(
                                self.peaks.time[interval],
                                hb.normalize(self.peaks.signal[interval]))
                            cell.plot(self.peaks.time[interval],
                                      hb.normalize(self.peaks.seis[interval]))
                            cell.plot(self.peaks.time[interval],
                                      hb.normalize(self.peaks.phono[interval]))
                            cell.set_ylabel(start + i)

                        elif j == 1:
                            signal_lay_over_cell.plot(
                                self.peaks.time[interval] -
                                self.peaks.time[self.peaks.R.data[start + 1 +
                                                                  i]],
                                hb.normalize(self.peaks.signal[interval] -
                                             self.peaks.signal[
                                                 self.peaks.R.data[start + 1 +
                                                                   i]]),
                                "--",
                                linewidth=0.5)
                            seis_lay_over_cell.plot(
                                self.peaks.time[interval] -
                                self.peaks.time[self.peaks.R.data[start + 1 +
                                                                  i]],
                                hb.normalize(self.peaks.seis[interval] -
                                             self.peaks.signal[
                                                 self.peaks.R.data[start + 1 +
                                                                   i]]),
                                "--",
                                linewidth=0.5)
                            phono_lay_over_cell.plot(
                                self.peaks.time[interval] -
                                self.peaks.time[self.peaks.R.data[start + 1 +
                                                                  i]],
                                hb.normalize(self.peaks.phono[interval] -
                                             self.peaks.signal[
                                                 self.peaks.R.data[start + 1 +
                                                                   i]]),
                                "--",
                                linewidth=0.5)

                            signal_lay_over_cell.set_xticks([])
                            signal_lay_over_cell.set_yticks([])

                            seis_lay_over_cell.set_xticks([])
                            seis_lay_over_cell.set_yticks([])

                            phono_lay_over_cell.set_xticks([])
                            phono_lay_over_cell.set_yticks([])

                        else:
                            if i == 0:
                                signal_lay_over_cell.plot(
                                    composite_time,
                                    hb.normalize(composite_signal),
                                    'r',
                                    linewidth=2,
                                    label="Composite Signal")
                                signal_lay_over_cell.legend(loc='lower left')

                                seis_lay_over_cell.plot(
                                    composite_time,
                                    hb.normalize(composite_seis),
                                    'r',
                                    linewidth=2,
                                    label="Composite Seis")
                                seis_lay_over_cell.legend(loc='lower left')

                                phono_lay_over_cell.plot(
                                    composite_time,
                                    hb.normalize(composite_phono),
                                    'r',
                                    linewidth=2,
                                    label="Composite Phono")
                                phono_lay_over_cell.legend(loc='lower left')

                                composite_cell.plot(composite_signal,
                                                    'r',
                                                    label="EKG")
                                composite_cell.plot(composite_seis,
                                                    'b',
                                                    label="Seis",
                                                    linewidth=0.5)
                                composite_cell.plot(composite_phono,
                                                    'g',
                                                    label="Phono",
                                                    linewidth=0.5)
                                composite_cell.legend(loc='lower left')
                                composite_cell.set_xticks([])
                                composite_cell.set_yticks([])
                                composite_cell.set_title("Composite")
                                signal_lay_over_cell.set_title("Superimposed")

                # Maximize Frame
                mng = plt.get_current_fig_manager()
                mng.full_screen_toggle()

                plt.show()

        self.composites = composites
        return composites
Exemple #4
0
    def plot_signals(self):
        # Create figure
        self.fig, self.ax = plt.subplots()
        self.signal = hb.normalize(self.peaks.signal[range(self.peaks.P.data[self.index], self.peaks.T.data[self.index + 1])])

        # Determine what cutoff freq to use
        self.cutoff_freq = 15 if np.mean(np.diff(self.peaks.R.data)) > 2500 else 10

        # Pass through a Low pass
        self.smoothed_signal = hb.lowpass_filter(signal = self.signal,
                                            cutoff_freq = self.cutoff_freq)

        # Calculate first derivative
        self.first, _ = hb.get_derivatives(self.smoothed_signal)

        # Plot ECG, Phono and Seismo
        self.signal_line, = self.ax.plot(range(len(self.signal)), self.signal, linewidth = 0.75, c = "r", label = "ECG")

        self.smooth_signal_line, = self.ax.plot(range(len(self.signal)), self.smoothed_signal, linewidth = 1, c = "b", label = "Low Pass ECG")

        self.first_line, = self.ax.plot(range(len(self.signal)), 1 + 5*self.first,
                                        '--', linewidth = 0.5, c = 'k', label = "ECG 1st Derv.")

        self.ax.set_xlim(0, len(self.signal))

        sig_min = min(self.signal)
        sig_max = max(self.signal)

        self.ax.set_ylim(sig_min - 0.2*(sig_max - sig_min), sig_max + 0.2*(sig_max - sig_min))
        plt.legend(loc='upper right')

        # T Peak
        self.T_point = self.ax.scatter(self.peaks.T.data[self.index] - self.peaks.P.data[self.index], self.smoothed_signal[self.peaks.T.data[self.index] - self.peaks.P.data[self.index]], c = '#9467bd')
        self.T_text  = self.ax.text(self.peaks.T.data[self.index] - self.peaks.P.data[self.index], self.smoothed_signal[self.peaks.T.data[self.index] - self.peaks.P.data[self.index]] + 0.2, "T", fontsize=9, horizontalalignment = 'center')

         # ST Start Peak
        self.ST_start_point = self.ax.scatter(self.peaks.ST_start.data[self.index] - self.peaks.P.data[self.index], self.smoothed_signal[self.peaks.ST_start.data[self.index] - self.peaks.P.data[self.index]], c = 'y')
        self.ST_start_text  = self.ax.text(self.peaks.ST_start.data[self.index] - self.peaks.P.data[self.index], self.smoothed_signal[self.peaks.ST_start.data[self.index] - self.peaks.P.data[self.index]] + 0.2, "ST Start", fontsize=9, horizontalalignment = 'center')

        # T'max Peak
        self.dT_point = self.ax.scatter(self.peaks.dT.data[self.index] - self.peaks.P.data[self.index], self.smoothed_signal[self.peaks.dT.data[self.index] - self.peaks.P.data[self.index]], c = '#2ca02c')
        self.dT_text  = self.ax.text(self.peaks.dT.data[self.index] - self.peaks.P.data[self.index], self.smoothed_signal[self.peaks.dT.data[self.index] - self.peaks.P.data[self.index]] + 0.2, "T'max", fontsize=9, horizontalalignment = 'center')

        # # T''max Peak
        # self.ddT_point = self.ax.scatter(self.peaks.ddT.data[self.index] - self.peaks.P.data[self.index], self.smoothed_signal[self.peaks.ddT.data[self.index] - self.peaks.P.data[self.index]], c = '#2ca02c')
        # self.ddT_text  = self.ax.text(self.peaks.ddT.data[self.index] - self.peaks.P.data[self.index], self.smoothed_signal[self.peaks.ddT.data[self.index] - self.peaks.P.data[self.index]] + 0.2, "T''max", fontsize=9, horizontalalignment = 'center')

        # Initalize axes and data points
        self.x = range(len(self.signal))
        self.y = self.smoothed_signal

        # Cross hairs
        self.lx = self.ax.axhline(color='k', linewidth=0.2)  # the horiz line
        self.ly = self.ax.axvline(color='k', linewidth=0.2)  # the vert line

        # Add data
        left_shift = 0.45
        start = 0.96
        space = 0.04
        self.ax.text(0.01, start, transform = self.ax.transAxes,
                    s = "Folder: " + self.folder_name, fontsize=12, horizontalalignment = 'left')
        self.ax.text(0.01, start - space, transform = self.ax.transAxes,
                    s = "Dosage: " + str(self.dosage), fontsize=12, horizontalalignment = 'left')
        self.i_text = self.ax.text(0.60 - left_shift, 1.1 - space, transform = self.ax.transAxes,
                                    s = "Heartbeat: " + str(self.index + 1) + "/" + str(len(self.peaks.R.data) - 1), fontsize=12, horizontalalignment = 'left')

        # Add index buttons
        ax_prev = plt.axes([0.575 - left_shift, 0.9, 0.1, 0.075])
        self.bprev = Button(ax_prev, 'Previous')
        self.bprev.on_clicked(self.prev)
        
        ax_next = plt.axes([0.8 - left_shift, 0.9, 0.1, 0.075])
        self.b_next = Button(ax_next, 'Next')
        self.b_next.on_clicked(self.next)

        self.fig.canvas.mpl_connect('motion_notify_event', self.mouse_move)

        self.fig.canvas.mpl_connect('button_press_event', self.on_click)
        self.fig.canvas.mpl_connect('button_release_event', self.off_click)

        # Add Sliders
        start = 0.91
        slider_width = 0.0075
        slider_height = 0.47

        self.cutoff_amp_slider = Slider(plt.axes([0.05, 0.15, 2*slider_width, slider_height]),
                                                label = "Cutoff (Hz)",
                                                valmin = 1,
                                                valmax = 50, 
                                                valinit = self.cutoff_freq,
                                                orientation = 'vertical',
                                                valfmt='%0.0f')
        self.cutoff_amp_slider.label.set_size(8)
        self.cutoff_amp_slider.on_changed(self.switch_signal)

        self.signal_amp_slider = Slider(plt.axes([start, 0.15, slider_width, slider_height]),
                                                label = "ECG\n\nA",
                                                valmin = 0.01,
                                                valmax = 10, 
                                                valinit = 1,
                                                orientation = 'vertical')
        self.signal_amp_slider.label.set_size(8)
        self.signal_amp_slider.on_changed(self.switch_signal)
        self.signal_amp_slider.valtext.set_visible(False)

        self.first_height_slider = Slider(plt.axes([start + 2*slider_width, 0.15, slider_width, slider_height]),
                                                    label = "   1st\n    Derv.\nH",
                                                    valmin = 1.5 * min(self.signal),
                                                    valmax = 1.5 * max(self.signal), 
                                                    valinit = 0,
                                                    orientation = 'vertical')
        self.first_height_slider.label.set_size(8)
        self.first_height_slider.on_changed(self.switch_signal)
        self.first_height_slider.valtext.set_visible(False)

        self.first_amp_slider = Slider(plt.axes([start + 3*slider_width, 0.15, slider_width, slider_height]),
                                        label = "\nA",
                                        valmin = 0.01,
                                        valmax = 10, 
                                        valinit = 1,
                                        orientation = 'vertical')
        self.first_amp_slider.label.set_size(8)
        self.first_amp_slider.on_changed(self.switch_signal)
        self.first_amp_slider.valtext.set_visible(False)

        # Maximize frame
        mng = plt.get_current_fig_manager()
        mng.full_screen_toggle()

        plt.show()