Button instance has no __call__ method - python

i want to make app in python so i have just started, i want to click button and graph should be displayed !!!
But its not allowing me to do so.
code snippet:
from Tkinter import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
def schart2(stock_sym):
df
df.astype(float)
labels = ['day0','day1','day2','day3','day4','day5','day6','day7','day8','day9','day10','day11','day12','day13','day14','day15','day16','day17','day18','day19','day20','day21','day22','day23','day24','day25','day26','day27','day28','day29','day30']
df.columns=labels
plt.subplots_adjust(left=0.1, bottom=0.15, right=0.99, top=0.95)
ax=plt.imshow(df, cmap=plt.cm.get_cmap("RdPu"), interpolation="nearest",aspect="auto")
plt.xticks(range(len(labels)), labels, rotation=90, va="top", ha="center")
plt.colorbar()
plt.title("Return rate Retention")
plt.xlabel("Retention Days")
plt.ylabel("Total Days")
fig=ax.get_figure()
plt.show()
class StockChart(Frame):
def __init__(self, stock_sym=''):
Frame.__init__(self, parent=None)
self.pack(expand=YES, fill=BOTH)
self.create_widgets(stock_sym)
self.makeWidgets(stock_sym)
def create_widgets(self, stock_sym):
self.makeWidgets = tk.Button(self)
self.makeWidgets["text"] = "Hello World\n(click me)"
self.makeWidgets["command"] = self.makeWidgets
self.makeWidgets.pack(side="top")
self.quit = tk.Button(self, text="QUIT", fg="red",
command=root.destroy)
self.quit.pack(side="bottom")
def makeWidgets(self, stock_sym):
#self.f = graphData(stock_sym,12,26)
self.f = schart2(stock_sym)
self.canvas = FigureCanvasTkAgg(self.f)
self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
self.canvas.show()
if __name__ == '__main__':
StockChart('ACAD').mainloop()
And the ERROR is:
self.makeWidgets(stock_sym)
AttributeError: Button instance has no __call__ method
Am I doing this completely wrong or is there an easy way to fix this? Any help would be greatly appreciated.

Your variable
self.makeWidgets = tk.Button(self)
Has the same name as your class method
def makeWidgets(self, stock_sym):
Try first to change this

Related

How to disconnect matplotlibs event handler?

I am trying to find a way to disconnect matplotlib's event handler by using mpl_disconnect. So far I followed the instructions here and here to learn how to disconnect but unfortunately it did not work for me.
With the following code I am able to connect button_press_event to the callback function on_press by using a checkbutton. After unchecking cid prints 0 so it should be disconnected but the callback function still fires.
I am using python 3.7.4 and matplotlib 3.1.1.
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.image as mpimg
class MainApplication(Tk.Frame):
def __init__(self, parent, *args, **kwargs):
Tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
parent.iconify
parent.grid_rowconfigure(1, weight=1)
parent.grid_columnconfigure(1, weight=1)
top_frame = Tk.Frame(parent)
top_frame.grid(row=0)
mid_frame = Tk.Frame(parent)
mid_frame.grid(row=1)
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
self.ax.set_aspect('equal')
canvas = FigureCanvasTkAgg(self.fig, mid_frame)
canvas.get_tk_widget().grid(row=0, column=0, sticky="nsew")
canvas._tkcanvas.grid(row=0, column=0, sticky="nsew")
img = mpimg.imread('stinkbug.png') # insert image file here
self.ax.imshow(img)
self.fig.canvas.draw()
self.var1 = Tk.IntVar()
chkbx1 = Tk.Checkbutton(top_frame, text='connect', variable=self.var1, command=self.de_activate)
chkbx1.grid(row=0, column=0, sticky="w")
def de_activate(self):
print('checkbutton: '+str(self.var1.get()))
self.cidpress = 0
if self.var1.get() == 1:
self.cidpress = self.fig.canvas.mpl_connect('button_press_event', self.on_press)
print('on_press connected (cid='+str(self.cidpress)+')')
else:
self.fig.canvas.mpl_disconnect(self.cidpress)
print('on_press disconnected (cid='+str(self.cidpress)+')')
def on_press(self, event):
if event.inaxes != self.ax: return
print('button pressed')
if __name__ == '__main__':
root = Tk.Tk()
MainApplication(root).grid(row=0, column=0, sticky="nsew")
root.mainloop()
To disconnect, you must pass the original cid to mpl_disconnect, but you're resetting self.cidpress before the if .. else .. block, so you're always requesting the disconnection of cid 0. Remove self.cidpress = 0 and place it right after self.fig.canvas.mpl_disconnect(self.cidpress):
def de_activate(self):
print('checkbutton: '+str(self.var1.get()))
if self.var1.get() == 1:
self.cidpress = self.fig.canvas.mpl_connect('button_press_event', self.on_press)
print('on_press connected (cid='+str(self.cidpress)+')')
else:
self.fig.canvas.mpl_disconnect(self.cidpress)
self.cidpress = 0 # <<<<<<<<<<<<<<<<<<<<
print('on_press disconnected (cid='+str(self.cidpress)+')')

