2

I am trying to use tkinter and matplotlib to create an interface to pair with some lab equipment, but right now I am just loading in some old test data. I am trying to add in the NavigationToolbar2Tk navigation bar.

When I run the program the bar pops up properly but every time I click one of the buttons I get the error 'FigureCanvasTkAgg' object has no attribute 'manager'. The funny thing is that all of the buttons except for save will still perform their operations, they just continually spit out the errors. I have tried creating a seperate frame for the navigation box but that hasn't worked.

import tkinter
import matplotlib
matplotlib.use('TkAgg')
from tkinter import Tk
from tkinter import Label as label
from tkinter import Message
from tkinter import Button as button
from tkinter import Canvas as canvas
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import pyplot as plt
from tkinter import Entry as entry
from matplotlib import style
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
import url

dataset = url.open_and_convert_csv("Wednesday_4pm_107_2_Blue.csv")

data = dataset[2:]

x = []
y = []
for row in data:
    strain = row[3]
    x.append(strain)
    stress = row[4]
    y.append(stress)

plt.grid(True, which='major', axis='both')
plt.plot(x, y)
figure = plt.gcf()

def tensile_graph():

    canv.get_tk_widget().grid(column = 1, row = 1)


def title():
    title_text = title_box.get()
    title_box.delete(0,len(title_text))
    plt.title(title_text)
    figure = plt.gcf()
    canv = FigureCanvasTkAgg(figure, master=top)
    canv.get_tk_widget().grid(column=1, row=1)

def x_ax():
    x_ax_text = x_ax_box.get()
    x_ax_box.delete(0, len(x_ax_text))
    plt.xlabel(x_ax_text)
    figure = plt.gcf()
    canv = FigureCanvasTkAgg(figure, master=top)
    canv.get_tk_widget().grid(column=1, row=1)

def y_ax():
    y_ax_text = y_ax_box.get()
    y_ax_box.delete(0, len(y_ax_text))
    plt.ylabel(y_ax_text)
    figure = plt.gcf()
    canv = FigureCanvasTkAgg(figure, master=top)
    canv.get_tk_widget().grid(column=1, row=1)


top = tkinter.Tk()
top.geometry('1000x600+30+30')

canv = FigureCanvasTkAgg(figure, master=top)

tensile_graph()

options_frame = tkinter.Frame(top)
options_frame.grid(row = 1, column = 0)

title_box = entry(options_frame)
title_box.grid(row = 1, column = 0)
text = title_box.get()
title_button = button(options_frame,text='Apply',command = title)
title_button.grid(row = 1, column = 1)
title_label = label(options_frame,text='Title')
title_label.grid(row = 0, column = 0)

x_axlabel = label(options_frame,text='X Axis Label')
x_axlabel.grid(row = 2, column = 0)
x_ax_box = entry(options_frame)
x_ax_box.grid(row = 3, column = 0)
x_ax_button = button(options_frame, text = 'Apply', command = x_ax)
x_ax_button.grid(row = 3, column = 1)

y_axlabel = label(options_frame,text='Y Axis Label')
y_axlabel.grid(row = 4, column = 0)
y_ax_box = entry(options_frame)
y_ax_box.grid(row = 5, column = 0)
y_ax_button = button(options_frame, text = 'Apply', command = y_ax)
y_ax_button.grid(row = 5, column = 1)


toolbar_frame = tkinter.Frame(top)
toolbar_frame.grid(column = 1, row = 1)
toolbar = NavigationToolbar2Tk(canv,toolbar_frame)
toolbar.update()
canv._tkcanvas.grid(row=1, column=1)



top.mainloop()
6
  • 2
    Why would you rename the tkinter classes like Button, Label, etc to the lowercase versions? It makes your code MUCH harder for experienced programmers to read. Commented Jun 4, 2019 at 20:36
  • You shouldn't mix pyplot with custom GUIs and there should only be one single FigureCanvasTkAgg instance in the game. Commented Jun 4, 2019 at 21:09
  • Novel thanks for the pointer I realized that after I posted this and have changed my code accordingly. @ImportanceOfBeingEnest I don't understand the reasoning behind your suggestions. Pyplot is just a structure built within matplotlib Figures so when I call plt.gcf() it should pull the current Figure object, and I need multiple instances of FigureCanvasTkAgg to update the graph after new input has been recieved unless there is a better way to update the graph. Commented Jun 6, 2019 at 13:19
  • I have also gone through and added a lot of structure because my code was messy before, but I still couldn't get the toolbar to work so I ended up coding my own save button and plan to work on the other buttons. However, it would still be much easier if I could get this working. Commented Jun 6, 2019 at 13:19
  • check this link might be helpful Commented Aug 14, 2019 at 12:25

4 Answers 4

2

I've managed to fix this error. It's actually a bug in NavigationToolbar2Tk class. If you want to fix it you have to modify their code yourself. You only need to change one line of code in the class NavigationToolbar2Tk.

  1. Navigate to class NavigationToolbar2Tk.
  2. Navigate to method def set_cursor(self, cursor).
  3. Change "window = self.canvas.manager.window" to "window = self.window"

You won't see the error again.

Sign up to request clarification or add additional context in comments.

Comments

0

I had the same problem and also when I hovered the mouse around the plot I continuously got errors, I found out that I have to downgrade my matplotlib. Here are the versions that solved my problem:

python 3.7.3, matplotlib 2.2.2

To downgrade your matplotlib version, open the prompt and write:

conda install matplotlib == 2.2.2

Comments

0

The answer to your problem can be solved looking the question How to get FigureCanvasTkAgg to work with Scrollbar

It seems that you need to access to the Tk widget by calling the method FigureCanvasTkAgg.get_tk_widget()

self.canvas=FigureCanvasTkAgg(fig, master=self.frame)
self.canvas.get_tk_widget().config(bg='#FFFFFF',scrollregion=(0,0,500,500))
self.canvas.get_tk_widget().config(width=300,height=300)
self.canvas.get_tk_widget().config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set)
self.canvas.get_tk_widget().grid(row=0, column=0, sticky=W+E+N+S)

Comments

-1

Blockquote I've managed to fix this error. It's actually a bug in NavigationToolbar2Tk class. If you want to fix it you have to modify their code yourself. You only need to change one line of code in the class NavigationToolbar2Tk.

Vincent's answer works a charm. As I cannot add a direct comment to his answer, I'm adding here which file to modify:

<python_installation>\Lib\site-packages\matplotlib\backends\_backend_tk.py

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.