I'm trying to display equations by using GUI. I use latex and canvas. However, I'm getting an error message ValueError: KeyPress event keysym=Return keycode=36 char='\r' x=266 y=8
it should be working because I have already converted python expressions into Latex's.
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib
import matplotlib.pyplot as plt
from tkinter import *
from sympy import *
matplotlib.use('TkAgg')
root=Tk()
frame=Frame(root)
frame.pack()
frame1= Frame()
frame1.pack()
caracter=StringVar()
def result(caracter):
a = str(caracter)
text1=latex(a)
ax.clear()
ax.text(0.2, 0.6, "$"+text1+"$", fontsize = 6)
canvas.draw()
def element(num):
caracter.set(caracter.get()+num)
#-----------------------------SCREEN------------
screen=Entry(frame, width=50, textvariable=caracter)
screen.pack()
screen.grid(row=1, column=1, pady=10, columnspan=5)
#-----------------------BUTTONS-----------------------
go=Button(frame, height=1, text="Go")
go.grid(row=1, column=6)
Buttonx=Button(frame, text="x", width=5, padx=0, pady=2, command=lambda:element("x"))
Buttonx.grid(row=2, column=6)
#--------CANVAS ---------------
label = Label(frame1)
label.pack()
fig = matplotlib.figure.Figure(figsize=(5, 4), dpi=100)
ax = fig.add_subplot(111)
canvas = FigureCanvasTkAgg(fig, master=label)
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
root.bind('<Return>', result)
root.mainloop()
This is the shortest code to reproduce the issue. Any help or hint will be appreciated. Thank you very much in advance
You are passing the char associated with <RETURN> to your function result. Because the parameter is named caracter, this shadows the variable caracter declared earlier as a tk.StringVar.
something like this should give you the expected result:
def result(dummy_c):
a = caracter.get()
text1 = latex(a)
ax.clear()
ax.text(0.2, 0.6, "$"+text1+"$", fontsize = 6)
canvas.draw()
Related
I wrote a program to draw some plots. I want to clear the screen and reuse the same canvas to draw different plot. How should i go about it? ocanvas is my outer canvas to which i'm attaching a scrollbar. innerCanvas is the canvas I do my drawing on. The first time I press "Go" I call the function drawGraph. I want the innerCanvas to be cleared the next time I press "Go" and then call drawGraph2. Is there a way to accomplish this?. Below is my code:
(I'm a beginner in Python and thus I don't know all the concepts/functions present.)
from tkinter import *
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
def on_configure(event=None):
canvas.configure(scrollregion=canvas.bbox("all"))
def drawGraph(innerCanvas):
for i in range(5):
f = Figure(figsize=(5,5), dpi=100)
a = f.add_subplot(111)
a.plot([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],[5,6,1,3,8,9,3,5,9,7,6,5,7,3,2,9,3,5])
canvas = FigureCanvasTkAgg(f, innerCanvas)
canvas.draw()
canvas.get_tk_widget().pack(side=LEFT, fill=BOTH, expand=True)
def drawGraph2(innerCanvas):
for i in range(5):
f = Figure(figsize=(5,5), dpi=100)
a = f.add_subplot(111)
a.plot([1,2,3,4,5,6,7,8,9,10,11,12,13,14],[3,4,5,6,8,9,0,1,23,44,4,5,17,5])
canvas = FigureCanvasTkAgg(f, innerCanvas)
canvas.draw()
canvas.get_tk_widget().pack(side=LEFT, fill=BOTH, expand=True)
root=Tk()
ocanvas=Canvas(root)
innerCanvas=Canvas(canvas)
xscrollbar=Scrollbar(ocanvas, orient=HORIZONTAL)
xscrollbar.config(command=ocanvas.xview)
button=Button(root, text='Go',command= lambda: drawGraph(frame))
button.pack()
ocanvas.configure(scrollregion=ocanvas.bbox("all"))
ocanvas.config(xscrollcommand=xscrollbar.set)
xscrollbar.pack(side=BOTTOM, fill=X)
ocanvas.bind("<Configure>", on_configure)
ocanvas.pack(fill=BOTH, expand=True)
ocanvas.create_window((0,0),window=innerCanvas, anchor='nw')
root.geometry('500x500')
root.mainloop()
Any help would be appreciated.
To clear innerCanvas You can destroy its children before calling drawGraph2.
for figureCanvas in innerCanvas.winfo_children():
figureCanvas.destroy()
First I'm sorry for my bad english. I am designing a chatbot with the tkinter as an amateur. I want to add whatsapp-like balloons to the dialog window. I also want the writings to go from the bottom up in the window. I tried to do it as a canvas but it didn't happen. I tried as a label but gave an error.I'd appreciate it if you could help me with that. "TypeError: can only concatenate str (not "Canvas") to str".
The sample design I want
import tkinter as tk
from tkinter import *
import random
import re
import datetime
from tkinter import messagebox
from tkinter.font import Font
root = tk.Tk()
root.title('deneme')
root.geometry('410x600+400+100')
root.config(bg='lightblue')
buton_işlevi=StringVar(root)
buton_işlevi.set("")
#buton oluşturma ve konumu
buton = tk.Button(root, width=10, height=2, relief='raised',state='active',command=lambda :add_text(pencere,giriş,buton_işlevi))
buton.pack()
buton.place(x=310, y=550)
buton.config(text='GÖNDER', bg='lightblue', font='Verdana 8 bold')
root.bind('<Return>',lambda x:add_text(pencere,giriş,buton_işlevi))
#mesaj yazma alanı ve konumu
giriş = tk.Entry(root, textvariable=buton_işlevi,font=('NanumGothic', 12))
giriş.pack()
giriş.place(x=10, y=550, width=290, height=40)
canvas = Canvas(width=300, height=300, bg='white')
canvas.create_oval(200, 200, 300, 300, width=5, fill='red')
#pencere ve konumu
pencere = tk.Text(root, bg='white', yscrollcommand='YES', font=('NanumGothic', 12))
pencere.config(state='disabled')
pencere.pack()
pencere.place(x=10, y=10, width=390, height=530)
#bot ve user mesaj arka plan rengi
pencere.tag_config('bot_renk', background='#fccbc7', foreground='black')
pencere.tag_config('user_renk', background='yellow')
pencere.config(state='normal')
#bot karşılama mesajı
karşılama = 'Hoşgeldiniz'
soru1 = ['merhaba', 'selam']
cevap1 = ["sanada", "iyiyim"]
soru2 = ["deneme", "merhaba", "selam"]
pencere.insert('end', '\nBOT:\t')
pencere.insert('end', karşılama +'\n', 'bot_renk')
#Mesaj ayarları
def add_text(mw,st,imsg):
#mw:message window/st:state/imsg:input message
bot_mesaj=""
user_mesaj = imsg.get()
if user_mesaj in soru1:
user_mesaj='\nUSER :\t'+imsg.get()+'\n'+canvas
bot_mesaj = '\nBOT :\t'+ random.choice(cevap1)+'\n'
mw.config(state='normal')
mw.insert('end',user_mesaj, 'user_renk')
mw.insert('end',bot_mesaj, 'bot_renk')
imsg.set("")
mw.see('end')
mw.config(state='disabled')
elif user_mesaj in soru2:
user_mesaj='\nERÇİN :\t'+imsg.get()+'\n'
bot_mesaj='\nBOT :\t'+ random.choice(cevap2)+'\n'
mw.config(state='normal')
mw.insert('end',user_mesaj, 'user_renk')
mw.insert('end',bot_mesaj, 'bot_renk')
imsg.set("")
mw.see('end')
mw.config(state='disabled')
else :
user_mesaj='\nUSER:\t' +imsg.get()+'\n'
bot_mesaj='\nBOT:\t' + 'Bu kelimeyi henüz öğrenmedim' +'\n'
mw.config(state='normal')
mw.insert('end',user_mesaj, 'user_renk')
mw.insert('end',bot_mesaj, 'bot_renk')
imsg.set("")
mw.see('end')
mw.config(state='disabled')
root.mainloop()
I ran your code and there is no error. But since you mentioned about Whatsapp bubble, here is a basic version you can work on.
from tkinter import *
from datetime import datetime
root = Tk()
root.config(bg="lightblue")
canvas = Canvas(root, width=200, height=200,bg="white")
canvas.grid(row=0,column=0,columnspan=2)
bubbles = []
class BotBubble:
def __init__(self,master,message=""):
self.master = master
self.frame = Frame(master,bg="light grey")
self.i = self.master.create_window(90,160,window=self.frame)
Label(self.frame,text=datetime.now().strftime("%Y-%m-%d %H:%m"),font=("Helvetica", 7),bg="light grey").grid(row=0,column=0,sticky="w",padx=5)
Label(self.frame, text=message,font=("Helvetica", 9),bg="light grey").grid(row=1, column=0,sticky="w",padx=5,pady=3)
root.update_idletasks()
self.master.create_polygon(self.draw_triangle(self.i), fill="light grey", outline="light grey")
def draw_triangle(self,widget):
x1, y1, x2, y2 = self.master.bbox(widget)
return x1, y2 - 10, x1 - 15, y2 + 10, x1, y2
def send_message():
if bubbles:
canvas.move(ALL, 0, -65)
a = BotBubble(canvas,message=entry.get())
bubbles.append(a)
entry = Entry(root,width=26)
entry.grid(row=1,column=0)
Button(root,text="Send",command=send_message).grid(row=1,column=1)
root.mainloop()
I want the "shapefile" mentioned below in the code to be displayed inside the "sideFrame" of the tkinter window. But now, the shapefile is getting opened up in the another window which I don't want to. That is, I want to display the "shapefile" inside the right frame of the "tkinter" window.I am new to this field, so could be clear with the explanation along with the code.
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use("TkAgg") # for backend
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
def forSubmit():
if MyVar1.get()== 0 or MyVar2.get()==0:
messagebox.showwarning("Warning", "Select input files!")
fp = r"F:\ISRO\Spatial_Data\grid_jagalur_spatialjoin.shp"
data = gpd.read_file(fp)
print (type(data))
data.head()
data.plot()
plt.show(sideFrame)
middleFrame = LabelFrame(root,width=800,text="Input data")
middleFrame.grid(row=1, column=0, padx=8, pady=8, sticky=N+S+W+E)
middleFrame.grid_rowconfigure(0, weight=1)
middleFrame.grid_rowconfigure(1, weight=0)
middleFrame.grid_columnconfigure(0, weight=1)
middleFrame.grid_columnconfigure(1, weight=1)
Button6 = Button(middleFrame, text="View", command=forSubmit)
Button6.grid(row=1, column=1, padx=4, pady=4,sticky=E)
sideFrame = LabelFrame(root,width=500, bg="powder blue", text="Image")
sideFrame.grid(row=0, column=1, padx=8, pady=8, sticky=N+S+W+E, rowspan=3)
sideFrame.grid_rowconfigure(0, weight=1)
sideFrame.grid_rowconfigure(1, weight=1)
sideFrame.grid_rowconfigure(2, weight=1)
sideFrame.grid_columnconfigure(0, weight=1)
sideFrame.grid_columnconfigure(1, weight=1)
You should add a FigureCanvasTkAgg widget to your sideFrame and then try something on the following lines:
fig, ax = plt.subplots(nrows = 1, ncols = 1)
cavnas_plot = FigureCanvasTkAgg(fig, master = sideFrame)
canvas_plot.draw()
canvas_plot.get_tk_widget.grid(row = 0, column = 0)
Ensure that there is enough space for the sideFrame to be visible on the main window
I am trying to convert some code from the matplotlib documentation site that embeds a matplotlib graph into tkinter from a module containing defs into a module containing a class. This code is taken directly from matplotlib (https://matplotlib.org/gallery/user_interfaces/embedding_in_tk_sgskip.html) and works exactly as expected. However for my purposes I need this in the format of a class rather than a grouping of defs within a module. Here is the original matplotlib code:
import tkinter
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure
import numpy as np
root = tkinter.Tk()
root.wm_title("Embedding in Tk")
fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH,
expand=1)
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH,
expand=1)
def on_key_press(event):
print("you pressed {}".format(event.key))
key_press_handler(event, canvas, toolbar)
canvas.mpl_connect("key_press_event", on_key_press)
def _quit():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL
tstate
button = tkinter.Button(master=root, text="Quit", command=_quit)
button.pack(side=tkinter.BOTTOM)
tkinter.mainloop()
# If you put root.destroy() here, it will cause an error if the window
# is closed with the window manager.
It is easy enough to convert the figure creation portion of this code into a class, but I am unable to figure out how to get the on_key_press and the toolbar sections to code properly.
This is my class code, which creates the plot but all my attempts at adding the toolbar and having key presses work have failed.
class matplotlibAsClass:
def __init__(self, master):
self.master = master
self.frame = Frame(self.master)
self.create_chart()
self.frame.pack(expand=YES, fill=BOTH)
def create_chart(self):
fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
canvas = FigureCanvasTkAgg(fig, self.master)
canvas.draw()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
if __name__ == '__main__':
root = Tk()
matplotlibAsClass(root)
root.mainloop()
Any help on how to convert the full matplotlib code, where the key presses and the toolbar works, into a fully functioning class would be greatly appreciated.
Here is code I have written that does not work:
The following code has been corrected and now works properly.
class matplotlibAsClass:
def __init__(self, master):
self.master = master
self.frame = Frame(self.master)
self.create_chart()
self.frame.pack(expand=YES, fill=BOTH)
def create_chart(self):
self.master.wm_title("Embedding in Tk")
fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
canvas = FigureCanvasTkAgg(fig, self.master)
canvas.draw()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
canvas.mpl_connect("key_press_event", self.on_key_press)
toolbar = NavigationToolbar2Tk(canvas, self.master)
toolbar.update()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
self.button = Button(self.master, text="Quit",command=self._quit)
self.button.pack(side=BOTTOM)
def on_key_press(event):
print("you pressed {}".format(event.key))
key_press_handler(event, canvas, toolbar)
def _quit(self):
self.master.quit() # stops mainloop
#self.master.destroy()
if __name__ == '__main__':
root = Tk()
matplotlibAsClass(root)
root.mainloop()
when I run this code I get the following error:
File
"/Users/Me/Mee/python_db_programs/simpletestgui_sc_two.py",
line 104, in create_stockchart
canvas.mpl_connect("key_press_event", on_key_press)
NameError: name 'on_key_press' is not defined
After changing the on_key_press to self.on_key_press I get the following error:
File "/Users/Me/Mee/python_db_programs/simpletestgui_sc_two.py", line
111, in create_stockchart
self.button = Button(self.master,
text="Quit",command=self._quit())
TypeError: _quit() takes 0 positional arguments but 1 was given
After correcting the def _quit() to def _quit(self) I get the following error:
File
"/Users/Me/Mee/python_db_programs/simpletestgui_sc_two.py",
line 111, in create_stockchart
self.button = Button(self.master, text="Quit",
command=self._quit())
_tkinter.TclError: can't invoke "button" command: application has been
destroyed
Based upon the previous error I commented out the self.master.destroy() portion of the def _quit and now the chart loads and the toolbar works but the quit button doesn't actually cause the widget to quit.
The final correction, which I didn't fully catch from a previous comment was to change command=self._quit() to command=self._quit and now everything works correctly.
The problem is that I want to draw a plot by clicking on a button but it doesn't work. However, when I call draw from __init__, the plot appears on the screen.
Plotter.py
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class Plotter(FigureCanvasTkAgg):
def __init__(self, master):
self.figure = Figure(dpi=100)
super().__init__(self.figure, master=master)
self.axes = self.figure.add_subplot(111)
self.get_tk_widget().grid(column=0, row=0, sticky='nsew')
def draw(self):
self.axes.clear()
x_list = [x for x in range(0, 100)]
y_list = [x^3 for x in x_list]
self.axes.plot(x_list, y_list, color='y')
MainApplication.py
from tkinter import ttk
import tkinter as tk
import plotter
class MainApplication(ttk.Frame):
def __init__(self, master, *args, **kwargs):
super().__init__(root)
self.grid(column=0, row=0, sticky='nsew')
frame = ttk.Frame(self, borderwidth=8)
frame.grid(column=0, row=0, sticky='nsew')
frame.rowconfigure(0, weight=1)
notes = ttk.Notebook(frame)
notes.grid(column=0, row=0, sticky='nsew')
notes.rowconfigure(0, weight=1)
page = ttk.Frame(notes)
notes.add(page, text='Picture')
plot = plotter.Plotter(page)
# plot.draw() # This call updates the plot
input_frame = ttk.Frame(self)
input_frame.grid(column=1, row=0, sticky='nsew')
# this binding doesn't update the plot
button = ttk.Button(input_frame, text='Plot', \
command=lambda: plot.draw())
button.grid(column=0, row=4, columnspan=2, sticky='ew')
root = tk.Tk()
MainApplication(root)
root.mainloop()
Personally I would write this up in a single class so that we can use class attributes and methods to control everything with ease. Also you do not need a lambda here. Just save the reference to the command button and not a lambda call. That said you were also overwriting the draw method of FigureCanvasTkAgg so change the draw() method to something else.
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from tkinter import ttk
import tkinter as tk
class MainApplication(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
notes = ttk.Notebook(self)
notes.grid(column=0, row=0, sticky='nsew')
notes.rowconfigure(0, weight=1)
self.page = ttk.Frame(notes)
notes.add(self.page, text='Picture')
self.plotter()
input_frame = ttk.Frame(self)
input_frame.grid(column=1, row=0, sticky='nsew')
button = ttk.Button(input_frame, text='Plot', command=self.new_draw)
button.grid(column=0, row=4, columnspan=2, sticky='ew')
def plotter(self):
self.figure = Figure(dpi=100)
self.plot_canvas = FigureCanvasTkAgg(self.figure, self.page)
self.axes = self.figure.add_subplot(111)
self.plot_canvas.get_tk_widget().grid(column=0, row=0, sticky='nsew')
def new_draw(self):
self.axes.clear()
x_list = [x for x in range(0, 100)]
y_list = [x^3 for x in x_list]
self.axes.plot(x_list, y_list, color='y')
self.plot_canvas.draw_idle()
MainApplication().mainloop()
You overwrote the canvas' draw method without reimplementing it. But since you do not want to update your plot on every draw-event anyways, I'd suggest to call the method to update the plot differently, e.g. draw_lists. Inside draw_lists you would then need to call the draw method of the canvas (or in this case better draw_idle).
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class Plotter(FigureCanvasTkAgg):
def __init__(self, master):
self.figure = Figure(dpi=100)
super().__init__(self.figure, master=master)
self.axes = self.figure.add_subplot(111)
self.get_tk_widget().grid(column=0, row=0, sticky='nsew')
def draw_lists(self):
self.axes.clear()
x_list = [x for x in range(0, 100)]
y_list = [x^3 for x in x_list]
self.axes.plot(x_list, y_list, color='y')
self.draw_idle()
from tkinter import ttk
import tkinter as tk
class MainApplication(ttk.Frame):
def __init__(self, master, *args, **kwargs):
super().__init__(root)
self.grid(column=0, row=0, sticky='nsew')
frame = ttk.Frame(self, borderwidth=8)
frame.grid(column=0, row=0, sticky='nsew')
frame.rowconfigure(0, weight=1)
notes = ttk.Notebook(frame)
notes.grid(column=0, row=0, sticky='nsew')
notes.rowconfigure(0, weight=1)
page = ttk.Frame(notes)
notes.add(page, text='Picture')
plot = Plotter(page)
input_frame = ttk.Frame(self)
input_frame.grid(column=1, row=0, sticky='nsew')
# this binding doesn't update the plot
button = ttk.Button(input_frame, text='Plot', \
command=lambda: plot.draw_lists())
button.grid(column=0, row=4, columnspan=2, sticky='ew')
root = tk.Tk()
MainApplication(root)
root.mainloop()