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()
  • 1
    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. – Novel Jun 04 '19 at 20:36
  • You shouldn't mix pyplot with custom GUIs and there should only be one single `FigureCanvasTkAgg` instance in the game. – ImportanceOfBeingErnest Jun 04 '19 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. – Jacob St.Martin Jun 06 '19 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. – Jacob St.Martin Jun 06 '19 at 13:19
  • check this [link](https://github.com/MichaelGrupp/evo/issues/180) might be helpful – Majo_Jose Aug 14 '19 at 12:25
  • @JacobSt.Martin : did you find the answer to this problem ? I have already the same, so I would be so happy if you solved your issue and share! – Netchaiev Sep 21 '19 at 16:23

3 Answers3

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.

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
beginner
  • 85
  • 10
-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
linssab
  • 61
  • 9