Tkinter textvariable not updated with MatplotLib - python

Can anyone help me here? The textvariable is not being updated when I add the line:
f = plt.figure(0, figsize=(20,9))
If I comment the line above, then I see the textvariable being updated in the Label, but as soon as I uncomment the line, the Label is not updated anymore.
Can anyone help me, please?
from tkinter import *
from tkinter import ttk
from tkinter import StringVar
import matplotlib
import matplotlib.artist as artists
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.animation as animation
f = plt.figure(0, figsize=(20,9))
class make_window():
def __init__(self, *args, **kwargs):
self.win = Tk()
self.win.title("Test")
self.win.state("zoomed")
Frame = ttk.Frame(self.win)
Frame.pack()
labelVar = StringVar()
labelVar.set("Hi")
self.LabelUpdate = Label(Frame, textvariable = labelVar)
self.LabelUpdate.pack()
#################################################################################
window = make_window()
window.win.mainloop()

I have noticed a few issues that you need to address.
First the way you are importing (from tkinter import *) is going to cause problems and in fact here in this case you make the kind of mistake this import is known for. Later in your code you do Frame = ttk.Frame() and this one line is actually overriding the Frame import from from tkinter import *. Do not name your variables the same as built in methods. In order to prevent this kind of mistake you can simply do import tkinter as tk and always use the tk. prefix to prevent any overriding in your code.
Next I noticed your Label does pack to the screen but does not show any text oddly enough but when I comment out f = plt.figure(0, figsize=(20,9)) the Label starts to work as expected.
So there is some odd interaction here with matplotlib and this label.
When I change f = plt.figure(0, figsize=(20,9)) to f = Figure(figsize=(20,9)) the label also works again.
If Figure() is not exactly what you are trying to use here then please add some more context to your code as to what you are expecting to do with f.
Update:
I did also notice that when you move f to be after self.win = tk.Tk() the code works fine. My only guess as to why this is happening is possible how matplotlib does have its own tkinter code in it. So if you try to create a plt.figure before you create your tkinter instance then I imaging in the back end a tkinter instance is being ran by matplotlib and this is what is causing the odd behavior. I could be wrong but I cannot think of anything else. Maybe the Tkinter master Bryan Oakley can enlighten us as to what is causing this :D
import tkinter as tk
import tkinter.ttk as ttk
import matplotlib
import matplotlib.artist as artists
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.animation as animation
class make_window():
def __init__(self, *args, **kwargs):
self.win = tk.Tk()
# moving the line to here should at least allow your code to work.
f = plt.figure(0, figsize=(20,9))
self.win.title("Test")
self.win.state("zoomed")
frame = ttk.Frame(self.win)
frame.pack()
labelVar = tk.StringVar()
labelVar.set("Hi")
self.LabelUpdate = tk.Label(frame, textvariable = labelVar)
self.LabelUpdate.pack()
window = make_window()
window.win.mainloop()

Related

"cannot import name 'geometry' from 'tkinter'"

