Home > Blockchain >  How to create separate plots in different windows that don't interfere with each other?
How to create separate plots in different windows that don't interfere with each other?

Time:10-20

This my first time using gui in python so sorry if my code is not pretty.

What I am doing is showing three signals of human body generated by the neurokit2 library (ecg, emg,rsp). I succeeded in showing the signal as it progress with time using matplotlib animation (it has a lot of flaws but I think I can fix them if I searched long enough). What I am truly struggling with for days now is that I need to show a spectrogram of the three signals (not animated though just a static graph).

But each time I try to show the spectrogram, it interferes with the plot of the animation producing garbage graphs and freezes the program.

So how can I totally separate these two functions from each other and produce different windows for each function?

import PySimpleGUI as sg
import matplotlib.pyplot as plt
import neurokit2 as nk
from matplotlib.animation import FuncAnimation
from matplotlib.backends._backend_tk import Toolbar, NavigationToolbar2Tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


class Toolbar(NavigationToolbar2Tk):
    # only display the buttons we need
    toolitems = [t for t in NavigationToolbar2Tk.toolitems if
                 t[0] in ('Home', 'Pan', 'Zoom')]

    # t[0] in ('Home', 'Pan', 'Zoom','Save')]

    def _init_(self, *args, **kwargs):
        super(Toolbar, self)._init_(*args, **kwargs)


def draw_figure(canvas, figure, canvas_toolbar=None):
    figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
    figure_canvas_agg.draw_idle()
    if canvas_toolbar is not None:
        toolbar = Toolbar(figure_canvas_agg, canvas_toolbar)
        toolbar.update()
    figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
    return figure_canvas_agg


def main():
    # define the form layout
    layout = [[sg.Text('Signal Viewer', size=(40, 1), justification='center', font='Helvetica 20')],
              [sg.Canvas(key='controls_cv', pad=((280, 0), 3))],
              [sg.Canvas(size=(50, 36), key='-CANVAS-'), sg.Canvas(size=(50, 36), key='-CANVAS0-')],
              [sg.Button('ECG', pad=((250, 0), 3)), sg.Button('EMG'), sg.Button('RSP'), sg.Button('Spec')],
              [sg.Button('Exit', size=(5, 1), pad=((280, 0), 3), font='Helvetica 14')]]

    # create the form and show it without the plot
    window = sg.Window('Signal Viewer', layout, finalize=True)

    canvas_elem = window['-CANVAS-']
    canvas2_e = window['-CANVAS0-']
    canvas = canvas_elem.TKCanvas
    canvas2 = canvas2_e.TKCanvas
    x, y = [], []
    fig, ax = plt.subplots()
    fig2, ax2 = plt.subplots()
    plt.grid(True)
    fig_agg = draw_figure(canvas, fig, window.FindElement('controls_cv').TKCanvas)
    fig_agg2 = draw_figure(canvas2, fig2)

    def wave2(ecg100):
        plt.specgram(ecg100, NFFT=64, Fs=256, noverlap=32)
        fig_agg2.draw_idle()

    def wave_form(ecg100):
        def update_time():
            t = 0
            t_max = len(ecg100)
            while t < t_max and t >= 0:
                t  = ani.direction
                yield t

        def animate(frame):
            st, end = frame / 2, frame   0.5
            x.append(ecg100[frame])
            plt.cla()
            plt.ylim([ecg100.min(), ecg100.max()])
            plt.plot(x)
            plt.grid()
            plt.tight_layout()
            ax.set_xlim(st, end)

        def on_press(event1):
            print(event1.key)
            if event1.key.isspace():
                if ani.running:
                    ani.event_source.stop()
                else:
                    ani.event_source.start()
                ani.running ^= True
            elif event1.key == 'left':
                ani.direction = -1
            elif event1.key == 'right':
                ani.direction =  1
            if event1.key in ['left', 'right']:
                t = ani.frame_seq.__next__()
                animate(t)

        fig.canvas.mpl_connect('key_press_event', on_press)
        ani = FuncAnimation(plt.gcf(), animate, frames=update_time(), interval=5, repeat=True)
        ani.running = True
        ani.direction =  1
        fig_agg.draw_idle()

    while True:
        event, values = window.read(timeout=10)
        if event in ('Exit', sg.WIN_CLOSED):
            exit(69)
        elif event in 'ECG':
            ecg100 = nk.ecg_simulate(duration=10, noise=0.01, heart_rate=100)
            wave_form(ecg100)
            wave2(ecg100)
        elif event in 'EMG':
            ecg100 = nk.emg_simulate(duration=10, sampling_rate=100, burst_number=4)
            wave_form(ecg100)
            wave2(ecg100)
        elif event in 'RSP':
            ecg100 = nk.rsp_simulate(duration=30, sampling_rate=50, noise=0.01)
            wave_form(ecg100)
            wave2(ecg100)
    window.close()


if __name__ == '__main__':
    main()

The funtion wave2 is the function that I want to implement for the signal to produce spectrogram in different plot when I press the 'spec' button

this is the gui now

CodePudding user response:

User code cannot run on my platform, so just example here. Of course, you can use sg.Canvas here.

import math

from matplotlib import use as use_agg
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import PySimpleGUI as sg

def pack_figure(graph, figure):
    canvas = FigureCanvasTkAgg(figure, graph.Widget)
    plot_widget = canvas.get_tk_widget()
    plot_widget.pack(side='top', fill='both', expand=1)
    return plot_widget

def plot_figure(index, theta):
    fig = plt.figure(index)         # Active an existing figure
    ax = plt.gca()                  # Get the current axes
    x = [degree for degree in range(1080)]
    y = [math.sin((degree theta)/180*math.pi) for degree in range(1080)]
    ax.cla()                        # Clear the current axes
    ax.set_title(f"Sensor Data {index}")
    ax.set_xlabel("X axis")
    ax.set_ylabel("Y axis")
    ax.set_xscale('log')
    ax.grid()
    plt.plot(x, y)                  # Plot y versus x as lines and/or markers
    fig.canvas.draw()               # Rendor figure into canvas

# Use Tkinter Agg
use_agg('TkAgg')

layout = [[sg.Graph((640, 480), (0, 0), (640, 480), key='Graph1'), sg.Graph((640, 480), (0, 0), (640, 480), key='Graph2')]]
window = sg.Window('Matplotlib', layout, finalize=True)


# Initial
graph1 = window['Graph1']
graph2 = window['Graph2']
plt.ioff()                          # Turn the interactive mode off
fig1 = plt.figure(1)                # Create a new figure
ax1 = plt.subplot(111)              # Add a subplot to the current figure.
fig2 = plt.figure(2)                # Create a new figure
ax2 = plt.subplot(111)              # Add a subplot to the current figure.
pack_figure(graph1, fig1)           # Pack figure under graph
pack_figure(graph2, fig2)
theta1 = 0                          # theta for fig1
theta2 = 90                         # theta for fig2
plot_figure(1, theta1)
plot_figure(2, theta2)

while True:

    event, values = window.read(timeout=10)

    if event == sg.WINDOW_CLOSED:
        break
    elif event == sg.TIMEOUT_EVENT:
        theta1 = (theta1   40) % 360
        plot_figure(1, theta1)
        theta2 = (theta2   40) % 260
        plot_figure(2, theta2)

window.close()

enter image description here

  • Related