Behavior of passed subplot reference different in direct reference and as list

I am trying to write a function to update a matplotlib chart following a combobox selection. I don't understand a difference in behavior. In the full program and in the streamlined version below, I create a subplot "a" and can pass it to a function ("tester") and it will modify the subplots attributes as expected. But if I pass the subplot as an entry in a lambda function to a Comboboxselected entry, it does not work. Why the difference?
When the following is run, the x-axis of the plot reads "XAXIS RESET BY TESTER", as expected given the call to tester(). When a new combobox entry is selected, update_chart() prints the choice in the combobox correctly, prints the accompanying test parameter "ZERO" correctly, but the x-axis on the chart does not change. Why the difference in behaviors?
The following stand-alone code reproduces the problem:
# -*- coding: utf-8 -*-
from tkinter import ttk
import tkinter as tk
from tkinter.scrolledtext import ScrolledText
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg,
NavigationToolbar2TkAgg)
from matplotlib.figure import Figure
def make_chart_page(nb, chartPage):
labelFrameChart = tk.LabelFrame(chartPage, text="Chart control:")
labelFrameChart.pack(side="left", fill="y", padx=5, pady=5)
comboChart = ttk.Combobox(labelFrameChart, values=["Foos", "Bars", "Widgets"], width=25)
comboChart.pack(anchor="w", padx=5)
f = Figure(figsize=(7,5), dpi=100)
a = f.add_subplot(111)
canvas = FigureCanvasTkAgg(f, chartPage)
canvas.show()
canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
data = [ "ZERO", a ]
comboChart.bind("<<ComboboxSelected>>", lambda event, args=data: callback(event, args))
tester(a)
def tester(a):
a.set_xlabel("XAXIS RESET BY TESTER")
def update_chart(combo, var0, chart):
print ("Combobox choice is: ", combo)
print ("Args[0] is: ", var0)
chart.set_xlabel("Xaxis reset by Update_Chart")
def callback(eventObject, args):
update_chart(eventObject.widget.get(), args[0], args[1])
def demo():
root = tk.Tk()
nb = ttk.Notebook(root)
chartPage = ttk.Frame(nb)
make_chart_page(nb, chartPage)
nb.add(chartPage, text='Charts')
nb.pack(expand=1, fill="both")
root.mainloop()
if __name__ == "__main__":
demo()
Thank you,
Randy
You simply need to redraw the canvas again by calling canvas.draw_idle().
def make_chart_page(nb, chartPage):
...
global canvas
canvas = FigureCanvasTkAgg(f, chartPage)
...
def update_chart(combo, var0, chart):
print("Combobox choice is: ", combo)
print("Args[0] is: ", var0)
chart.set_xlabel("Xaxis reset by Update_Chart")
canvas.draw_idle()

How to prevent multiple graph plot in tkinter canvas

Im using function plot_graph() which is triggered everytime you open Graph window, my question is: How to plot graph with this function everytime on same place?
plot_graph function looks like this:
def plot_graph(self,event):
df_1 = self.controller.df_1
df_2 = self.controller.df_2
df_3 = self.controller.df_3
df_4 = self.controller.df_4
f = Figure(figsize=(5, 5), dpi=100)
a = f.add_subplot(111)
a.plot(df_1['mean'])
a.plot(df_2['mean'])
a.plot(df_3['mean'])
a.plot(df_4['mean'])
a.legend(['bsl morning', '1st expo', 'bsl noon', '2nd expo'])
canvas = FigureCanvasTkAgg(f, self)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)
And im calling this function with self.bind("<<ShowGraph>>", self.plot_graph)
After second call of this function program starts create second graph under first one, on and on. Output of program, as you can see on image.I want to prevent this and have only one graph.
Thank you for help!
I believe you have two choices:
destroy the canvas before creating a new one. See Using tkinter -- How to clear FigureCanvasTkAgg object if exists or similar?
(I think this is a better method) create the figure/canvas in the init section, and reuse those objects to plot new data:
The following demonstrates option #2:
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter
import numpy as np
class MyClass:
def __init__(self, frame):
self.frame = frame
self.fig = Figure(figsize=(5, 5), dpi=100)
self.ax = self.fig.add_subplot(111)
self.canvas = FigureCanvasTkAgg(self.fig, self.frame)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=True)
self.button = tkinter.Button(self.frame, text="plot", command=self.plot_graph)
self.button.pack()
def plot_graph(self):
x, y = np.random.random(size=(2, 10))
self.ax.cla()
self.ax.plot(x, y)
self.canvas.draw()
root = tkinter.Tk()
MyFrame = tkinter.Frame(root)
MyClass(MyFrame)
MyFrame.pack()
root.mainloop()

