From 6f02fb4a54950c050134cc1e97cd1fb8e0a75c70 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 19 Sep 2019 11:57:11 -0400 Subject: [PATCH 1/2] Updated, removed the force_toplevel in Window as it doesn't seem to be needed anymore. --- DemoPrograms/Demo_Matplotlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DemoPrograms/Demo_Matplotlib.py b/DemoPrograms/Demo_Matplotlib.py index 73363a98..8c503f66 100644 --- a/DemoPrograms/Demo_Matplotlib.py +++ b/DemoPrograms/Demo_Matplotlib.py @@ -17,7 +17,7 @@ Basic steps are: * Display form (BLOCKING) Based on information from: https://matplotlib.org/3.1.0/gallery/user_interfaces/embedding_in_tk_sgskip.html - (Thank you dirck) + (Thank you Em-Bo & dirck) """ @@ -93,7 +93,7 @@ layout = [[sg.Text('Plot test', font='Any 18')], [sg.OK(pad=((figure_w / 2, 0), 3), size=(4, 2))]] # create the form and show it without the plot -window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI', layout, force_toplevel=True, finalize=True) +window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI', layout, finalize=True) # add the plot to the window fig_photo = draw_figure(window['canvas'].TKCanvas, fig) From 3b24d8921e264fe553a1ed4d8d31a3c15d85b0e0 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 19 Sep 2019 13:32:25 -0400 Subject: [PATCH 2/2] Update of ALL Matplotlib demos so they run on 3.1. Brought up to date too. --- DemoPrograms/Demo_Matplotlib.py | 4 +- DemoPrograms/Demo_Matplotlib_Animated.py | 77 ++++++++--------- .../Demo_Matplotlib_Animated_Scatter.py | 76 +++++++---------- DemoPrograms/Demo_Matplotlib_Browser.py | 8 +- DemoPrograms/Demo_Matplotlib_Browser_Paned.py | 85 +++++++------------ 5 files changed, 102 insertions(+), 148 deletions(-) diff --git a/DemoPrograms/Demo_Matplotlib.py b/DemoPrograms/Demo_Matplotlib.py index 8c503f66..63164465 100644 --- a/DemoPrograms/Demo_Matplotlib.py +++ b/DemoPrograms/Demo_Matplotlib.py @@ -84,7 +84,7 @@ def draw_figure(canvas, figure, loc=(0, 0)): figure_canvas_agg = FigureCanvasTkAgg(figure, canvas) figure_canvas_agg.draw() figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1) - + return figure_canvas_agg #------------------------------- Beginning of GUI CODE ------------------------------- # define the window layout @@ -96,6 +96,6 @@ layout = [[sg.Text('Plot test', font='Any 18')], window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI', layout, finalize=True) # add the plot to the window -fig_photo = draw_figure(window['canvas'].TKCanvas, fig) +fig_canvas_agg = draw_figure(window['canvas'].TKCanvas, fig) event, values = window.read() diff --git a/DemoPrograms/Demo_Matplotlib_Animated.py b/DemoPrograms/Demo_Matplotlib_Animated.py index 6063a5ee..da28c03c 100644 --- a/DemoPrograms/Demo_Matplotlib_Animated.py +++ b/DemoPrograms/Demo_Matplotlib_Animated.py @@ -1,64 +1,55 @@ #!/usr/bin/env python -import sys -if sys.version_info[0] >= 3: - import PySimpleGUI as sg -else: - import PySimpleGUI27 as sg +import PySimpleGUI as sg from random import randint from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, FigureCanvasAgg from matplotlib.figure import Figure -import matplotlib.backends.tkagg as tkagg -import tkinter as tk +def draw_figure(canvas, figure, loc=(0, 0)): + figure_canvas_agg = FigureCanvasTkAgg(figure, canvas) + figure_canvas_agg.draw() + figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1) + return figure_canvas_agg def main(): - fig = Figure() + NUM_DATAPOINTS = 10000 + # define the form layout + layout = [[sg.Text('Animated Matplotlib', size=(40, 1), justification='center', font='Helvetica 20')], + [sg.Canvas(size=(640, 480), key='-CANVAS-')], + [sg.Text('Progress through the data')], + [sg.Slider(range=(0, NUM_DATAPOINTS), size=(60, 10), orientation='h', key='-SLIDER-')], + [sg.Text('Number of data points to display on screen')], + [sg.Slider(range=(10, 500), default_value=40, size=(40, 10), orientation='h', key='-SLIDER-DATAPOINTS-')], + [sg.Button('Exit', size=(10, 1), pad=((280, 0), 3), font='Helvetica 14')]] + + # create the form and show it without the plot + window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI', layout, finalize=True) + + canvas_elem = window.FindElement('-CANVAS-') + slider_elem = window.FindElement('-SLIDER-') + canvas = canvas_elem.TKCanvas + + # draw the initial plot in the window + fig = Figure() ax = fig.add_subplot(111) ax.set_xlabel("X axis") ax.set_ylabel("Y axis") ax.grid() + fig_agg = draw_figure(canvas, fig) + # make a bunch of random data points + dpts = [randint(0, 10) for x in range(NUM_DATAPOINTS)] - # define the form layout - layout = [[sg.Text('Animated Matplotlib', size=(40, 1), justification='center', font='Helvetica 20')], - [sg.Canvas(size=(640, 480), key='canvas')], - [sg.Slider(range=(0, 10000), size=(60, 10), orientation='h', key='slider')], - [sg.ReadButton('Exit', size=(10, 2), pad=((280, 0), 3), font='Helvetica 14')]] - - # create the form and show it without the plot - window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout).Finalize() - - canvas_elem = window.FindElement('canvas') - slider_elem = window.FindElement('slider') - graph = FigureCanvasTkAgg(fig, master=canvas_elem.TKCanvas) - canvas = canvas_elem.TKCanvas - - dpts = [randint(0, 10) for x in range(10000)] for i in range(len(dpts)): event, values = window.Read(timeout=10) if event in ('Exit', None): exit(69) - - slider_elem.Update(i) - ax.cla() - ax.grid() - DATA_POINTS_PER_SCREEN = 40 - ax.plot(range(DATA_POINTS_PER_SCREEN), dpts[i:i+DATA_POINTS_PER_SCREEN], color='purple') - graph.draw() - figure_x, figure_y, figure_w, figure_h = fig.bbox.bounds - figure_w, figure_h = int(figure_w), int(figure_h) - photo = tk.PhotoImage(master=canvas, width=figure_w, height=figure_h) - - canvas.create_image(640/2, 480/2, image=photo) - - figure_canvas_agg = FigureCanvasAgg(fig) - figure_canvas_agg.draw() - - # Unfortunately, there's no accessor for the pointer to the native renderer - tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2) - - # time.sleep(.1) + slider_elem.Update(i) # slider shows "progress" through the data points + ax.cla() # clear the subplot + ax.grid() # draw the grid + data_points = int(values['-SLIDER-DATAPOINTS-']) # draw this many data points (on next line) + ax.plot(range(data_points), dpts[i:i+data_points], color='purple') + fig_agg.draw() if __name__ == '__main__': diff --git a/DemoPrograms/Demo_Matplotlib_Animated_Scatter.py b/DemoPrograms/Demo_Matplotlib_Animated_Scatter.py index b57df505..21df8cdf 100644 --- a/DemoPrograms/Demo_Matplotlib_Animated_Scatter.py +++ b/DemoPrograms/Demo_Matplotlib_Animated_Scatter.py @@ -1,66 +1,50 @@ #!/usr/bin/env python -import sys -if sys.version_info[0] >= 3: - import PySimpleGUI as sg -else: - import PySimpleGUI27 as sg - -from random import randint import PySimpleGUI as sg -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, FigureCanvasAgg -from matplotlib.figure import Figure -import matplotlib.backends.tkagg as tkagg -import tkinter as tk + +import PySimpleGUI as sg +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg +import matplotlib.pyplot as plt +from numpy.random import rand + +def draw_figure(canvas, figure): + figure_canvas_agg = FigureCanvasTkAgg(figure, canvas) + figure_canvas_agg.draw() + 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('Animated Matplotlib', size=(40, 1), justification='center', font='Helvetica 20')], - [sg.Canvas(size=(640, 480), key='canvas')], - [sg.ReadButton('Exit', size=(10, 2), pad=((280, 0), 3), font='Helvetica 14')]] + [sg.Canvas(size=(640, 480), key='-CANVAS-')], + [sg.Button('Exit', size=(10, 2), pad=((280, 0), 3), font='Helvetica 14')]] # create the form and show it without the plot - window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI').Layout(layout).Finalize() + window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI', layout, finalize=True) - canvas_elem = window.FindElement('canvas') + canvas_elem = window.FindElement('-CANVAS-') canvas = canvas_elem.TKCanvas + # draw the intitial scatter plot + fig, ax = plt.subplots() + ax.grid(True) + fig_agg = draw_figure(canvas, fig) while True: event, values = window.Read(timeout=10) if event in ('Exit', None): exit(69) - def PyplotScatterWithLegend(): - import matplotlib.pyplot as plt - from numpy.random import rand - - fig, ax = plt.subplots() - for color in ['red', 'green', 'blue']: - n = 750 - x, y = rand(2, n) - scale = 200.0 * rand(n) - ax.scatter(x, y, c=color, s=scale, label=color, - alpha=0.3, edgecolors='none') - - ax.legend() - ax.grid(True) - return fig - - fig = PyplotScatterWithLegend() - - figure_x, figure_y, figure_w, figure_h = fig.bbox.bounds - figure_w, figure_h = int(figure_w), int(figure_h) - photo = tk.PhotoImage(master=canvas, width=figure_w, height=figure_h) - - canvas.create_image(640/2, 480/2, image=photo) - - figure_canvas_agg = FigureCanvasAgg(fig) - figure_canvas_agg.draw() - - # Unfortunately, there's no accessor for the pointer to the native renderer - tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2) - - # time.sleep(.1) + ax.cla() + ax.grid(True) + for color in ['red', 'green', 'blue']: + n = 750 + x, y = rand(2, n) + scale = 200.0 * rand(n) + ax.scatter(x, y, c=color, s=scale, label=color, alpha=0.3, edgecolors='none') + ax.legend() + fig_agg.draw() if __name__ == '__main__': diff --git a/DemoPrograms/Demo_Matplotlib_Browser.py b/DemoPrograms/Demo_Matplotlib_Browser.py index 10653f7a..a05242b0 100644 --- a/DemoPrograms/Demo_Matplotlib_Browser.py +++ b/DemoPrograms/Demo_Matplotlib_Browser.py @@ -27,8 +27,8 @@ def PyplotSimple(): import numpy as np import matplotlib.pyplot as plt - # evenly sampled time at 200ms intervals - t = np.arange(0., 5., 0.2) + # evenly sampled time .2 intervals + t = np.arange(0., 5., 0.2) # go from 0 to 5 using .2 intervals # red dashes, blue squares and green triangles plt.plot(t, t, 'r--', t, t ** 2, 'bs', t, t ** 3, 'g^') @@ -823,7 +823,7 @@ def AxesGrid(): # The magic function that makes it possible.... glues together tkinter and pyplot using Canvas Widget -def draw_figure(canvas, figure, loc=(0, 0)): +def draw_figure(canvas, figure): figure_canvas_agg = FigureCanvasTkAgg(figure, canvas) figure_canvas_agg.draw() figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1) @@ -851,7 +851,7 @@ sg.ChangeLookAndFeel('LightGreen') figure_w, figure_h = 650, 650 # define the form layout listbox_values = list(fig_dict) -col_listbox = [[sg.Listbox(values=listbox_values, change_submits=True, size=(28, len(listbox_values)), key='-LISTBOX-')], +col_listbox = [[sg.Listbox(values=listbox_values, enable_events=True, size=(28, len(listbox_values)), key='-LISTBOX-')], [sg.T(' ' * 12), sg.Exit(size=(5, 2))]] layout = [[sg.Text('Matplotlib Plot Test', font=('current 18'))], diff --git a/DemoPrograms/Demo_Matplotlib_Browser_Paned.py b/DemoPrograms/Demo_Matplotlib_Browser_Paned.py index a4b0c7b9..3a61374d 100644 --- a/DemoPrograms/Demo_Matplotlib_Browser_Paned.py +++ b/DemoPrograms/Demo_Matplotlib_Browser_Paned.py @@ -1,16 +1,12 @@ #!/usr/bin/env python -import sys -if sys.version_info[0] >= 3: - import PySimpleGUI as sg - import tkinter as Tk -else: - import PySimpleGUI27 as sg - import Tkinter as Tk +#!/usr/bin/env python +import PySimpleGUI as sg import matplotlib matplotlib.use('TkAgg') -from matplotlib.backends.backend_tkagg import FigureCanvasAgg -import matplotlib.backends.tkagg as tkagg import inspect +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg """ Demonstrates one way of embedding Matplotlib figures into a PySimpleGUI window. @@ -827,28 +823,15 @@ def AxesGrid(): return plt.gcf() # The magic function that makes it possible.... glues together tkinter and pyplot using Canvas Widget -def draw_figure(canvas, figure, loc=(0, 0)): - """ Draw a matplotlib figure onto a Tk canvas - - loc: location of top-left corner of figure on canvas in pixels. - - Inspired by matplotlib source: lib/matplotlib/backends/backend_tkagg.py - """ - figure_canvas_agg = FigureCanvasAgg(figure) +def draw_figure(canvas, figure): + figure_canvas_agg = FigureCanvasTkAgg(figure, canvas) figure_canvas_agg.draw() - figure_x, figure_y, figure_w, figure_h = figure.bbox.bounds - figure_w, figure_h = int(figure_w), int(figure_h) - photo = Tk.PhotoImage(master=canvas, width=figure_w, height=figure_h) + figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1) + return figure_canvas_agg - # Position: convert from top-left anchor to center anchor - canvas.create_image(loc[0] + figure_w/2, loc[1] + figure_h/2, image=photo) - - # Unfortunately, there's no accessor for the pointer to the native renderer - tkagg.blit(photo, figure_canvas_agg.get_renderer()._renderer, colormode=2) - - # Return a handle which contains a reference to the photo object - # which must be kept live or else the picture disappears - return photo +def delete_figure_agg(figure_agg): + figure_agg.get_tk_widget().forget() + plt.close('all') # -------------------------------- GUI Starts Here -------------------------------# @@ -871,40 +854,36 @@ fig_dict = {'Pyplot Simple':PyplotSimple, 'Pyplot Formatstr':PyplotFormatstr,'Py sg.ChangeLookAndFeel('LightGreen') figure_w, figure_h = 650, 650 # define the form layout -listbox_values = [key for key in fig_dict.keys()] -col_listbox = [[sg.Listbox(values=listbox_values, change_submits=True, size=(28, len(listbox_values)), key='func')], +listbox_values = list(fig_dict) +col_listbox = [[sg.Listbox(values=listbox_values, change_submits=True, size=(28, len(listbox_values)), key='-LISTBOX-')], [sg.T(' ' * 12), sg.Exit(size=(5, 2))]] -col_multiline = sg.Column([[sg.Multiline(size=(70, 35), key='multiline')]]) -col_canvas = sg.Column([[ sg.Canvas(size=(figure_w, figure_h), key='canvas')]]) +col_multiline = sg.Column([[sg.Multiline(size=(70, 35), key='-MULTILINE-')]]) +col_canvas = sg.Column([[ sg.Canvas(size=(figure_w, figure_h), key='-CANVAS-')]]) +col_instructions = sg.Column([[sg.Pane([col_canvas, col_multiline], size=(800,600))], + [sg.Text('Grab square above and slide upwards to view source code for graph')]]) -layout = [[sg.Text('Matplotlib Plot Test', font=('current 18'))], - [sg.Column(col_listbox), sg.Pane([col_canvas, col_multiline], size=(800,600))], - ] +layout = [[sg.Text('Matplotlib Plot Test', font=('ANY 18'))], + [sg.Column(col_listbox), col_instructions],] # create the form and show it without the plot -window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI',resizable=True, grab_anywhere=False).Layout(layout) -window.Finalize() +window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI',layout, resizable=True, finalize=True) -canvas_elem = window.FindElement('canvas') -multiline_elem= window.FindElement('multiline') +canvas_elem = window.FindElement('-CANVAS-') +multiline_elem= window.FindElement('-MULTILINE-') +figure_agg = None while True: event, values = window.Read() - # print(event) - # show it all again and get buttons if event in (None, 'Exit'): break - try: - choice = values['func'][0] - func = fig_dict[choice] - except: - pass - - multiline_elem.Update(inspect.getsource(func)) - plt.clf() - fig = func() - fig_photo = draw_figure(canvas_elem.TKCanvas, fig) - + if figure_agg: + # ** IMPORTANT ** Clean up previous drawing before drawing again + delete_figure_agg(figure_agg) + choice = values['-LISTBOX-'][0] # get first listbox item chosen (returned as a list) + func = fig_dict[choice] # get function to call from the dictionary + window['-MULTILINE-'].Update(inspect.getsource(func)) # show source code to function in multiline + fig = func() # call function to get the figure + figure_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig) # draw the figure