from the following code, I could update the line by clicking the "replot" button. I have to use both set_data() and also plot a new plot, otherwise the old plot is still here.
However, I want the program automatically to update the curve inside of animate(), I use a 5 secs control to trigger replot() function, but it fails. if I do not use blit=True, just use blit=False, then everything is fine. Then my question is how to update the curve in animation triggered by condition, and also need to keep blit=True?
from multiprocessing import Process
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
##, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
import tkinter as tk
from tkinter import ttk
from tkinter import *
import matplotlib.pyplot as plt
import numpy as np
import time
#f = Figure(figsize=(6,6), dpi=100)
f = Figure(figsize=(6,6), dpi=100)
subplot_1 = f.add_subplot(211)
subplot_2 = f.add_subplot(212)
#subplot_1 = f.add_subplot(211)
#subplot_2 = f.add_subplot(212)
a_count = 0
b_count = 0
LARGE_FONT= ("Verdana", 12)
style.use("ggplot")
count_plot = 0
first_replot = 0
start_time = 0
a_t = [1,2,3,4,5]
a_T = np.ones(5)
def replot():
global a_t, count_plot,theory_line,a_T
a_T = np.ones(5)*2
#f.axes[0].clear
#theory_line[0].remove()
theory_line[0].set_data(a_t,a_T)
#theory_line.clear()
#theory_line = subplot_1.plot(a_t,a_T,'g-')
#subplot_1.draw
canvas.draw
def animate(i):
global a_count,b_count,first_replot
time1 = np.random.rand(2, 25)
data = np.random.rand(2, 25)*2
if (time.time() - start_time > 5) and (first_replot == 0):
replot()
first_replot = 1
a = subplot_1.scatter(time1,data,c='blue',s=2)
return a,
class home(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Graph ")
self.geometry("1000x1000")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
F=Graph
frame=Graph(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(Graph)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def get_frame(self, frame_class):
return self.frames[frame_class]
##
class Graph(tk.Frame):
def __init__(self, parent, controller):
global canvas
tk.Frame.__init__(self, parent)
label = tk.Label(self, text=" ", font=LARGE_FONT)
label.pack(pady=120,padx=10)
collectbtn=Button(self,text='collect',command=self.clickstart)
collectbtn.place(x=200,y=100)
collectbtn=Button(self,text='replot',command=self.clickreplot)
collectbtn.place(x=280,y=100)
canvas = FigureCanvasTkAgg(f, self)
## canvas.draw()
canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
def clickstart(self):
global theory_line,start_time
theory_line = subplot_1.plot(a_t,a_T,'c-')
#animate(0)
start_time = time.time()
aniplot_photon = animation.FuncAnimation(f, animate, blit=True,interval=100)
#aniplot_photon = animation.FuncAnimation(f, animate, interval=100)
canvas.draw()
def clickreplot(self):
replot()
canvas.draw()
app = home()
app.mainloop()
Not sure about the programming logic, but I think there maybe at least three issues.
start_time won't be reset if you don't click 'collect', so it won't replot every 5 seconds.
def clickstart(self):
....
start_time = time.time()
aniplot_photon = animation.FuncAnimation(f, animate, blit=True,interval=100)
....
first_replot initially set to 0, after 'collect' clicked and 5 seconds passed, then the value of first_replot will be always 1. It means no more replot in function 'animate'.
canvas.draw at last line of function 'replot', should be canvas.draw().
Related
I have created a tkinter GUI that when a button is pushed a tk.toplevel is created with an interactive animated chart inside. When I run it for the first time and push the button to create the tk.toplevel with the chart, it works well, but when I close the tk.toplevel and push the button to open a new tk.toplevel, another extra chart appears. Apart from that, If I close the program and I want to run it again I have to close the terminal because it freezes.
I have tried removing plt.ion() and doing plt.show() but none of these options solve the problem. Also, I have seen the use of multiprocessing, but I don't really understand it well and I don't know why is it needed.
Why does it happen? How can I solve this problem?
Here is the code that I have used:
import tkinter as tk
import matplotlib
import matplotlib.figure as mf
import matplotlib.pyplot as plt
import matplotlib.animation as ani
from matplotlib.animation import FuncAnimation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
container = tk.Frame(self)
container.pack()
frame = MAININTERFACE(parent=container, controller=self)
frame.grid(row=0, column=0, sticky="nsew")
def graph(self):
grafica1=GRAPHICATION(controller=self)
grafica1.Graph()
class MAININTERFACE(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.button=tk.Button(self, text='GRAPH', command=lambda: self.controller.graph())
self.button.pack(pady=20)
class GRAPHICATION(tk.Frame):
def __init__(self,controller):
tk.Frame.__init__(self)
self.controller=controller
self.x=[]
self.y=[]
def animation_frame(self, i):
if i==0.0:
self.time=0
self.energy=0
else:
self.time=self.time+1
self.energy=self.energy+1
self.x.append(self.time)
self.y.append(self.energy)
self.line.set_data(self.x,self.y)
self.ax.axis([0,10,0,10])
def Graph(self):
self.graphtoplevel=tk.Toplevel(self.controller)
self.graphtoplevel.title('Toplevel')
self.fig, self.ax = plt.subplots()
self.graph=FigureCanvasTkAgg(self.fig, self.graphtoplevel)
self.image=self.graph.get_tk_widget()
plt.ion()
self.line, = self.ax.plot(self.x,self.y)
self.image.grid(row=0, column=0, sticky='nsew')
self.animation=FuncAnimation(self.fig,func=self.animation_frame,frames=np.arange(0,11,1),interval=500, repeat=False)
self.snap_cursor = SnaptoCursor(self.ax, self.x, self.y)
self.fig.canvas.mpl_connect('button_press_event', self.snap_cursor.mouse_click)
class SnaptoCursor(object):
"""
Like Cursor but the crosshair snaps to the nearest x, y point.
For simplicity, this assumes that *x* is sorted.
"""
def __init__(self, ax, x, y):
self.ax = ax
self.lx = ax.axhline(color='k', linewidth=0.5) # the horiz line
self.ly = ax.axvline(color='k', linewidth=0.5) # the vert line
self.x = x
self.y = y
# text location in axes coords
self.txt = ax.text(0.05, 0.9, '', transform=ax.transAxes)
def mouse_click(self, event):
if not event.inaxes:
return
x, y = event.xdata, event.ydata
indx = min(np.searchsorted(self.x, x), len(self.x) - 1)
x = self.x[indx]
y = self.y[indx]
# update the line positions
self.lx.set_ydata(y)
self.ly.set_xdata(x)
self.txt.set_text('x=%1.2f, y=%1.2f' % (x, y))
self.ax.figure.canvas.draw()
if __name__ == "__main__":
app = SampleApp()
app.geometry('500x200')
app.title('MAIN GUI')
app.mainloop()
You need to make changes to your def Graph(self) function, as there are lines that are creating a window with tk.Toplevel and then the plt is creating another window.
Make your changes as follows, the capitalized comments you must do, and the others are optional for setting of titles:
def Graph(self):
#REMOVE THESE LINES
#self.graphtoplevel=tk.Toplevel(self.controller)
#self.graphtoplevel.title('Toplevel')
#modify the window title to your liking by assigning num
self.fig, self.ax = plt.subplots(num="TopLevel")
#REMOVE THESE LINES
#self.graph=FigureCanvasTkAgg(self.fig, self.graphtoplevel)
#self.image=self.graph.get_tk_widget()
plt.ion()
self.line, = self.ax.plot(self.x,self.y)
#REMOVE THIS LINE
#self.image.grid(row=0, column=0, sticky='nsew')
self.animation=FuncAnimation(self.fig,func=self.animation_frame,frames=np.arange(0,11,1),interval=500, repeat=False)
self.snap_cursor = SnaptoCursor(self.ax, self.x, self.y)
self.fig.canvas.mpl_connect('button_press_event', self.snap_cursor.mouse_click)
# displaying a title on top of figure (or do not add if not needed)
plt.title("Specific Fig Desc Title")
#ADD THIS LINE TO SHOW WINDOW
plt.show()
Please see this for more on figure window title:
Set matplotlib default figure window title
I am building a GUI that takes in sensor data from the raspberry pi and displays it onto a window via matplotlib animation. The code works fine, except when being run on raspberry pi, the matplotlib animation takes some time to execute, which momentarily blocks the sensor reading GetCPM that I'm interested in. How can I make both these programs run simultaneously without one clogging the other, I've tried the multiprocessing library, but I can't seem to get it to work.
Note: The sensor data that I'm plotting does not have to have a high sample rate, its the sensor that I'm displaying on label that does.
Here is my code
import matplotlib
matplotlib.use("TkAgg")
import numpy as np
import tkinter as tk
from tkinter import ttk
from tkinter import *
import math
import datetime as dt
import time
from collections import Counter
import random as rn
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
import matplotlib.pyplot as plt
import threading as td
import multiprocessing as mp
from multiprocessing import Process, Queue
style.use('seaborn')
limit = np.array([5])
# Initialize Pressure Figure
fig1, ax1 = plt.subplots()
fig2, ax2 = plt.subplots()
x1, y1 = [], []
x2, y2 = [], []
TOT = []
CPM = 0
def GetValues(i, x, y, ax):
volts2 = rn.uniform(3,6)
x.append(dt.datetime.now().strftime('%H: %M: %S.%f'))
y.append(float(volts2))
x = x[-50:]
y = y[-50:]
ax.clear()
ax.plot(x, y, linewidth=1, color= 'k')
ax.fill_between(x, y, limit[0], where=(y > limit[0]), facecolor='forestgreen', alpha=0.7, interpolate=True)
ax.fill_between(x, y, limit[0], where=(y < limit[0]), facecolor='darkred', alpha=0.7, interpolate=True)
ax.set_xticklabels([])
def animate(i, x, y, ax):
volts = rn.uniform(2,8)
x.append(dt.datetime.now().strftime('%H: %M: %S.%f'))
y.append(float(volts))
x = x[-50:]
y = y[-50:]
ax.clear()
ax.plot(x, y, linewidth=1, color= 'k')
ax.fill_between(x, y, limit[0], where=(y > limit[0]), facecolor='forestgreen', alpha=0.7, interpolate=True)
ax.fill_between(x, y, limit[0], where=(y < limit[0]), facecolor='darkred', alpha=0.7, interpolate=True)
ax.set_xticklabels([])
def GetCPM():
global TOT, CPM
temp = 1
# Test Case
if temp == True:
TOT.append(True)
else:
TOT.append(False)
TOT = TOT[-2750:]
count = Counter(TOT)
CPM = count[True]
return CPM
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# If you want to customize the icon of the tk window, only accepts .ico
#tk.Tk.iconbitmap(self, default="iconname.ico")
tk.Tk.wm_title(self, "Pressure")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0,weight=1)
container.grid_columnconfigure(0,weight=1)
self.frames = {}
frame = GUI(container, self)
self.frames[GUI] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(GUI)
def show_frame(self,cont):
frame = self.frames[cont]
frame.tkraise()
class GUI(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
canvas1 = FigureCanvasTkAgg(fig1, self)
canvas1.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
canvas2 = FigureCanvasTkAgg(fig2, self)
canvas2.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
#Initialize label as self.
lbl = tk.Label(self, font = ('Sans Serif', 40, 'bold'),
background = 'purple',
foreground = 'White')
lbl.place(relx=0.5, rely=0.5, anchor=CENTER)
def update():
ll = GetCPM()
lbl.config(text = "CPM = {}".format(ll))
print(dt.datetime.now().strftime('%H: %M: %S.%f'))
lbl.after(20, update)
update()
# interval determines the speed at which data is recorded, 1000 = 1 second
if __name__ == '__main__':
app = App()
t1 = mp.Process(target=GetCPM)
t1.start()
t1.join()
ani_1 = animation.FuncAnimation(fig1, animate, interval = 500,
fargs=(x1, y1, ax1))
ani_2 = animation.FuncAnimation(fig2, GetValues, interval = 500,
fargs=(x2, y2, ax2))
app.mainloop()
I would like to come directly to the point, so I will firstly just ask all my questions which I have.
In Class Win1 I have a combobox, my question is: Is there a possibility to define the entry/chosen symbol as a variable and is there a possibility to define the variable as global, without having to redefine classes?
This is my second question, which is at the moment less relevant than the first one.
When this code is running, first one window shows up, then a second one and so on. When turning this code into a software/app/..., will the software then also show one window than a second one or will everything be in one window?
import math
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
matplotlib.use('TkAgg')
#------------------------------------------------------------------------------
import tkinter
import tkinter as tk
from tkinter import ttk
import tkinter.font as tkFont
import tkinter.ttk as ttk
from tkinter import *
from tkinter.ttk import Combobox
#------------------------------------------------------------------------------
import numpy as np
#------------------------------------------------------------------------------
import pandas as pd
from pandas import DataFrame
from pandas.compat import StringIO
from pandas_datareader import data as web
#------------------------------------------------------------------------------
import yfinance as yf
#------------------------------------------------------------------------------
from statistics import mean
#------------------------------------------------------------------------------
import requests
#------------------------------------------------------------------------------
import time
from datetime import datetime
from datetime import date
from datetime import timedelta
import calendar
#------------------------------------------------------------------------------
import random
#------------------------------------------------------------------------------
from alpha_vantage.timeseries import TimeSeries
from alpha_vantage.techindicators import TechIndicators
#------------------------------------------------------------------------------
import sys
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler
#------------------------------------------------------------------------------
#symbol = 'TSLA'
global_symbol = ""#None
#combobox = ""
def onSymbolSelected(self,event = None):
global global_symbol
global_symbol = self.combobox.get() # this assume combo is a property of Win1
def config_plot():
fig, ax = plt.subplots()
return(fig, ax)
class Win1:
def __init__(self, master):
self.master = master
self.master.geometry("400x400")
self.frame = tk.Frame(self.master)
#symbol = Entry(root, text ='', bd=5)
#userInput1 = StringVar(None)
#self.master = Entry(root, textvariable=userInput1)
#self.master.pack()
SMI = ['ROG.SW','NOVN.SW','NESN.SW','SRAIL.SW','ABB','ADEN.SW','ALC.SW','CSGN.SW','GEBN.SW','GIVN.SW',
'LONN.SW','CFR.SW','SIKA.SW','UHR.SW','SLHN.SW','SREN.SW','SCMN.SW','UBSG.SW','ZURN.SW']
SMI.sort()
NYSE = ['NYSE:MMM','NYSE:AXP','NYSE:AAPL','NYSE:BA','NYSE:CAT','NYSE:CVX','NYSE:CSCO','NYSE:KO','NYSE:DOW','NYSE:XOM',
'NYSE:GS','NYSE:HD','NYSE:IBM','NYSE:INTC','NSYE:JNJ','NYSE:JPM','NYSE:MCD','NYSE:MRK','NYSE:MSFT','NYSE:NKE',
'NYSE:PFE','NYSE:PG','NYSE:RTX','NYSE:TRV','NYSE:UNH','NYSE:VZ','NYSE:V','NYSE:WMT','NYSE:WBA','NYSE:DIS']
NYSE.sort()
DAX = ['ETR:ADS','ETR:ALV','ETR:BAS','ETR:BAYN','ETR:BEI','ETR:BMW','ETR:CON','ETR:1COV','ETR:DAI','ETR:DBK',
'ETR:LHA','ETR:DPW','ETR:DTE','ETR:EOAN','ETR:FRE','ETR:FME','ETR:HEI','ETR:HEN3','ETR:IFX','ETR:MTX',
'ETR:MUV2','ETR:RWE','ETR:SAP','ETR:SIE','ETR:VOW3','ETR:VNA','ETR:WDI']
DAX.sort()
Stockxx = []
Stockxx.sort()
symbol = ['ROG.SW','SMI','NYSE','DAX','Stockxx']
symbol.sort()
#symbol.current()
#root= Tk()
self.combobox = StringVar()
self.combobox = ttk.Combobox(master, values = symbol)
#def onSymbolSelected(self, Event = None):
# global global_symbol
# global_symbol = self.combobox.get()
self.combobox.bind("<<ComboboxSelected>>", onSymbolSelected)#onSymbolSelected)
#cb = ttk.Combobox(master, values = symbol)
#print(var)
# note that this is the StringVar ICUS, not the combobox ICUSTOMER.
#label_var = tk.Label( textvariable= var)
#print(label_var)
#label_ICustVar.grid(row = 3, column = 3)
self.combobox.place(x=100, y=50)
button1 = Button(root, text="Click Here", fg = 'blue', width=20, command = lambda: self.new_window("2", Win2))
button1.pack(side='bottom',padx=15,pady=15)
# this assume combo is a property of Win1
#self.butnew("Hauptfunktionen", "2", Win2)
#self.butnew("Weitere Funktionen", "3", Win3)
self.quit = tk.Button(self.frame, text = f"Close this window", command = self.close_window)
self.quit.pack()
self.frame.pack()
print(symbol,"asfjöasldkjflödas")
print(global_symbol,"ioöbajbo")
def close_window(self):
self.master.destroy()
#def onSymbolSelected(self,event = None):
# global global_symbol
# global_symbol = self.combo.get() # this assume combo is a property of Win1
def butnew(self, text, number, _class):
tk.Button(self.frame, text = text, command= lambda: self.new_window(number, _class)).pack(side='left')
def new_window(self, number, _class):
self.new = tk.Toplevel(self.master)
_class(self.new, number)
class Win2:
def __init__(self, master, number):
self.master = master
self.master.geometry("1080x540")
self.frame = tk.Frame(self.master)
self.frame = Frame(self.master)
self.fig, self.ax = config_plot()
self.graphIndex = 0
self.canvas = FigureCanvasTkAgg(self.fig, self.master)
self.config_window()
self.quit = tk.Button(self.frame, text = f"Close this window", command = self.close_window)
self.quit.pack(side=LEFT)
self.draw_graph_one()
self.butnew("Weitere Funktionen", "3", Win3)
self.frame.pack(expand=YES, fill=BOTH)
def butnew(self, text, number, _class):
tk.Button(self.frame, text = text, command= lambda: self.new_window(number, _class)).pack(side='left')
def new_window(self, number, _class):
self.new = tk.Toplevel(self.master)
_class(self.new, number)
def draw_graph_one(self):
ts = TimeSeries(key='YOUR_API_KEY',output_format='pandas')
data1, meta_data1 = ts.get_monthly(symbol=global_symbol)
df1 = data1['4. close']
self.ax.clear()
self.ax.plot(df1)
self.ax.set(title='Historical Chart')
self.canvas.draw()
#------------------------------------------------------------------------fertig
def draw_graph_two(self):
ts = TimeSeries(key='YOUR_API_KEY',output_format='pandas')
data2, meta_data2 = ts.get_intraday(symbol=global_symbol, interval='1min', outputsize='compact')
df2 = data2['4. close']
self.ax.clear()
self.ax.plot(df2)
self.ax.set(title='Intraday')
self.canvas.draw()
#------------------------------------------------------------------------fertig
def draw_graph_three(self):
ti = TechIndicators(key='YOUR_API_KEY',output_format='pandas')
data3, meta_data3 = ti.get_bbands(symbol=global_symbol, interval='15min', time_period=30)
df3 = data3
ts = TimeSeries(key='YOUR_API_KEY',output_format='pandas')
data2, meta_data2 = ts.get_intraday(symbol=global_symbol, interval='15min', outputsize='full')
df2 = data2['4. close']
self.ax.clear()
self.ax.plot(df2, linestyle='-.')
self.ax.plot(df3)
self.ax.set(title='Bollinger Bands')
self.canvas.draw()
#------------------------------------------------------------------------fertig
def draw_graph_four(self):
ti = TechIndicators(key='YOUR_API_KEY',output_format='pandas')
data44, meta_data44 = ti.get_sma(symbol=global_symbol, interval='30min', time_period=60)
df44 = data44
ts = TimeSeries(key='YOUR_API_KEY',output_format='pandas')
data1, meta_data1 = ts.get_intraday(symbol=global_symbol, interval='30min', outputsize='full')
df1 = data1['4. close']
self.ax.clear()
self.ax.plot(df1)#, color='yellow')
self.ax.plot(df44)#, color='black')
self.ax.set(title='Simple Moving Average')
self.canvas.draw()
#------------------------------------------------------------------------fertig
def draw_graph_five(self):
ts = TimeSeries(key='YOUR_API_KEY',output_format='pandas')
data1, meta_data1 = ts.get_monthly(symbol=global_symbol)#, interval='1min', outputsize='full')
df1 = data1['4. close']
ts = TimeSeries(key='YOUR_API_KEY',output_format='pandas')
dataG, meta_dataG = ts.get_monthly(symbol='UCITS ETF')#, interval='1min', outputsize='full')
dG = dataG['4. close']
self.ax.clear()
self.ax.plot(df1)
self.ax.plot(dG)
self.ax.set(title='Comparision with Global Index')
self.canvas.draw()
#------------------------------------------------------------------------------
def draw_graph_six(self):
ti = TechIndicators(key='YOUR_API_KEY',output_format='pandas')
data23, meta_data23 = ti.get_cci(symbol=global_symbol, interval='30min', time_period=60)
df23 = data23
self.ax.clear()
self.ax.plot(df23)
self.ax.set(title='Commodity Channel Index')
self.canvas.draw()
#------------------------------------------------------------------------fertig
def draw_graph_seven(self):
ti = TechIndicators(key='YOUR_API_KEY',output_format='pandas')
data13, meta_data23 = ti.get_dx(symbol=global_symbol, interval='30min', time_period=60)
df13 = data13
self.ax.clear()
self.ax.plot(df13)
self.ax.set(title='Directional Movement Index')
self.canvas.draw()
#------------------------------------------------------------------------------
def draw_graph_eight(self):
self.ax.clear()
self.ax.plot()
self.ax.set(title='Further Information')
self.canvas.draw()
#------------------------------------------------------------------------------
def draw_graph_nine(self):
self.ax.clear()
self.ax.plot()
self.ax.set(title='Further Information')
self.canvas.draw()
def on_key_press(event):
print("you pressed {}".format(event.key))
key_press_handler(event, self.canvas, toolbar)
def config_window(self):
self.canvas.mpl_connect("key_press_event", self.on_key_press)
toolbar = NavigationToolbar2Tk(self.canvas, self.master)
toolbar.update()
self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
self.button_switch1 = Button(self.master, text="Historical Chart", command=self.draw_graph_one)
self.button_switch1.pack(side=LEFT)
self.button_switch2 = Button(self.master, text="Intraday", command=self.draw_graph_two)
self.button_switch2.pack(side=LEFT)
self.button_switch3 = Button(self.master, text="Bollinger Bands", command=self.draw_graph_three)
self.button_switch3.pack(side=LEFT)
self.button_switch4 = Button(self.master, text="SMA", command=self.draw_graph_four)
self.button_switch4.pack(side=LEFT)
self.button_switch5 = Button(self.master, text="Comparison with Index", command=self.draw_graph_five)
self.button_switch5.pack(side=LEFT)
self.button_switch6 = Button(self.master, text="CCI", command=self.draw_graph_six)
self.button_switch6.pack(side=LEFT)
self.button_switch7 = Button(self.master, text="DX", command=self.draw_graph_seven)
self.button_switch7.pack(side=LEFT)
self.button_switch8 = Button(self.master, text="Technical Analysis", command=self.draw_graph_eight)
self.button_switch8.pack(side=LEFT)
self.button_switch9 = Button(self.master, text="Technical Analysis", command=self.draw_graph_nine)
self.button_switch9.pack(side=LEFT)
def close_window(self):
self.master.destroy()
class Win3:
def __init__(self, master, number):
self.master = master
self.master.geometry("1080x540")
self.frame = tk.Frame(self.master)
#self.frame = Frame(self.master)
self.fig, self.ax = config_plot()
self.graphIndex = 0
self.canvas = FigureCanvasTkAgg(self.fig, self.master)
self.config_window()
self.quit = tk.Button(self.frame, text = f"Close this window", command = self.close_window)
self.quit.pack(side=LEFT)
self.frame.pack(expand=YES, fill=BOTH)
def on_key_press(event):
print("you pressed {}".format(event.key))
key_press_handler(event, self.canvas, toolbar)
def config_window(self):
self.canvas.mpl_connect("key_press_event", self.on_key_press)
toolbar = NavigationToolbar2Tk(self.canvas, self.master)
toolbar.update()
self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
def close_window(self):
f.master.destroy()
root = tk.Tk()
app = Win1(root)
root.mainloop()
Sorry for asking so many questions, unfortunately I didn't completely understand the answers from my previous question. Thank you very much for your help.
Ok, so I instead of opening a new thread, I decided just to expand my program directly here, since my new question is based on the old one. So I changed the program and my it doesn't work totally. The problem is that global_symbol doesn't change its value and I don't understand where the problem lies, I tried many things (leaving some lines, adding, etc) but none of them really worked. So does anyone of you guys know where the problem lies?
For question 1/ What you can do (worst case) is add a callback to your combobox. This callback can then update a "global variable"
Callback setting on combobox :
self.combo = ttk.Combobox(master, values = symbol)
self.combo.bind("<<ComboboxSelected>>", onSymbolSelected)
symbol declaration outside of Win1
global_symbol = None
callback implementation in Win1
def onSymbolSelected(self,event = None)
global global_symbol
global_symbol = self.combo.get() # this assume combo is a property of Win1
I'm trying to live plot EEG recording in my tkinter app. However, it does not plot while the data is updating in the while loop, and plots only at the end.
import tkinter as tk
from tkinter import ttk, Button, LabelFrame, N, W, messagebox as box
import time
import datetime as dt
from datetime import date
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib
import matplotlib.animation as animation
import matplotlib.pyplot as plt
class NFB_HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.nfbprotocol = 0
self.metricstime = 0
self.nfbmetric = 0
self.df = []
self.xList = []
self.yList = []
# Start Neurofeedback
self.StartNFB = Button(self, text="Start NFB", width=25, command=self.onStartNFB)
self.StartNFB.grid(row=7, column=0, padx=5, pady=3, sticky=W)
# LabelFrame for EEG Graph
labelframe3 = LabelFrame(self, text="EEG Plot")
labelframe3.grid(row=4, column=2, padx=5, pady=2, sticky=N, rowspan=5, columnspan=4)
self.fig = plt.Figure(figsize=(10, 5), dpi=100)
self.ax1 = self.fig.add_subplot(111)
self.line, = self.ax1.plot([], [], lw=2)
self.canvas = FigureCanvasTkAgg(self.fig, labelframe3)
self.canvas.draw()
self.canvas.get_tk_widget().grid()
self.canvas._tkcanvas.grid(row=0, column=0, padx=5, pady=3, sticky=W)
def createDF(self):
df_timestamp = []
df_data = np.empty([0, 5])
# metrics
df_alpha = np.empty([0, 1])
df_beta = np.empty([0, 1])
df_theta = np.empty([0, 1])
df_delta = np.empty([0, 1])
df_alpha_theta = np.empty([0, 1])
df_metricstime = np.empty([0, 1])
return df_timestamp, df_data, df_alpha, df_beta, df_theta, df_delta, df_alpha_theta, df_metricstime
def onStartNFB(self):
try:
self.start()
# Initialize dataframes
df_timestamp, df_data, df_alpha, df_beta, df_theta, df_delta, df_alpha_theta, df_metricstime = self.createDF()
# Start recording here!
timestart = time.time()
while time.time() < timestart + int(4):
""" 3.1 ACQUIRE DATA """
self.metricstime = dt.datetime.now().strftime('%H:%M:%S.%f')
""" 3.3 COMPUTE NEUROFEEDBACK METRICS """
alpha_metric, beta_metric, theta_metric, delta_metric, alphatheta_metric = float(np.random.normal(size=1)), float(np.random.normal(size=1)), \
float(np.random.normal(size=1)), float(np.random.normal(size=1)), \
float(np.random.normal(size=1))
self.nfbmetric = alpha_metric
# Save the bands to data frame
df_alpha = np.append(df_alpha, [[alpha_metric]], axis=0)
df_beta = np.append(df_beta, [[beta_metric]], axis=0)
df_theta = np.append(df_theta, [[theta_metric]], axis=0)
df_delta = np.append(df_delta, [[delta_metric]], axis=0)
df_alpha_theta = np.append(df_alpha_theta, [[alphatheta_metric]], axis=0)
df_metricstime = np.append(df_metricstime, [[self.metricstime]], axis=0)
# Update graph
self.df = np.concatenate([df_metricstime, df_alpha, df_theta, df_alpha_theta],
axis=1)
print(self.nfbmetric)
except:
raise RuntimeError("Error with Neurofeedback.")
def start(self):
self.ani = animation.FuncAnimation(self.fig, self.animate, interval=int(500))
self.running = True
self.ani._start()
def animate(self,i):
df = self.df
for eachline in df:
if len(eachline) > 1:
dfX = eachline[0]
dfY = eachline[1]
self.xList.append(dfX)
self.yList.append(dfY)
self.ax1.clear()
self.ax1.plot(self.xList, self.yList)
title = "Neurofeedback Band Power"
self.ax1.set_title(title)
app = ExpGUI()
app.geometry("1280x720")
app.mainloop()
Does somebody know what is wrong with my code? I know how to get it to run outside the while loop, but I have problems getting it to run while the data is updating.
I'm practicing tkinter and matplotlib.
I wrote this piece of code which creates an entered number of frames and in each frame a different plot is embedded. I can then go from plot to plot by switching between the created frames and turn a drawing mode on. What the drawing mode do is enable me to click on the plot and create a horizontal line on it.
But when I turn drawing mode on I can only interact with the last graph.
Any ideas why this is happening?
The piece of code:
from tkinter import *
from random import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib import pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
numberOfFrames = eval(input('Number of frames to be crated: '))
x = []
y = []
class app(Tk):
def __init__(self):
Tk.__init__(self)
self.geometry('640x400')
self.frames = []
self.currentPage = 0
def nextpage():
try:
frame = self.frames[self.currentPage+1]
frame.tkraise()
self.currentPage += 1
except:
pass
def backpage():
if self.currentPage == 0:
pass
else:
frame = self.frames[self.currentPage-1]
frame.tkraise()
self.currentPage -= 1
def DrawOn():
def onclick(event):
plt.hlines(event.ydata,event.xdata-0.1,event.xdata+0.1,
colors='r',linestyle='solid')
canvas.show()
fig.canvas.mpl_connect('button_press_event', onclick)
for i in range(numberOfFrames):
frame = Frame(self)
frame.grid(row=0, column=0, sticky="nsew")
self.frames.append(frame)
fig = plt.figure()
for j in range(2):
x.append(randint(1,10))
y.append(randint(1,10))
plt.plot(x,y)
canvas = FigureCanvasTkAgg(fig, self.frames[i])
canvas.get_tk_widget().pack(fill='both', expand=True)
toolbar = NavigationToolbar2TkAgg(canvas, self.frames[i])
toolbar.update()
canvas._tkcanvas.pack(fill='both', expand=True)
label = Label(self.frames[i], text='Page %d'%(i+1))
label.pack()
Next = Button(self.frames[i], text='Next', command = nextpage)
Next.pack(side=LEFT)
Back = Button(self.frames[i], text='Back', command = backpage)
Back.pack(side=LEFT)
Draw = Button(self.frames[i], text='Draw', command = DrawOn)
Draw.pack(side=LEFT)
self.frames[0].tkraise()
run = app()
run.mainloop()
That's the alteration I made to my code. It made possible to interact with all the embedded graphs. I'm not sure if it is the best way to do it, but it seems to work.
from tkinter import *
from random import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib import pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
numberOfFrames = eval(input('Number of frames to be crated: '))
x = []
y = []
class app(Tk):
def __init__(self):
Tk.__init__(self)
self.geometry('640x400')
self.frames = []
self.currentPage = 0
self.figs = []
self.axeslist = []
self.canvaslist = []
def nextpage():
try:
frame = self.frames[self.currentPage+1]
frame.tkraise()
self.currentPage += 1
except:
pass
def backpage():
if self.currentPage == 0:
pass
else:
frame = self.frames[self.currentPage-1]
frame.tkraise()
self.currentPage -= 1
def DrawOn():
def onclick(event):
self.axeslist[self.currentPage].hlines(event.ydata,event.xdata-0.1,event.xdata+0.1,
colors='r',linestyle='solid')
self.canvaslist[self.currentPage].show()
print(event.xdata,event.ydata)
for i in self.figs:
i.canvas.mpl_connect('button_press_event', onclick)
for i in range(numberOfFrames):
frame = Frame(self)
frame.grid(row=0, column=0, sticky="nsew")
self.frames.append(frame)
fig = plt.figure()
self.figs.append(fig)
ax = self.figs[i].add_subplot(111)
self.axeslist.append(ax)
for j in range(2):
x.append(randint(1,10))
y.append(randint(1,10))
plt.plot(x,y)
canvas1 = FigureCanvasTkAgg(self.figs[i], self.frames[i])
self.canvaslist.append(canvas1)
self.canvaslist[i].get_tk_widget().pack(fill='both', expand=True)
toolbar = NavigationToolbar2TkAgg(self.canvaslist[i], self.frames[i])
toolbar.update()
self.canvaslist[i]._tkcanvas.pack(fill='both', expand=True)
label = Label(self.frames[i], text='Page %d'%(i+1))
label.pack()
Next = Button(self.frames[i], text='Next', command = nextpage)
Next.pack(side=LEFT)
Back = Button(self.frames[i], text='Back', command = backpage)
Back.pack(side=LEFT)
Draw = Button(self.frames[i], text='Draw', command = DrawOn)
Draw.pack(side=LEFT)
self.frames[0].tkraise()
run = app()
run.mainloop()