Tkinter, error maximum recursion depth exceeded

I am having trouble writting a tkinter application with matplotlib that updates dinamicaly. I create a plot and use it inside the tkinter window. Then the plot is updated every 50ms with a tk.after() method, which works fine in other applications I have tryed so far. But in my application everything seems to be working until after some time (a minute or so) I get an error:
RecursionError: maximum recursion depth exceeded while calling a Python object
The code is:
import matplotlib
#matplotlib.use('TkAgg')
from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
# implement the default mpl key bindings
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure
import sys
import time
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
import numpy as np
import matplotlib.pyplot as plt
import math
class MainWindow():
#----------------
def __init__(self, root):
self.index=0
self.root=root
self.fig, self.ax = plt.subplots()
self.line, = self.ax.plot(np.random.randn(100))
#plt.show(block=False)
# a tk.DrawingArea
self.canvas = FigureCanvasTkAgg(self.fig, master=root)
self.canvas.show()
self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
self.toolbar = NavigationToolbar2TkAgg(self.canvas, root)
self.toolbar.update()
self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
self.canvas.mpl_connect('key_press_event', self.on_key_event)
self.display = Tk.Label(root, text="") # we need this Label as a variable!
self.display.pack()
self.button1 = Tk.Button(master=root, text='Quit', command=self._quit)
self.button1.pack(side=Tk.BOTTOM)
global w
w=2*math.pi
self.button2 = Tk.Button(master=root, text='Increase frecuency', command=self.button2_event)
self.button2.pack(side=Tk.BOTTOM)
#A simple clock
global miliseconds
global t
t=time.time()
self.update_clock()
print('going to the next stop')
self.root.mainloop()
def on_key_event(event):
print('you pressed %s' % event.key)
key_press_handler(event, self.canvas, toolbar)
def _quit(self):
self.root.quit() # stops mainloop
self.root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
def button2_event(self):
global t
global w
w+=2*3.1416
def update_clock(self):
global t
mili=str(math.floor(1000*(t-time.time())))+' ms'
t=time.time()
now = time.strftime("%H:%M:%S"+'-'+mili)
self.display.configure(text=now)
N=100
y=np.sin(4*math.pi*(np.array(range(N))/N)+t*w)
x=range(N)
self.line.set_ydata(y)
self.line.set_xdata(x)
self.ax.relim()
self.ax.autoscale()
#☺fig.canvas.update()
#fig.canvas.flush_events()
self.canvas.show()
self.canvas.flush_events()
self.root.after(50, self.update_clock()) #<------ERROR HERE!------
root = Tk.Tk()
root.wm_title("Embedding in TK")
MainWindow(root)
Change self.root.after(50, self.update_clock()) to self.root.after(50, self.update_clock), after
after(delay_ms, callback=None, *args)
Registers an alarm callback that is called after a given time.

Python: When do I execute the class->function-> Parenthesis. & Matplotlib figure wont show

