Passing a figure to be plotted in a tkinter tab - python

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'

Related

Background using imshow blurs after iteration on tkinter

The following is to plot contours from five (slider: 0 ~ 4) .xlsx files on tkinter. Each file just contains numerical data in the matrix 12X6 such as
from tkinter import *
import tkinter.ttk as ttk
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import ipywidgets as wg
import os
import pandas as pd
from matplotlib.ticker import MaxNLocator
from matplotlib.colors import BoundaryNorm
import math
from matplotlib.ticker import LinearLocator
%matplotlib widget
from matplotlib.widgets import Slider
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')
root = Tk()
root.title('TEST')
root.geometry("800x800")
cbar = None
def plot_noise():
# ============================================Read .xlsx file=====================================
folder = r'C:\Users\Dian-Jing Chen\Desktop\Work\test_read'
files = os.listdir(folder)
dfs = {}
for i, file in enumerate(files):
if file.endswith('.xlsx'):
dfs[i] = pd.read_excel(os.path.join(folder,file), sheet_name='Z=143', header = None, skiprows=[0], usecols = "B:M")
num = i + 1
rec = np.shape(dfs[0])
rmm = np.concatenate([dfs[0], dfs[1]])
for jj in range(2,num):
rmm = np.concatenate([rmm, dfs[jj]])
# =================================================PLOT===========================================
fig, ax = plt.subplots()
canvas = FigureCanvasTkAgg(fig, root)
canvas.get_tk_widget().grid(row=3, column=0, columnspan=3, rowspan=3, sticky=W+E+N+S, padx=0, pady=0)
# ===============================================contourf=========================================
fig.subplots_adjust(bottom=0.25)
X = np.arange(1,rec[1]+1,1)
Y = np.arange(1,rec[0]+1,1)
x , y = np.meshgrid(X,Y)
# ==============================================color bar=========================================
cbar_max = math.floor(np.min(rmm))
cbar_min = math.ceil(np.max(rmm))
cbar_num_colors = 200
cbar_num_format = "%d"
levels = MaxNLocator(nbins=cbar_num_colors).tick_values(cbar_min, cbar_max)
# ============================================Initial plot========================================
con = ax.contourf(x,y,dfs[1], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
cbar = fig.colorbar(con,ax = ax)
ax.axis([1, 12, 1, 6])
implot = plt.imshow(plt.imread('pcb.png'), interpolation='nearest', alpha=0.8, extent=[1,12,1,6]) # <-----
ax.set_aspect('equal', 'box')
# ================================================Slider==========================================
slider_bar = fig.add_axes([0.12, 0.1, 0.78, 0.03])
slider_de = Slider(slider_bar, 's_bar', 0, num-1, valinit=1,valfmt='%0.0f', valstep=1)
num_on_slider = []
def update(val):
num_on_slider.append(slider_de.val)
for ii in range(0,num):
if num_on_slider[-1] == ii:
con = ax.contourf(x,y,dfs[ii], levels = levels, cmap=cm.jet, alpha = 0.3, antialiased = True)
ax.axis([1, 12, 1, 6])
ax.set_aspect('equal', 'box')
slider_de.on_changed(update)
# =================================================GUI - Tkinter=======================================
resultButton = ttk.Button(root, text = 'show', command = plot_noise)
resultButton.grid(column=0, row=1, pady=15, sticky=W)
root.mainloop()
I use <------ to mark the place using imshow.
My question is after using slider to choose plot, by update(var), the background blurs. I mean
I know in the update(var), I should remove the previous con = ax.contourf. However, it does not work if I add con.remove()
def update(val):
num_on_slider.append(slider_de.val)
for ii in range(0,num):
if num_on_slider[-1] == ii:
con = ax.contourf(x,y,dfs[ii], levels = levels, cmap=cm.jet, alpha = 0.3, antialiased = True)
ax.axis([1, 12, 1, 6])
ax.set_aspect('equal', 'box')
ax.set_title('Frequency: f=%f' %float(avector[ii]))
con.remove()
AttributeError: 'QuadContourSet' object has no attribute 'remove'
​
How to fix this issue? Thanks!!
The background is not the problem, you are drawing multiple transparent plots on top of each other without removing the previous one; hence, they stack and blur the background.
To fix, you can add this in you update function
for c in ax.collections:
c.remove()
It shows some artifacts for me, but at least you get to see the correct picture without rethinking the whole code structure.

local variable 'cbar' referenced before assignment (after add global variable)

I am trying to solve my unsolved question:
(Python) tkinter figures (with colorbar) overlap when using slider
I applied the following answer:
tkinter figure (with colorbar) shrinks every time it's displayed
To avoid the problem shown in the title, I referred to Local (?) variable referenced before assignment
My codes:
from tkinter import *
import tkinter.ttk as ttk
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import ipywidgets as wg
import os
import pandas as pd
from matplotlib.ticker import MaxNLocator
from matplotlib.colors import BoundaryNorm
import math
from matplotlib.ticker import LinearLocator
%matplotlib widget
from matplotlib.widgets import Slider
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')
root = Tk()
root.title('TEST')
root.geometry("800x800")
cbar = None #<-------------------------(1)
def plot_noise():
# ============================================Read .xlsx file=====================================
folder = r'C:\Users\Dian-Jing Chen\Desktop\Work\test_read'
files = os.listdir(folder)
dfs = {}
for i, file in enumerate(files):
if file.endswith('.xlsx'):
dfs[i] = pd.read_excel(os.path.join(folder,file), sheet_name='Z=143', header = None, skiprows=[0], usecols = "B:M")
num = i + 1
rec = np.shape(dfs[0])
rmm = np.concatenate([dfs[0], dfs[1]])
for jj in range(2,num):
rmm = np.concatenate([rmm, dfs[jj]])
# =================================================PLOT===========================================
fig, ax = plt.subplots()
canvas = FigureCanvasTkAgg(fig, root)
canvas.get_tk_widget().grid(row=3, column=0, columnspan=3, rowspan=3, sticky=W+E+N+S, padx=0, pady=0)
# ===============================================contourf=========================================
fig.subplots_adjust(bottom=0.25)
X = np.arange(1,rec[1]+1,1)
Y = np.arange(1,rec[0]+1,1)
x , y = np.meshgrid(X,Y)
# ==============================================color bar=========================================
cbar_max = math.floor(np.min(rmm))
cbar_min = math.ceil(np.max(rmm))
cbar_num_colors = 200
cbar_num_format = "%d"
levels = MaxNLocator(nbins=cbar_num_colors).tick_values(cbar_min, cbar_max)
# ============================================Initial plot========================================
global cbar #<-------------------------(2)
con = ax.contourf(x,y,dfs[1], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
cbar = fig.colorbar(con,ax = ax)
ax.axis([1, 12, 1, 6])
# ================================================Slider==========================================
global slider_de
slider_bar = fig.add_axes([0.12, 0.1, 0.78, 0.03])
slider_de = Slider(slider_bar, 's_bar', 0, num-1, valinit=1,valfmt='%0.0f', valstep=1)
num_on_slider = []
def update(val):
num_on_slider.append(slider_de.val)
for ii in range(0,num):
if num_on_slider[-1] == ii:
if cbar:
cbar.remove() #<-------------------------(3)
con = ax.contourf(x,y,dfs[ii], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
cbar = fig.colorbar(con,ax = ax)
ax.axis([1, 12, 1, 6])
slider_de.on_changed(update)
# =================================================GUI - Tkinter=======================================
resultButton = ttk.Button(root, text = 'show', command = plot_noise)
resultButton.grid(column=0, row=1, pady=15, sticky=W)
root.mainloop()
I used <-------------(1),(2) to avoid local variable 'cbar' referenced before assignment
I used <-------------(3) to overcome the original problem.
However, the same error still popped out
UnboundLocalError: local variable 'cbar' referenced before assignment
How to fix that problem?

(python) How to fit the frame to the plot

I used the following codes (related to my question)
fig = plt.Figure()
canvas = FigureCanvasTkAgg(fig, root)
canvas.get_tk_widget().grid(row=6, column=0, columnspan=3, rowspan=3, sticky=W+E+N+S, padx=0, pady=0)
ax = fig.add_subplot(111)
fig.subplots_adjust(bottom=0.25)
X = np.arange(1,rec[1]+1,1)
Y = np.arange(1,rec[0]+1,1)
x , y = np.meshgrid(X,Y)
# Initial plots
con = ax.contourf(x,y,dfs[1], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
cbar = fig.colorbar(con, ax=ax)
ax.axis([1, 12, 1, 6])
ax.axis('equal') #<-------------------------
ax.set_title('Frequency: f=%f' %float(avector[1]))
Here ax.axis('equal') set the x & y-axis same scale. I got the following plot
How to fit the frame to the blue plot? (I want to remove the white region)
Thanks!
Complete codes:
The following codes is to plot contours from five (slider: 0 ~ 4) .xlsx files on tkinter. Each file just contains numerical data in the matrix 12X6 such as
from tkinter import *
import tkinter.ttk as ttk
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import ipywidgets as wg
import os
import pandas as pd
from matplotlib.ticker import MaxNLocator
from matplotlib.colors import BoundaryNorm
import math
from matplotlib.ticker import LinearLocator
%matplotlib widget
from matplotlib.widgets import Slider
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')
root = Tk()
root.title('TEST')
root.geometry("800x800")
cbar = None
def plot_noise():
# ============================================Read .xlsx file=====================================
folder = r'C:\Users\Dian-Jing Chen\Desktop\Work\test_read'
files = os.listdir(folder)
dfs = {}
for i, file in enumerate(files):
if file.endswith('.xlsx'):
dfs[i] = pd.read_excel(os.path.join(folder,file), sheet_name='Z=143', header = None, skiprows=[0], usecols = "B:M")
num = i + 1
rec = np.shape(dfs[0])
rmm = np.concatenate([dfs[0], dfs[1]])
for jj in range(2,num):
rmm = np.concatenate([rmm, dfs[jj]])
# =================================================PLOT===========================================
fig, ax = plt.subplots()
canvas = FigureCanvasTkAgg(fig, root)
canvas.get_tk_widget().grid(row=3, column=0, columnspan=3, rowspan=3, sticky=W+E+N+S, padx=0, pady=0)
# ===============================================contourf=========================================
fig.subplots_adjust(bottom=0.25)
X = np.arange(1,rec[1]+1,1)
Y = np.arange(1,rec[0]+1,1)
x , y = np.meshgrid(X,Y)
# ==============================================color bar=========================================
cbar_max = math.floor(np.min(rmm))
cbar_min = math.ceil(np.max(rmm))
cbar_num_colors = 200
cbar_num_format = "%d"
levels = MaxNLocator(nbins=cbar_num_colors).tick_values(cbar_min, cbar_max)
# ============================================Initial plot========================================
con = ax.contourf(x,y,dfs[1], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
cbar = fig.colorbar(con,ax = ax)
ax.axis([1, 12, 1, 6])
ax.axis('equal')
# ================================================Slider==========================================
slider_bar = fig.add_axes([0.12, 0.1, 0.78, 0.03])
slider_de = Slider(slider_bar, 's_bar', 0, num-1, valinit=1,valfmt='%0.0f', valstep=1)
num_on_slider = []
def update(val):
num_on_slider.append(slider_de.val)
for ii in range(0,num):
if num_on_slider[-1] == ii:
con = ax.contourf(x,y,dfs[ii], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
ax.axis([1, 12, 1, 6])
ax.axis('equal')
slider_de.on_changed(update)
# =================================================GUI - Tkinter=======================================
resultButton = ttk.Button(root, text = 'show', command = plot_noise)
resultButton.grid(column=0, row=1, pady=15, sticky=W)
root.mainloop()
you can change this line:
ax.axis('equal')
to:
ax.set_aspect('equal', 'box')
Output:
tip: Im use fake data to this fig!

Tkinter real time animation

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()

TKinter Matplotlib plot not displaying

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()

Categories