I was writing a code that Ploting variable input into a Bar Chart. the idea is: on each click, the code reads its input and refresh the ploted Bar chart to a new one, like the values increases on each click. here is the output:
enter image description here
After the second click (which is the supposed the second test), the canvas fiure doesn't refresh, but it adds another figure below.
enter image description here
How can keep display all the results in the same figure, which mean refreshing the same figure each time I click. I tried the creat a refresh function ,and I used delete(), clear()... and nothing is work properly (or may be I didn't use them right).
import time
import PySimpleGUI as sg
import pandas as pd
import tkinter as tk
from matplotlib.ticker import NullFormatter
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from tkinter import *
import matplotlib
import csv
from protoHODReader import main
from result import TestResult
matplotlib.use('TkAgg')
SW_ToT = 0 #my_variable
SW_OK = 0 #my_variable
SW_NOK = 0 #my_variable
test_result = TestResult.get_instance() #the input from another py code.
def plot_bar(plt_):#creating the plot
plt_.clf()
bar_values = (test_result.sw_total, test_result.sw_ok, test_result.sw_nok)
ind = np.arange(len(bar_values))
width = 0.4
p1 = plt_.bar(ind, bar_values, width)
plt_.ylabel('Quantity')
plt_.title('Test Results')
plt_.xticks(ind, ('Number Total of SW', 'SW oK', 'SW NOK'))
plt_.yticks(np.arange(0, 81, 10))
plt_.legend((p1[0],), ('Data Group 1',))
plt_.gcf()
def draw_figure(canvas, figure):#creating the 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 refresh(plt_, window_):#my attempt_to_refresh
plot_bar(plt_)
fig_ = plt_.gcf()
figure_x_, figure_y_, figure_w_, figure_h_ = fig_.bbox.bounds
fig_photo_ = draw_figure(window_['-CANVAS-'].TKCanvas, fig_)
canvas_bar = fig_photo_
#fig = matplotlib.figure.Figure(figsize=(5, 4))
plot_bar(plt)
sg.theme('DarkAmber')
fig = plt.gcf()
figure_x, figure_y, figure_w, figure_h = fig.bbox.bounds
layout = [[sg.Text('test', font='Any 18')],
[sg.Text('Please Scan the SW ID', size=(20, 1)), sg.InputText(key='PN'), sg.Button("LOAD")],
[sg.Canvas(size=(figure_w, figure_h), key='-CANVAS-')],
[sg.Button("Protoreader", size=(12, 3)), sg.Button("Print QR", size=(6, 3)), sg.Push(),
sg.Exit(size=(6, 3))]]
window = sg.Window('Local Application', layout, force_toplevel=True, finalize=True)
#fig_photo = draw_figure(window['-CANVAS-'].TKCanvas, fig)
event, values = window.read()
while True:
event, values = window.read()
if event == 'Exit' or event == sg.WIN_CLOSED:
break
# if event == 'LOAD':
if event == 'Protoreader':
exec(open('protoreader.py').read())
print(test_result.sw_nok)
print(test_result.sw_ok)
test_result.sw_total = test_result.sw_nok + test_result.sw_ok
print(test_result.`enter code here`sw_total)
refresh(plt, window)
test_result.saveAsCsv()
window.close()
Related
I am trying to make a simple interactive plot, where a value of single variable can be changed by the slider. I already have non-interactive code which is working, where I use pandas DataFrame. I am using PySimpleGUI, to which I am completely new. I have managed to get a window with the slider, but no plot which changes. Where do I do an error in my code?
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import copy as copy
import PySimpleGUI as sg
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
V_A=5
dfN_A=np.array([[-1, 1], [0, 3], [1, -1]])
dfN=copy.deepcopy(dfN_A)
dfN[:,-1]=dfN_A[:,-1]*V_A
DC = pd.DataFrame(dfN,
columns=['X','value'])
_VARS = {'window': False,
'fig_agg': False,
'pltFig': False,
'V_A': 5}
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
AppFont = 'Any 16'
SliderFont = 'Any 14'
sg.theme('black')
layout = [[sg.Canvas(key='figCanvas', background_color='#FDF6E3')],
# pad ((left, right), (top, bottom))
[sg.Text(text="V_A :",
font=SliderFont,
background_color='#FDF6E3',
pad=((0, 0), (10, 0)),
text_color='Black'),
sg.Slider(range=(-10,10), size=(60, 10),
orientation='h', key='-SLIDERV_A-')],
[sg.Button('Exit', font=AppFont, pad=((540, 0), (0, 0)))]]
_VARS['window'] = sg.Window('Simple GUI', layout, finalize=True,resizable=True, element_justification='center', font='Helvetica 18')
def drawChart():
_VARS['pltFig'] = plt.figure()
fig = plt.gcf()
DC.plot(y='value',x='X')
_VARS['fig_agg'] = draw_figure(
_VARS['window']['figCanvas'].TKCanvas, _VARS['pltFig'])
def updateChart():
_VARS['fig_agg'].get_tk_widget().forget()
plt.cla()
plt.clf()
_VARS['fig_agg'] = draw_figure(
_VARS['window']['figCanvas'].TKCanvas, _VARS['pltFig'])
def updateDataV_A(val):
_VARS['V_A'] = val
updateChart()
drawChart()
while True:
event, values = _VARS['window'].read(timeout=2000)
if event == sg.WIN_CLOSED or event == 'Exit':
break
elif event == '-SliderV_A-':
updateDataV_A(int(values['-SliderV_A-']))
_VARS['window'].close()
There're some issues in your code. Try not to say much about those issues, for easily, so a different code here for you.
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import PySimpleGUI as sg
# 1. Define the class as the interface between matplotlib and PySimpleGUI
class Canvas(FigureCanvasTkAgg):
"""
Create a canvas for matplotlib pyplot under tkinter/PySimpleGUI canvas
"""
def __init__(self, figure=None, master=None):
super().__init__(figure=figure, master=master)
self.canvas = self.get_tk_widget()
self.canvas.pack(side='top', fill='both', expand=1)
# 2. Define a function to draw the figure
def plot_figure(var):
ax.cla()
ax.plot(x0, y0*var)
canvas.draw() # Rendor figure into canvas
# 3. Initial Values
var = 5
x0, y0 = np.array([-1, 0, 1]), np.array([1, 3, -1])
# 4. create PySimpleGUI window
sg.theme('DarkBlue3')
layout = [
[sg.Canvas(size=(640, 480), key='Canvas')],
[sg.Text(text="Var"),
sg.Slider(range=(-10, 10), default_value=var, size=(10, 20), expand_x=True, enable_events=True, orientation='h', key='Slider')],
[sg.Push(), sg.Button('Exit'), sg.Push()],
]
window = sg.Window('Simple GUI', layout, finalize=True, resizable=True)
# 5. Create a matplotlib canvas under sg.Canvas or sg.Graph
fig = Figure()
ax = fig.add_subplot()
canvas = Canvas(fig, window['Canvas'].Widget)
# 6. initial for figure
plot_figure(var)
# 7. PySimpleGUI event loop
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
break
elif event == 'Slider':
var = values[event]
plot_figure(var)
# 8. Close window to exit
window.close()
I'm new in PySimpleGui and I want to plot a function which takes a variable in a slider. My problem is that when I update the value of the variable through the slider, the plot window becomes bigger each time. Any solution for that?
Here is my minimal working code:
import numpy as np
import matplotlib.pyplot as plt
import PySimpleGUI as sg
import math
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg,\
NavigationToolbar2Tk
def fun(nu):
x=np.arange(1,10,0.1)
plt.plot(x,nu*x)
return plt.gcf()
sg.theme('SandyBeach')
layout = [
[sg.Text('nu_min', size =(15, 1)), sg.InputText(0.2,key='-nu_min-')],
[sg.Text('nu_max', size =(15, 1)), sg.InputText(1,key='-nu_max-')],
[sg.Text('nu_step', size =(15, 1)), sg.InputText(0.1,key='-nu_step-')],
[sg.Submit('Run'), sg.Cancel()]
]
window = sg.Window('Simple data entry window', layout)
event, values = window.read()
window.close()
nu_min=float(values['-nu_min-'])
nu_max=float(values['-nu_max-'])
nu_step=float(values['-nu_step-'])
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 delete_figure_agg(figure_agg):
figure_agg.get_tk_widget().forget()
plt.close('all')
figure_w, figure_h = 400, 400
layout = [[sg.Text('Graph Element Combined with Math!', justification='center', relief=sg.RELIEF_SUNKEN, expand_x=True, font='Courier 18')],
[sg.Button('Plot'), sg.Cancel(), sg.Button('Popup')],
[sg.Canvas(size=(figure_w, figure_h), key='-CANVAS-')],
[sg.Text('nu', font='Courier 14'), sg.Slider((nu_min,nu_max),default_value=nu_min,resolution=nu_step, orientation='h', enable_events=True, key='-slider_nu-', expand_x=True)]]
window = sg.Window('', layout, finalize=True)
figure_agg = None
while True:
event, values = window.read()
if figure_agg:
# ** IMPORTANT ** Clean up previous drawing before drawing again
delete_figure_agg(figure_agg)
fig=fun(values['-slider_nu-'])
figure_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig)
window.close()
I ran your code, and see that your Y values shrink and grow as the slider is changed. Is this what you mean when you say, "the plot window becomes bigger..."
If so, try setting the Xlim and Ylim values to limit your plot values. When I inserted this into your code, the Y values are fixed at 10, and the plot updates as I move the slider.
def fun(nu):
x=np.arange(1,10,0.1)
plt.xlim(10)
plt.ylim(10)
plt.plot(x,nu*x)
return plt.gcf()
I wanted to give my little program a nice GUI with PySimpleGui when I ran into the problem that after the PySimpleGui window was closed the show() function from matplotlib blocked, even though the window of the figure is closed.
Here is an example code which doesn't determinate:
import PySimpleGUI as sg
import matplotlib.pyplot as plt
sg.theme('DarkAmber')
layout = [ [sg.Text('Some text on Row 1')],
[sg.Text('Enter something on Row 2'), sg.InputText()],
[sg.Button('Ok'), sg.Button('Cancel')] ]
window = sg.Window('Window Title', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Cancel': # if user closes window or clicks cancel
break
print('You entered ', values[0])
window.close()
plt.plot([1,2,3,4,5,6])
plt.show()
Yes, it also work on my platform.
WIN10, Python 3.9.5, PySimpleGUI 4.40.0.4, tkinter 8.6.9, Matplotlib 3.4.2
Following code show how I embed Matplotlib into PySimpleGUI.
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("Sensor Data")
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')
Firsttab = [[sg.Graph((640, 480), (0, 0), (640, 480),key='Graph1')]]
Secondtab = [[sg.Graph((640, 480), (0, 0), (640, 480),key='Graph2')]]
tab_group_layout = [
[sg.Tab('test', Firsttab,font='Courier 15', key='FirstTAB')],
[sg.Tab('test2', Secondtab,font='Courier 15', key='SecondTAB')],
]
column_layout= [[sg.TabGroup(tab_group_layout, enable_events=True,key='TABGROUP')]]
# PySimplGUI window
layout = [[sg.Column(column_layout, visible = True, key='GRAPHPANEL')],
[sg.Button(button_text = 'Graph', key='Start')]]
window = sg.Window('Matplotlib', layout, finalize=True)
# Set Button to repeat
window['Start'].Widget.configure(repeatdelay=50, repeatinterval=50)
# 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 = 0 # theta for fig2
index = 1 # Current Tab
plot_figure(1, theta1)
plot_figure(2, theta2)
flag1, flag2 = False, False
while True:
event, values = window.read(timeout=100)
if event == sg.WINDOW_CLOSED:
break
elif event == sg.TIMEOUT_KEY:
if index == 1 and flag1:
theta1 = (theta1 + 10) % 360
plot_figure(index, theta1)
elif index == 2 and flag2:
theta2 = (theta2 + 10) % 260
plot_figure(index, theta2)
elif event == 'Start':
print('Start', index)
if index == 1:
flag1 = not flag1
elif index == 2:
flag2 = not flag2
print(flag1, flag2)
elif event == 'TABGROUP':
index = 1 if values[event].startswith('First') else 2
window.close()
Your code works fine on my machine. After pressing cancel on the GUI, the plot shows:
I'm new to coding and i'm trying to create a Tkinter window using Matplotlib classes that allows me to manipulate a line graph depicting the share prices for 4 companies over two years in a separate window, this is the code I've written:
from tkinter import *
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg,NavigationToolbar2Tk)
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure
import pandas as pd
root = Tk ()
data = pd.read_csv('C:\\Users\\Admin\\Desktop\\shares.csv')
df = data.iloc[:,:5]
print(df)
print()
fig = Figure( figsize = (20,5) , dpi = 100 )
ax1 = fig.add_subplot()
df.plot('Date',figsize = (20,5), ax = ax1)
canvas = FigureCanvasTkAgg ( fig , root )
canvas.draw()
canvas.get_tk_widget().pack(side = TOP, fill = BOTH, expand = 1)
df.plot(kind = 'bar' , ax = ax1)
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side = TOP, fill = BOTH, expand = 1)
def on_key(event):
print('You Pressed {}'.format(event.key))
key_press_handler(event, canvas, toolbar)
canvas.mpl_connect('key_press_event' , on_key)
def Quit():
root.quit()
root.destroy()
return
button = Button(root, text = 'QUIT' , command = Quit )
button.pack ()
root.mainloop()
This is the output I have obtained:
Whereas this is the desired graph:
I would appreciate any input as to how I can fix this, and make my code better.
Thanks :)
Try this it may work
df.plot(kind = 'line' , ax = ax1)
You are ploting bar and your expected output is a line graph
how do i delete data from a figure when it is used in tktinter via FigureCanvasTkAgg?
I have tried to clear the figure with cla, clf and to delete the canvas with .delete, .clear.
My code: (If you have any advise how i can improve my code let me now. This is my first project in coding)
import tkinter as tk
from tkinter import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
#createplot
fig_CDF = Figure(figsize = (6, 5), facecolor = "white")
axis_CDF = fig_CDF.add_subplot(111)
canvas_CDF = FigureCanvasTkAgg(fig_CDF, master = window_main)
canvas_CDF._tkcanvas.pack(side = tk.TOP, fill = tk.BOTH, expand = 1)
canvas_CDF.get_tk_widget().place(x=400,y=50)
#plotdata
axis_CDF.plot(datax, datay, label = "data",marker=".", linestyle = "")
canvas_CDF.draw()
Thanks for your help!
In this code I added three buttons which shows three methods - all of them need canvas_CDF.draw() to redraw element in window.
first replaces data in plot and it removes points from chart but it still show axes.
second clears axis - so it remove data and set axis to 0..1
third clears figure - it removes even axis.
First version needs
plot = axis_CDF.plot(...)
to have access to data.
I use random only to create some data.
import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import random
# --- functions ---
def replace_data():
datax = []
datay = []
#datax = range(10)
#datay = [x/10 for x in random.sample(range(10), 10)]
plot[0].set_data(datax, datay)
canvas_CDF.draw()
def clear_axis():
#axis_CDF.clear()
axis_CDF.cla()
canvas_CDF.draw()
def clear_figure():
fig_CDF.clear()
#fig_CDF.clf()
canvas_CDF.draw()
# --- main ---
window_main = tk.Tk()
datax = range(10)
datay = [x/10 for x in random.sample(range(10), 10)]
# create plot
fig_CDF = Figure(figsize=(6, 5), facecolor="white")
axis_CDF = fig_CDF.add_subplot(111)
canvas_CDF = FigureCanvasTkAgg(fig_CDF, master=window_main)
canvas_CDF._tkcanvas.pack(side='top', fill='both', expand=True)
canvas_CDF.get_tk_widget().pack()
# plot data
plot = axis_CDF.plot(datax, datay, label="data", marker=".", linestyle="")
canvas_CDF.draw()
# buttons
b = tk.Button(window_main, text='Replace data', command=replace_data)
b.pack()
b = tk.Button(window_main, text='Clear axis', command=clear_axis)
b.pack()
b = tk.Button(window_main, text='Clear figure', command=clear_figure)
b.pack()
window_main.mainloop()