I am stuck. I have tried to code a figure into Tk from Matplotlib. I have done it before, but for some reason this is just not working.
I also don't understand when to use "()" to call a function and when not too:
#Example
def _Example(self)
print "Blah blah"
# Do I call?
self._Example # or
self._Example()
Sometimes one works and one doesn't?? AKA in the case of "events" in my code _UpdateCanvas??
That would be helpful, because now I can't seem to find out why my figure isn't loading?
# ----------------------- Import <<
from Tkinter import *
import matplotlib
import numpy as np
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
# ----------------------- Class <<
class App(Frame):
def __init__(self,master=None):
Frame.__init__(self,master)
self._job = None
self.canvas = None
self.Flag_Zoom = False
self.pack()
self._Data()
self._GUI_Design()
# Create Canvas + Load Canvas
self._Figure(self.Arm,self.Tri)
self.canvas = FigureCanvasTkAgg(self.f,self.LF_Graph)
self.canvas.draw()
self.canvas.show()
def _GUI_Design(self):
# FRAME
self.LF_Control = LabelFrame(self, text='Angle Controls', width=400, height=100 )
self.LF_Graph = LabelFrame(self, text='Figure', width=400, height=400)
self.LF_Control.grid(row=0, column=0, padx=5,pady=1)
self.LF_Graph.grid(row=1, column=0,padx=5,pady=3)
# LABELS
self.LB_Info = Label(self.LF_Control,text="MOTION CONTACT EXAMPLE\nwith spoiler controls\n2013-07-23", justify=LEFT)
self.LB_SP = Label(self.LF_Control, text="Spoiler:")
self.LB_FP = Label(self.LF_Control, text="Triangle:")
# SLIDERS
self.SpScale = Scale(self.LF_Control, from_=0, to=45, orient=HORIZONTAL, length=350, resolution=1, command=self._UpdateCanvas, tickinterval=5)
self.TrScale = Scale(self.LF_Control, from_=0, to=180, orient=HORIZONTAL, length=350, resolution=5, command=self._UpdateCanvas, tickinterval=30)
# BUTTONS
self.Bup = Button(self.LF_Control, text=" ^ \n | ", command=self._Bup)
self.Bdn = Button(self.LF_Control, text=" | \n V ", command=self._Bdn)
self.Blf = Button(self.LF_Control, text=" <- " , command=self._Blf)
self.Brt = Button(self.LF_Control, text=" -> " , command=self._Brt)
# GRIDS
self.LB_Info.grid(row=0, column=0,padx=1,pady=1,columnspan=2)
self.LB_SP.grid(row=1, column=0,padx=1,pady=1)
self.LB_FP.grid(row=2, column=0,padx=1,pady=1)
self.SpScale.grid(row=1, column=1,padx=1,pady=1)
self.TrScale.grid(row=2, column=1,padx=1,pady=1)
self.Bup.grid(row=0, column=4 ,padx=1,pady=1)
self.Bdn.grid(row=2, column=4 ,padx=1,pady=1)
self.Blf.grid(row=1, column=3 ,padx=1,pady=1)
self.Brt.grid(row=1, column=5 ,padx=1,pady=1)
print "Graphics Loaded"
def _Figure(self,Arm,Tri):
self.f = plt.figure(1)
plt.axis([-500,500,-500,500])
plt.axes().set_aspect('equal', 'datalim')
plt.plot(Arm[0],Arm[1],"r")
plt.plot(Tri[0],Tri[1],"g")
print "figure set",Arm,Tri
def _UpdateCanvas(self,event):
print "def:_UpdateCanvas"
self._job = self.after(100, self._Execute) #miliseconds
if self._job:
self.after_cancel(self._job)
def _Data(self):
self.Arm = [[0,100],[0,100]]
self.Tri = [[50,150,100,50],[-50,-40,-120,-50]]
def _Execute(self):
print "def:_Execute"
self.SpAngle = self.SpScale.get()
self.TrAngle = self.TrScale.get()
self._Figure(self.Arm,self.Tri)
self.canvas.draw()
self.canvas.show()
# Button Commands
def _Bup(self):
self.Tri[1] = [i+5 for i in self.Tri[1]]
print "Button: UP"
self._Execute()
def _Bdn(self):
self.Tri[1] = [i-5 for i in self.Tri[1]]
print "Button: DOWN"
self._Execute()
def _Blf(self):
self.Tri[0] = [i-5 for i in self.Tri[0]]
print "Button: LEFT"
self._Execute()
def _Brt(self):
self.Tri[0] = [i+5 for i in self.Tri[0]]
print "Button: RIGHT"
self._Execute()
# Execute App
root = Tk()
root.title("Contact")
Exe = App(master=root)
root.mainloop()
Please me understand why no figures are loading?
You always use parenthesis to call a function. You never use parenthesis if you are using the function as a parameter to a command attribute, or when using it in a bind statement.
The trick is knowing when you want to call a function, and when you want to use a reference to the function. With respect to Tkinter, the value of a command attribute, and the second argument to a bind statement must always be a reference to a function that will be called later.

Categories

Resources