I am trying to make a TKinter app that displays a graph made with networkx, using FigureCanvasTkAgg, But the plot it not displayed, only a blank white square is displayed. Here is my program:
root = Tk()
root.wm_protocol('WM_DELETE_WINDOW', root.quit)
canvas = FigureCanvasTkAgg(fig1, master=root)
#canvas.show()
canvas.get_tk_widget().place(relx=.5,rely=.4,anchor="center")
root.title("Item Search")
root.title_font = font.Font(family='Helvetica', size=30, weight="bold", slant="italic")
root.configure(background="#00FFFF")
label = Label(root, text = "Item Search", bg="#236B8E",fg="#67C8FF", height=2, width=root.winfo_height(),font=("Courier", 25))
label.pack(side=TOP,fill=X)
button1 = Button(root, text = "Load User Items", command = lambda:get_user_items(button2),height=2,width=11)
button1.place(relx=.5,rely=.7,anchor="center")
button2 = Button(root, text="Find the Shortest way", comman = find_shortest_way, height=2,width=15,state="disabled")
button2.place(relx=.5,rely=.9,anchor="center")
init()
init() function:
item_db = pd.read_csv("all_items.csv")
item_dict={}
for shelf in item_db:
for item in item_db[shelf]:
if shelf != np.nan:
item_dict[item] = int(shelf)
store.add_node(0,pos=(1,1))
store.add_node(1,pos=(1,0.5))
store.add_node(2,pos=(1,0))
store.add_node(3,pos=(2,0.5))
store.add_node(4,pos=(2,0))
store.add_node(5,pos=(3,1))
store.add_node(6,pos=(3.5,0.5))
store.add_node(7,pos=(4,0))
store.add_node(8,pos=(4,2))
store.add_node(9,pos=(5,2))
store.add_node(10,pos=(5,0))
store.add_edge(0,1,weight=1)
store.add_edge(1,2,weight=1)
store.add_edge(1,3,weight=1)
store.add_edge(3,4,weight=1)
store.add_edge(3,7,weight=2)
store.add_edge(3,6,weight=1)
store.add_edge(3,5,weight=2)
store.add_edge(5,6,weight=1)
store.add_edge(5,8,weight=2)
store.add_edge(6,8,weight=3)
store.add_edge(7,10,weight=1)
store.add_edge(8,9,weight=1)
store.add_edge(8,7,weight=4)
pos=nx.get_node_attributes(store,'pos')
nx.draw(store,pos,with_labels=True)
labels = nx.get_edge_attributes(store,'weight')
nx.draw_networkx_edge_labels(store,pos,edge_labels=labels)
plt.axis('off')
fig1.canvas.draw()
How do I display the plot? what am I doing wrong?
In this minimal example I have to use nx.draw(..., ax=fig.gca() ) to display graph
import tkinter
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import networkx as nx
root = tkinter.Tk()
fig = plt.Figure()
#sub = fig.add_subplot('111')
canvas = FigureCanvasTkAgg(fig, master=root)
#canvas.draw()
canvas.get_tk_widget().pack() #fill='both', expand=True)
G = nx.dodecahedral_graph()
ax = fig.gca() # it can gives list of `ax` if there is more subplots.
nx.draw(G, ax=ax)
tkinter.mainloop()
Other example which display NetworkX with other standard plots.
import tkinter
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import networkx as nx
root = tkinter.Tk()
fig = plt.Figure()
sub1 = fig.add_subplot('311')
sub2 = fig.add_subplot('312')
sub3 = fig.add_subplot('313')
canvas = FigureCanvasTkAgg(fig, master=root)
#canvas.draw()
canvas.get_tk_widget().pack() #fill='both', expand=True)
data = [1, 3, 2, 4]
sub1.plot(data)
G = nx.dodecahedral_graph()
nx.draw(G, ax=sub2)
data = [1, 3, 2, 4]
sub3.plot(data)
tkinter.mainloop()
Related
I have the following code for a counter with two buttons, one to increase the count and the other to decrease it. The count is a label containing a number. The graph that appears with the buttons is supposed to visualise the history of the counted number ie. x axis is the index number of results_table and the y axis is the number that appears in the count. The buttons and the count work but the graph doesn't show with the following code. There is obviously something I am missing to get the graph to update. Here's the code:
import tkinter
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class App:
def __init__(self, master):
# Create a container
frame = tkinter.Frame(master)
# Create 2 buttons
self.button_left = tkinter.Button(frame,text="-", command=self.decrease, bg = 'red', fg = 'white')
self.button_left.pack(side="left")
self.button_right = tkinter.Button(frame,text="+", command=self.increase, bg = 'green', fg = 'white')
self.button_right.pack(side="right")
self.label_value = tk.Label(frame, text = '0')
self.label_value.pack(side = "bottom")
fig = Figure()
ax = fig.add_subplot(111)
self.line, = ax.plot(0)
self.canvas = FigureCanvasTkAgg(fig,master=master)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side='top', fill='both', expand=1)
frame.pack()
result_table = []
def decrease(self):
value = int(self.label_value["text"])
self.label_value["text"] = f"{value - 1}"
result_table.append(self.label_value['text'])
x, y = self.line.get_data('result_table')
self.canvas.draw()
def increase(self):
value = int(self.label_value["text"])
self.label_value["text"] = f"{value + 1}"
result_table.append(self.label_value['text'])
x, y = self.line.get_data('result_table')
self.canvas.draw()
root = tkinter.Tk()
app = App(root)
root.mainloop()
Any help graetly appreciated.
Matt
so I solved your problem, but it is not a straight forward answer/solution.
First of all you designed your GUI quiet good! I just wouldn't use pack() but I prefer grid().
Next, I had to delete your class, because I never used tkinter with a class. Maybe you will be able to put it back in.
So what I did:
As already mentioned by Matiiss, you don't really use your x and y values to plot your figure. Your result_table on the other hand just works fine and stores all values created!
So you have to plot them as y values and your x values are basically dependent on the length of your result_table len(result_table). For this part I used numpy to always generate an array of the appropriate length.
Furthermore, I created an extra container fig_frame inside the root, where I always display the figure.
This code worked for me:
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np
def decrease():
value = int(label_value["text"])
label_value["text"] = f"{value - 1}"
result_table.append(label_value['text'])
x = np.arange(len(result_table))
y = result_table
create_fig(x, y)
def increase():
value = int(label_value["text"])
label_value["text"] = f"{value + 1}"
result_table.append(label_value['text'])
x = np.arange(len(result_table))
y = result_table
create_fig(x, y)
def create_fig(x, y):
fig = Figure()
ax = fig.add_subplot(111)
line, = ax.plot(x, y)
canvas = FigureCanvasTkAgg(fig, fig_frame)
canvas.draw()
canvas.get_tk_widget().grid(row=0, column=0)
root = tk.Tk()
# Create a container
frame = tk.Frame(root)
fig_frame = tk.Canvas(root, height=650, width=650, borderwidth=1, relief='ridge')
fig_frame.pack()
# Create 2 buttons
button_left = tk.Button(frame, text="-", command=decrease, bg='red', fg='white')
button_left.pack(side="left")
button_right = tk.Button(frame, text="+", command=increase, bg='green', fg='white')
button_right.pack(side="right")
label_value = tk.Label(frame, text='0')
label_value.pack(side="bottom")
fig = Figure()
ax = fig.add_subplot(111)
line, = ax.plot(0)
canvas = FigureCanvasTkAgg(fig, fig_frame)
canvas.draw()
canvas.get_tk_widget().grid(row=0, column=0)
frame.pack()
result_table = []
root.mainloop()
Keep going like this! You really already did a great work and even if my code looks different to your code, most parts are just rearranged!
How I would achieve that the first point that I plot isn't (0,0), (determined by line1, = ax1.plot([0], [0]), but the point that is calculated by func_A in first iteration of update_plot() function.
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt
from matplotlib import style
import matplotlib
matplotlib.use("Agg")
root = tk.Tk()
root.title("Graph")
#root.geometry("800x400")
# progress label, pause and resume buttons
frame = tk.Frame(root)
frame.pack(fill="x", side=tk.TOP)
progress = tk.Label(frame)
progress.pack(side="left")
is_paused = tk.BooleanVar() # variable to hold the pause/resume state
tk.Button(frame, text="Pause", command=lambda: is_paused.set(True)).pack(side="right")
tk.Button(frame, text="Resume", command=lambda: is_paused.set(False)).pack(side="right")
# the plot
fig = plt.figure(figsize=(10, 5), dpi=100)
canvas = FigureCanvasTkAgg(fig, master=root)
toolbar = NavigationToolbar2Tk(canvas, root)
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
plt.grid("both")
style.use("ggplot")
a = 1
ax1 = plt.subplot(111)
line1, = ax1.plot([0], [0])
def func_A(a, x):
import numpy
data_x = numpy.arange(0, x)
data_y = a * numpy.sin(data_x/5)
return data_x, data_y
# function to update ploat
def update_plot(k=0):
if not is_paused.get():
progress["text"] = f"iteration: {k}"
data_x, data_y = func_A(a, k)
#print("iteration", k)
#print("data_x", data_x)
#print("data_y", data_y)
line1.set_xdata(data_x)
line1.set_ydata(data_y)
ax1.set_ylim([-1, 1])
ax1.set_xlim([0, 100])
plt.grid("both")
canvas.draw()
canvas.flush_events()
k += 1
if k <= 100:
# update plot again after 10ms. You can change the delay to whatever you want
root.after(10, update_plot, k)
update_plot() # start updating plot
root.mainloop()
Plot displaying properly
x=[]
y=[]
figure = Figure(figsize=(5, 4), dpi=100)
plot = figure.add_subplot(1, 1, 1)
figure.suptitle(Date, fontsize=12)
plot.plot(x, y, color="blue")
cursor = Cursor(plot,horizOn=True,vertOn=False,color="green",linewidth=2.0)
canvas = FigureCanvasTkAgg(figure, root)
canvas.get_tk_widget().grid(column=0, row=3,columnspan=4,pady = 4, padx=4)
cursor = Cursor() takes ax and it seems i cant put plot.axes
You need to create the Cursor instance after creating the canvas:
canvas = FigureCanvasTkAgg(figure, root)
canvas.get_tk_widget().grid(column=0, row=3,columnspan=4,pady = 4, padx=4)
cursor = Cursor(plot, horizOn=True, vertOn=False, color="green", linewidth=2.0)
Full example code:
import tkinter as tk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
from matplotlib.widgets import Cursor
Date = "2021-06-01"
root = tk.Tk()
x = []
y = []
figure = Figure(figsize=(5, 4), dpi=100)
plot = figure.add_subplot(1, 1, 1)
#print(plot)
figure.suptitle(Date, fontsize=12)
plot.plot(x, y, color="blue")
canvas = FigureCanvasTkAgg(figure, root)
canvas.get_tk_widget().grid(column=0, row=3,columnspan=4,pady = 4, padx=4)
# pack_toolbar=False will make it easier to use a layout manager later on.
toolbar = NavigationToolbar2Tk(canvas, root, pack_toolbar=False)
toolbar.update()
toolbar.grid(sticky="ew")
cursor = Cursor(plot, useblit=True, horizOn=True, vertOn=True, color="green", linewidth=2.0)
root.mainloop()
And the output:
I'm trying to have a button that plots a graph in tkinter. The graph to be plotted is a matplotlib.image.AxesImage
the current code just plots a blank graph and I cant figure out why
can anyone help?
def plot_gui():
fig = plt.Figure(figsize=(6,5), dpi=100)
ax = fig.add_subplot(111)
chart_type = FigureCanvasTkAgg(fig, tab2)
ax = fo2.plotgas()
canvas = FigureCanvasTkAgg(ax,master=tab2)
#canvas.show()
canvas.get_tk_widget().grid(row=9,column=9)
#canvas.draw()
the fo2.plotgas() just produces the figure that I'm trying to display
EDIT here is the minimum runnable example
import math as m
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import tkinter as tk
import mpl_interactions.ipyplot as iplt
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
from tkinter import ttk
from ttkthemes import ThemedTk
class fo2():
def gas_absolute(T=1000,absolute=-12,P=1):
fO2 = (10**absolute)
R = 0.00198726
TK = T + 273.18
RK = (R*TK)
dG1 = (62.110326 -(2.1444460*10**-2)*(T) +(4.720325*10**-7)*(T**2) -(4.5574288*10**-12)*(T**3) -(7.3430182*10**-15)*(T**4))
K1 = m.exp(-dG1/(R*TK))
dG2 = (62.110326 +(7.3219457*10**-4)*(T) -(3.416474*10**-7)*(T**2) +(4.7858617*10**-11)*(T**3))
K2 = m.exp(-dG2/(R*TK))
Rm = (K1-(3*K1*fO2)-(2*fO2**(3/2)))/(2*K1*fO2 + fO2 + (fO2**(3/2)) + (fO2**(1/2)))
VolCO2 = 100/(1+Rm) # in percent CO2
return(VolCO2)
def plotgas(Tmin=800,Tmax=1300,fbottom=-16,ftop=-8,buff=[],Temp=1200,F=-11):
Dt=Tmax-Tmin
Df=100*np.abs(fbottom-ftop)
z=np.zeros((Dt,(Df)))
x=np.zeros((Dt,(Df)))
y=np.zeros((Dt,(Df)))
for i in range(Dt):
for j in range(Df):
t = Tmin+i
f = ftop-(j/100)
c = fo2.gas_absolute(t,f,1)
x[i,j]=t
y[i,j]=f
z[i,j]=c
z=np.rot90(z,k=4)
# f, (ax1,ax2) = plt.subplots(1, 2, figsize=(4,8))
# figt = ax1.imshow(x,cmap='tab20c')
# figf = ax2.imshow(y,cmap='tab20c')
# figure(num=2, figsize=(12, 8), dpi=480, facecolor='w', edgecolor='k')
fig = plt.imshow(z,extent=[Tmin,Tmax,fbottom,ftop],aspect=50,cmap='Greys')
plt.colorbar().set_label('Volume of $CO_2$')
plt.xlabel('Temperature $^\circ$C')
plt.ylabel('$fO_2$')
if 'FMQ' in buff:
plt.plot(np.linspace(Tmin,Tmax),fo2.FMQ(np.linspace(Tmin,Tmax)),color='C0',lw=1,ls='-',label='FMQ')
if 'NNO' in buff:
plt.plot(np.linspace(Tmin,Tmax),fo2.NNO(np.linspace(Tmin,Tmax)),color='C1',lw=1,ls='--',label='NNO')
if 'IW' in buff:
plt.plot(np.linspace(Tmin,Tmax),fo2.IW(np.linspace(Tmin,Tmax)),color='C2',lw=1,ls=':',label='IW')
if 'CCO' in buff:
plt.plot(np.linspace(Tmin,Tmax),fo2.CCO(np.linspace(Tmin,Tmax)),color='C3',lw=1,ls='-',label='COO')
if 'CoCoO' in buff:
plt.plot(np.linspace(Tmin,Tmax),fo2.CoCoO(np.linspace(Tmin,Tmax)),color='C4',lw=1,ls='--',label='CoCoO')
if 'MH' in buff:
plt.plot(np.linspace(Tmin,Tmax),fo2.MH(np.linspace(Tmin,Tmax)),color='C5',lw=1,ls=':',label='MH')
plt.axvline(x=Temp, color='r',lw=1)
plt.axhline(y=F, color='r',lw=1)
plt.legend()
plt.xlim(Tmin,Tmax)
plt.ylim(fbottom,ftop)
return fig
root = ThemedTk(theme='clam')
#root = tk.Tk()
root.title('Oxygen Fugacity')
root.geometry("500x400")
style = ttk.Style(root)
style.theme_use('scidpurple')
tabs = ttk.Notebook(root)
tab1 = ttk.Frame(tabs)
tab2 = ttk.Frame(tabs)
tab3 = ttk.Frame(tabs)
tab4 = ttk.Frame(tabs)
tabs.add(tab1, text ='Buffers')
tabs.add(tab2, text ='Gas Mixes')
tabs.add(tab3, text ='Plotting')
tabs.add(tab4, text ='Measure')
tabs.grid(row=0,column=0)
def gasmix_abs_GUI():
T = Temp_input_tab2_abs.get()
fug = fo2_input_tab2_abs.get()
volco2output=str(round(fo2.gas_absolute(T,fug),3))
tk.Label(tab2,text=volco2output).grid(row=5,column=1,padx=(10,10),pady=(0,10))
def plot_gui():
fig = plt.Figure(figsize=(6,5), dpi=100)
ax = fo2.plotgas()
canvas = FigureCanvasTkAgg(ax,master=tab2)
canvas.show()
canvas.grid(row=9,column=9)
buffers = ['NNO','FMQ','IW','MH','CoCoO','CCO']
plot = ttk.Button(tab2, text='Plot', command=lambda: plot_gui()).grid(row=7,column=1,padx=(10,10),pady=(0,10))
root.mainloop()
The error is
AttributeError: 'AxesImage' object has no attribute 'set_canvas'
I have a code here.
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import matplotlib
import math
import numpy as np
root = tk.Tk()
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.spines['left'].set_position('center')
ax.spines['bottom'].set_position('center')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
x = np.linspace(3,-3,10000)
p = np.sin(x)
w = np.sin(2*x)
l = np.sin(x)/x
c = np.cos(1/x)
r = np.tan(x)
ur = np.cos(x)/x
def firstx():
plt.plot(x, p, 'p-', label = 'y=sin(x)')
fig.canvas.draw()
def snx():
plt.plot(x, w, 'c-', label = 'y=sin(2x)')
fig.canvas.draw()
def thx():
plt.plot(x, l, 'm-', label = 'y=sin(x)/x')
fig.canvas.draw()
def fthx():
plt.plot(x, c, 'v-', label = 'y=sin(1/x)')
fig.canvas.draw()
def tan():
plt.plot(x, r, 's-', label = 'y=tan(x)')
ax.set_ylim([-5, 5])
fig.canvas.draw()
canvas = FigureCanvasTkAgg(fig, master=root)
plot_widget = canvas.get_tk_widget()
plot_widget.grid(row=0, column=1)
tk.Button(root, text="y=sin(x)", command=firstx).grid(row=0, column=0)
tk.Button(root, text="y=sin(2x)", command=snx).grid(row=1, column=0)
tk.Button(root, text="y=sin(x)/x", command=thx).grid(row=2, column=0)
tk.Button(root, text="y=sin(1/x)", command=fthx).grid(row=3, column=0)
tk.Button(root, text="y=tan(x)", command=tan).grid(row=4, column=0)
root.mainloop()
If you run the code you will see one button on the left and the rest of the buttons on the bottom left. How do I make it so that the buttons are all on the left and not the bottom left?
P.S. I am using python 3.6.6.
Change this line:
plot_widget.grid(row=0, column=1)
to
plot_widget.grid(row=0, column=1, rowspan=5)
Read about the rowspan= argument here https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/grid.html or https://effbot.org/tkinterbook/grid.htm