I am trying a "Hello World" test on a GUI window, imported from tkinter. The problem starts when I try to run it and an error pops up in the terminal of VScode:
cannot import name 'geometry' from 'tkinter'.
import csv
from fileinput import filename
import os
from tkinter import *
from tkinter import ttk
from tkinter import Tk, Button, Frame, Entry, END
from tkinter import geometry
class attendance_tester(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
root = Tk()
root.geometry("800x800")
frm = ttk.Frame(root, padding=10)
frm.grid()
ttk.Label(frm, text="Hello World!").grid(column=0, row=0)
ttk.Button(frm, text="Quit", command=root.destroy).grid(column=1, row=0)
app = attendance_tester(master=root)
app.master.title("Student Attendance Program")
app.mainloop()
root.destroy()
from attendance_create import (func_create, func_edit_add,
func_ask_edit, func_edit_change, func_edit_sub,
func_edit_view, func_open, func_first_change)
with open(r"C:\\Users\\user_name\\Desktop\\attendance_sheet.csv") as file:
csv_file_read = csv.reader(file)
for row in csv_file_read:
print(row)
func_open()
attend_test = attendance_tester(root)
root.mainloop()
I have tried seemingly every solution I could find on the internet. I really need some help.
You don't need to import geometry to use it. Just remove the import line and it should work.
you shouldnt import it from the first place you just need to import the tkinter itself just remove that line and it should be just fine
There is no reason to import geometry, it works without that import line.
Also, you have a few duplicate imports which may become confusing. It's better to stick to fewer imports:
from tkinter import *
from tkinter import ttk
from tkinter import Tk, Button, Frame, Entry, END

Tkinter Matplotlib NavigationToolbar2Tk renders incorrectly and buttons are bugged on MacOS, any solutions to fix this?

I am trying to implement a navigation toolbar that works with my graph that is embedded into Tkinter. When displayed, it looks broken, with the icons pushed into the bottom right corner and the buttons do not work correctly and sometimes get stuck. I am on MacOS BigSur.
Code to replicate:
import tkinter as tk
from PIL import ImageTk, Image
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
root = tk.Tk()
figure = Figure(figsize = (7.5, 5.19), dpi = 100)
line = figure.add_subplot(111)
canvas = FigureCanvasTkAgg(figure, master = root)
canvasToolBar = NavigationToolbar2Tk(canvas, window = root)
canvas.get_tk_widget().pack()
canvasToolBar.pack()
line.plot([0,1,2,3,4,5], [0,1,2,3,4,5], marker='o')
canvas.draw()
root.mainloop()
I have noticed previously that some elements of Tkinter work incorrectly on a Mac system, so is this another problem Mac users will face or is the implementation of the toolbar incorrect?

python, tkinter, issues while creating bar graph

I'm getting the following error message when I try to create a bars graph, using python and tkinter:
AttributeError: 'FigureCanvasTkAgg' object has no attribute 'show'
Here's my code
import matplotlib,numpy,sys
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from tkinter import *
root=Tk()
f=Figure(figsize=(5,4),dpi=100)
ax=f.add_subplot(111)
data=(20,35,30,35,27)
ind=numpy.arange(5) # the x locations for the groups
width=.5
rects1=ax.bar(ind,data,width)
canvas=FigureCanvasTkAgg(f,master=root)
canvas.show()
canvas.get_tk_widget().pack(side=TOP,fill=BOTH,expand=1)
root.mainloop()
Simply delete the line that's causing the problem:
import matplotlib,numpy,sys
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from tkinter import Tk,TOP,BOTH
root=Tk()
f=Figure(figsize=(5,4),dpi=100)
ax=f.add_subplot(111)
data=(20,35,30,35,27)
ind=numpy.arange(5) # the x locations for the groups
width=.5
rects1=ax.bar(ind,data,width)
canvas=FigureCanvasTkAgg(f,master=root)
canvas.get_tk_widget().pack(side=TOP,fill=BOTH,expand=1)
root.mainloop()
Or replace .show() with .draw() as #acw1668 mentioned in comment.

Embedding matplotlib into a tkinter application

I've got a program that on launch will open a matplotlib graph of bitcoin prices and will update every time the price changes. Then when I close it a fullscreen tkinter application opens with a background image and a updating clock in the corner. What I would like to happen is when I launch the program a fullscreen tkinter application opens with a background image, an updating clock in the corner, and the matplotlib graph in the middle. Basically I want to embed the matplotlib graph into my application. I've tried putting the graph code into my class and calling it but that just gives the results mentioned earlier. I tried replacing the plt.show() with this:
canvas = FigureCanvasTkAgg(fig, self)
canvas.show()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)
but then the program wasn't launching at all. No matter where I put it in the script it would give errors like ''self' is not defined' when I directly replaced plt.show()with it and ''canvas' is not defined' when I tried to integrate it into the class. Here is the full code below:
from tkinter import *
from PIL import ImageTk, Image
import os
import time
import requests
import tkinter as tk
import matplotlib.pyplot as plt
import matplotlib.animation as animation
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
from tkinter import ttk
import urllib
import json
import pandas as pd
import numpy as np
from PyQt5 import QtWidgets
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
class App(tk.Tk):
def __init__(self):
# call the __init__ method of Tk class to create the main window
tk.Tk.__init__(self)
# background image
img = ImageTk.PhotoImage(Image.open("0.png"))
panel = Label(self, image=img)
panel.pack()
# clock
self.label = tk.Label(self, text="", font=('comic',50,'bold'),
bg='#464545', fg='#1681BE')
self.label.place(height=204, width=484, x=1384, y=824)
self.update_clock()
# window geometry
w, h = self.winfo_screenwidth(), self.winfo_screenheight()
self.geometry("%dx%d+0+0" % (w, h))
self.overrideredirect(True)
self.mainloop()
def update_clock(self):
now = time.strftime('%H:%M:%S')
self.label.configure(text=now)
self.after(1000, self.update_clock)
def animate(self):
dataLink = 'https://btc-e.com/api/3/trades/btc_usd?limit=2000d'
data = urllib.request.urlopen(dataLink)
data = data.read().decode("utf-8")
data = json.loads(data)
data = data["btc_usd"]
data = pd.DataFrame(data)
buys = data[(data['type']=="ask")]
buys["datestamp"] = np.array(buys["timestamp"]).astype("datetime64[s]")
buyDates = (buys["datestamp"]).tolist()
plot(buyDates, buys["price"])
xlabel('time')
ylabel('Temperature')
title('Temperature Chart')
grid(True)
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
app = App()
There are a few dependable's like '0.png' which is the background image and of course the many modules but any feedback would be much appreciated.
plt.show() will open a new dedicated GUI window to host the figure(s) currently present in the matplotlib state machine. If you don't want that, don't use plt.show().
To be on the save side, best don't use pyplot at all as even such innocent commands as plt.xticks() can cause a new window to open.
Also, get rid of from pylab import *. Pylab is a construct which includes several packages like numpy and pyplot in a single namespace. This may be desired for interactive notebook-like applications, but is usually a bad idea for scripts, as it makes debugging very cumbersome. Instead, try to fully stick to matplotlib API commands.
This linked question actually is an example of how to use FigureCanvasTkAgg and NavigationToolbar2Tk to embed a figure into tk.
A better start might be to look at the matplotlib example page where a minimal example for tk embedding is presented.

