Change the scale of a plot in a graphic interface tkinter - python

I am trying to plot in a graphic interface and when I see what it looks like I want to change the scale with the button OK(def changerechelle is supposed to do that when I click OK) but it doesn't seem to work... I don't know why. I am a beginner so I don't understand everything I found on internet.
Here is the error I have:
UserWarning: No labelled objects found. Use label='...' kwarg on
individual plots. warnings.warn("No labelled objects found. "
Exception in Tkinter callback
And here is my code:
from numpy import *from matplotlib.pyplot import *
from matplotlib.lines import *
from cmath import *
from scipy import interpolate
from scipy.signal import butter, lfilter, freqz
import os
import imp
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import pylab as pl
temps=linspace(0,50)
marche=linspace(0,50)
figure(1)
plot(temps, marche)
xlabel('Temps [heure]')
ylabel('Marche [s/j]')
grid(True)
legend(loc=0)
xmini=tk.DoubleVar()
ymini=tk.DoubleVar()
xmaxi=tk.DoubleVar()
ymaxi=tk.DoubleVar()
fenetre = tk.Tk()
graph = FigureCanvasTkAgg(figure(1), master=fenetre)
canvas = graph.get_tk_widget()
canvas.grid(row=0, column=0)
xmini= tk.Entry(fenetre, width=4)
xmini.grid(row = 1, column = 2)
label_xmin = tk.Label(fenetre, text = "Coord de l'abscisse minimale")
label_xmin.grid(row = 1, column = 1)
ymini = tk.Entry(fenetre, width=4)
ymini.grid(row = 2, column = 2)
label_ymin = tk.Label(fenetre, text = "Coord de l'ordonnée minimale")
label_ymin.grid(row = 2, column = 1)
xmaxi = tk.Entry(fenetre, width=4)
xmaxi.grid(row = 3, column = 2)
label_xmax = tk.Label(fenetre, text = "Coord de l'abscisse maximale")
label_xmax.grid(row = 3, column = 1)
ymaxi = tk.Entry(fenetre, width=4)
ymaxi.grid(row = 4, column = 2)
label_ymax = tk.Label(fenetre, text = "Coord de l'ordonnée maximale")
label_ymax.grid(row = 4, column = 1)
def changerechelle() :
xmin = xmini.get()
xmax = xmaxi.get()
ymin = ymini.get()
ymax = ymaxi.get()
figure(1)
plot(temps, marche)
xlim(xmin,xmax)
ylim(ymin,ymax)
graph = FigureCanvasTkAgg(figure(1), master=fenetre)
canvas = graph.get_tk_widget()
canvas.grid(row=0, column=0)
bouton=tk.Button(fenetre, text="OK", command=changerechelle)
bouton.grid(row=2,column=3)
close(figure(1))
fenetre.mainloop()

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?

Passing a figure to be plotted in a tkinter tab

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'

How to display only one column of csv using tkinter and overwrite with next value after 100ms

Contents of csv file:
Latitude(deg), Longitude(deg), Speed(ms-1)
12.8742,13.6543, 0.23,
12.8743,13.6544, 0.25,
12.8744,13.6545, 0.29,
import tkinter
import csv
root = tkinter.Tk()
# open file
with open("File.csv", newline = "") as file:
reader = csv.reader(file)
# Reads all rows and columns[enter image description here][1]
r = 0
for col in reader:
c = 0
for row in col:
label = tkinter.Label(root, width = 10, height = 2, \
text = row, relief = tkinter.RIDGE)
label.grid(row = r, column = c)
c += 1
r += 1
root.mainloop()
Current output:
Expected result update speed column with next values overwriting the previous value with same size of text box:
For any kind of loop in tkinter, you should look into the ".after(ms, func)" method, which allows you to specify a loop where values are updated after a number of milliseconds
Here is a minimum working example, just replace the data with your csv file (and catch the StopIteration error when reaching the end of your dataset)
import tkinter as tk
import numpy as np
data = (x for x in np.random.random_sample(1000))
root = tk.Tk()
svar = tk.StringVar()
tk.Label(root, text='Speed(ms-1)').pack()
tk.Label(root, textvariable=svar).pack()
def update_speed():
svar.set(next(data))
root.after(500, update_speed)
update_speed()
root.mainloop()
I have modified this code. I need to plot as well as display speed value by tkinter. But below code is working sequentially after displaying all speed values and closing the display box the plotting of latitude and longitude begins. Can I do it parallelly both displaying and plotting has same file?
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import pandas as pd
import numpy as np
import tkinter as tk
HV = pd.read_csv('file.csv')
lat_HV = []
lon_HV = []
speed_HV = []
lat_HV = HV['Latitude(deg)']
lon_HV = HV[' Longitude(deg)']
speed_HV = HV[' Speed(ms-1)']
data = iter(speed_HV)
root = tk.Tk()
svar = tk.StringVar()
tk.Label(root, text='Speed(ms-1)').pack()
tk.Label(root, textvariable=svar).pack()
def update_speed():
svar.set(next(data))
root.after(100, update_speed)
update_speed()
root.mainloop()
plt.style.use('seaborn')
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
def animation(i):
HV = pd.read_csv('file.csv')
lat_HV = []
lon_HV = []
speed_HV = []
lat_HV = HV[0:i]['Latitude(deg)']
lon_HV = HV[0:i][' Longitude(deg)']
speed_HV = HV [0:i][' Speed(ms-1)']
ax.clear()
plt.title('IMA Scenario')
plt.xlabel('Longitude')
plt.ylabel('Latitude')
ax.scatter(lon_HV, lat_HV,s=30, marker="s",label='HV')
plt.legend(loc='upper right');
animation = FuncAnimation(fig, func=animation, interval=100)
plt.show()

Update matplotlib plot correctly - tkinter

Evening,
I want to insert a data point externally into an existing plot (f(x) = x, g(x) = x**2). To do this, the x and y coordinates can be entered in entry fields. The user can then press a button to insert the point.
Assuming a data point (x1, y1) is inserted and the user trys to enter a new data point (x2,y2). In this case the GUI should only display the curves (f(x), g(x)) and the point (x2, y2). The last point (x1,y1) should be deleted.
My solution only partially works: Additional points (x,y) can be created, but the old ones are not deleted...
Does any of you know an approach to solve the problem described above.
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import numpy as np
fig = Figure(figsize = (9, 6), facecolor = "white")
axis = fig.add_subplot(111)
x_values = np.array([1,2,3,4,5,6,7])
axis.plot(x_values, x_values, "-r")
axis.plot(x_values, x_values ** 2, "--g")
axis.grid()
root = tk.Tk()
Label(root, text = "x =" ).grid(row = 0, column = 0)
Label(root, text = "y =" ).grid(row = 1, column = 0)
x = DoubleVar()
y = DoubleVar()
x_entry = Entry(root, textvariable = x).grid(row = 0, column = 1)
y_entry = Entry(root, textvariable = y).grid(row = 1, column = 1)
def plotgraphs():
axis.plot(x.get(), y.get(), "ko")
canvas = FigureCanvasTkAgg(fig, master = root)
canvas._tkcanvas.grid(row = 2, column = 1)
Button(root, text = "New Graphs", command = plotgraphs).grid(row = 0, column = 2)
canvas = FigureCanvasTkAgg(fig, master = root)
canvas._tkcanvas.grid(row = 2, column = 1)
root.mainloop()
You need to delete existing point to get the desired behavior. Below would do - what you are looking for. I did enhanced it a bit.
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import numpy as np
from tkinter import *
fig = Figure(figsize = (9, 6), facecolor = "white")
axis = fig.add_subplot(111)
x_values = np.array([1,2,3,4,5,6,7])
axis.plot(x_values, x_values, "-r", label = 'f(X) = x')
axis.plot(x_values, x_values ** 2, "--g", label = 'f(x) = x\N{SUPERSCRIPT TWO}')
axis.grid()
axis.legend()
root = tk.Tk()
Label(root, text = "x =" ).grid(row = 0, column = 0)
Label(root, text = "y =" ).grid(row = 1, column = 0)
x = DoubleVar()
y = DoubleVar()
x_entry = Entry(root, textvariable = x).grid(row = 0, column = 1)
y_entry = Entry(root, textvariable = y).grid(row = 1, column = 1)
def plotgraphs():
if (len(axis.lines)) == 3: # Count existing plotted lines and delete if already existing
del (axis.lines[2])
axis.plot(x.get(), y.get(), "ko", label = 'Input point')
else:
axis.plot(x.get(), y.get(), "ko", label = 'Input point')
axis.legend()
canvas = FigureCanvasTkAgg(fig, master = root)
canvas._tkcanvas.grid(row = 2, column = 1)
Button(root, text = "New Graphs", command = plotgraphs).grid(row = 0, column = 2)
canvas = FigureCanvasTkAgg(fig, master = root)
canvas._tkcanvas.grid(row = 2, column = 1)
root.mainloop()

Categories