update matplotlib plot in tkinter GUI

I wanna update a matplotlib plot in a tkinter GUI. I tried to do so in the following code example.
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import tkinter as tk
import tkinter.ttk as ttk
import sys
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master)
self.createWidgets()
def createWidgets(self):
fig=plt.figure(figsize=(8,8))
ax=fig.add_axes([0.1,0.1,0.8,0.8],polar=True)
canvas=FigureCanvasTkAgg(fig,master=root)
canvas.get_tk_widget().grid(row=0,column=1)
canvas.show()
self.plotbutton=tk.Button(master=root, text="plot", command=self.plot)
self.plotbutton.grid(row=0,column=0)
def plot(self):
for line in sys.stdout: #infinite loop, reads data of a subprocess
theta=line[1]
r=line[2]
ax.plot(theta,r,linestyle="None",maker='o')
plt.show(block=False)
plt.pause(0.001)
plt.cla()
#here set axes
root=tk.Tk()
app=Application(master=root)
app.mainloop()
At the moment the problem is, that the ax object is not known in the plot function. If I try plot(self,canvas,ax) the GUI does not open. Only a figure that plots the data.
I wanna plot the data in the figure that is seen in the GUI. At least with a refresh rate round about 3-5Hz.
Cause I am an absolute beginner this code solution is probably not the best way to do so. So I would be happy, if someone could show me a smarter solution.
Thanks!
Ok I could solve it myself. Here the solution:
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import tkinter as tk
import tkinter.ttk as ttk
import sys
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master)
self.createWidgets()
def createWidgets(self):
fig=plt.figure(figsize=(8,8))
ax=fig.add_axes([0.1,0.1,0.8,0.8],polar=True)
canvas=FigureCanvasTkAgg(fig,master=root)
canvas.get_tk_widget().grid(row=0,column=1)
canvas.show()
self.plotbutton=tk.Button(master=root, text="plot", command=lambda: self.plot(canvas,ax))
self.plotbutton.grid(row=0,column=0)
def plot(self,canvas,ax):
for line in sys.stdout: #infinite loop, reads data of a subprocess
theta=line[1]
r=line[2]
ax.plot(theta,r,linestyle="None",maker='o')
canvas.draw()
ax.clear()
#here set axes
root=tk.Tk()
app=Application(master=root)
app.mainloop()
Thanks Abishek for taking the time to post the answer to your own problem.
I've just modified your answer a bit so that it runs as a standalone module without needing input from sys.stdout. Also changed the tkinter imports for python 2.7
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import Tkinter as tk # python 2.7
import ttk # python 2.7
import sys
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master)
self.createWidgets()
def createWidgets(self):
fig=plt.figure(figsize=(8,8))
ax=fig.add_axes([0.1,0.1,0.8,0.8],polar=True)
canvas=FigureCanvasTkAgg(fig,master=root)
canvas.get_tk_widget().grid(row=0,column=1)
canvas.show()
self.plotbutton=tk.Button(master=root, text="plot", command=lambda: self.plot(canvas,ax))
self.plotbutton.grid(row=0,column=0)
def plot(self,canvas,ax):
c = ['r','b','g'] # plot marker colors
ax.clear() # clear axes from previous plot
for i in range(3):
theta = np.random.uniform(0,360,10)
r = np.random.uniform(0,1,10)
ax.plot(theta,r,linestyle="None",marker='o', color=c[i])
canvas.draw()
root=tk.Tk()
app=Application(master=root)
app.mainloop()
I don't know if it will be useful to anybody, but I updated the code to run with matplotlib 3.1.x+ and python 3.
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import numpy as np
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master)
self.createWidgets()
def createWidgets(self):
fig=plt.figure(figsize=(8,8))
ax=fig.add_axes([0.1,0.1,0.8,0.8],polar=True)
canvas=FigureCanvasTkAgg(fig,master=root)
canvas.get_tk_widget().grid(row=0,column=1)
canvas.draw()
self.plotbutton=tk.Button(master=root, text="plot", command=lambda: self.plot(canvas,ax))
self.plotbutton.grid(row=0,column=0)
def plot(self,canvas,ax):
c = ['r','b','g'] # plot marker colors
ax.clear() # clear axes from previous plot
for i in range(3):
theta = np.random.uniform(0,360,10)
r = np.random.uniform(0,1,10)
ax.plot(theta,r,linestyle="None",marker='o', color=c[i])
canvas.draw()
root=tk.Tk()
app=Application(master=root)
app.mainloop()

Categories

Resources