Tkinter pyplot subplot using dataframe - python

I have a dataframe with various values in and am trying to plot it onto a figure embedded into tkinter. Here is the code:
figure = plt.Figure(figsize=((0.8 / 3) * res_width / 100, 0.2 * res_height / 100), facecolor="#67676b")
figure.add_subplot(fc="#15151c").plot(df["Close time"][0:50], df["Close"][0:50], "-g")
Here is what is shown:
It shows a straight line, why is this, when the data clearly shows otherwise?
I ouputted Close axis as a list and here is the output:
['19183.62000000', '19184.58000000', '19185.57000000', '19183.94000000', '19202.16000000', '19213.30000000', '19199.25000000', '19176.14000000', '19186.30000000', '19179.88000000', '19179.34000000', '19178.32000000', '19187.08000000', '19181.12000000', '19200.12000000', '19202.25000000', '19209.05000000', '19208.59000000', '19200.92000000', '19205.37000000', '19205.23000000', '19205.19000000', '19200.26000000', '19199.92000000', '19198.12000000', '19200.99000000', '19204.54000000', '19210.29000000', '19210.00000000', '19209.86000000', '19219.52000000', '19222.24000000', '19253.65000000', '19241.24000000', '19255.85000000', '19257.37000000', '19250.00000000', '19239.38000000', '19236.97000000', '19246.57000000', '19230.70000000', '19229.76000000', '19228.76000000', '19229.75000000', '19231.22000000', '19227.77000000', '19229.69000000', '19209.75000000', '19211.64000000', '19232.56000000']
As you can see, the graph should go up and down and not just a straight line. Is it only plotting a trend line for some reason?
I recreated a "minimal reproducible example":
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import sys
platform = sys.platform
# root class
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
# cycle through windows
for F in (MainMenu, PageTwo):
frame = F(container)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(MainMenu)
# method to change frames
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class MainMenu(tk.Frame): # main menu
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.configure(bg="#15151c")
close_time = [1605549599999, 1605553199999, 1605556799999, 1605560399999, 1605563999999, 1605567599999, 1605571199999, 1605574799999, 1605578399999, 1605581999999, 1605585599999, 1605589199999, 1605592799999, 1605596399999, 1605599999999, 1605603599999, 1605607199999, 1605610799999, 1605614399999, 1605617999999, 1605621599999, 1605625199999, 1605628799999, 1605632399999, 1605635999999, 1605639599999, 1605643199999, 1605646799999, 1605650399999, 1605653999999, 1605657599999, 1605661199999, 1605664799999, 1605668399999, 1605671999999, 1605675599999, 1605679199999, 1605682799999, 1605686399999, 1605689999999, 1605693599999, 1605697199999, 1605700799999, 1605704399999, 1605707999999, 1605711599999, 1605715199999, 1605718799999, 1605722399999, 1605725999999]
close = ['16691.91000000', '16690.85000000', '16779.01000000', '16825.56000000', '16695.41000000', '16713.86000000', '16713.57000000', '16806.09000000', '16690.21000000', '16678.02000000', '16573.58000000', '16668.95000000', '16619.81000000', '16631.72000000', '16750.00000000', '16704.83000000', '16659.11000000', '16763.47000000', '16995.06000000', '17083.01000000', '16947.38000000', '17153.93000000', '17322.19000000', '17639.35000000', '17808.66000000', '17638.37000000', '17685.22000000', '17677.64000000', '17624.15000000', '17596.78000000', '17659.38000000', '17693.64000000', '17739.42000000', '17680.64000000', '18030.71000000', '18369.33000000', '17623.39000000', '17780.19000000', '18063.70000000', '18211.02000000', '18110.00000000', '18250.00000000', '18249.99000000', '18024.03000000', '17882.89000000', '17683.11000000', '17873.88000000', '17793.71000000', '17890.45000000', '17775.92000000']
# graphs
figure = plt.Figure(figsize=(100, 100), facecolor="#67676b")
figure.add_subplot(fc="#15151c").plot(close_time, close, "-g")
FigureCanvasTkAgg(figure, self).get_tk_widget().pack()
class PageTwo(tk.Frame): # second page
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.configure(bg="#15151c")
tk.Label(self, text="pg2", font=("Consolas", 40), fg="#67676b", bg="#15151c").pack()
tk.Button(self, text="Return", command=lambda: app.show_frame(MainMenu)).pack()
# launch application
app = Application()
app.title("Test App")
if platform == "linux":
app.wm_attributes("-zoomed", 1)
else:
app.state("zoomed")
app.configure(bg="black")
app.mainloop()

The issue is because your close list is a list of strings, not floats, so matplotlib is treating them as catagorical data.
close = ['16691.91000000', '16690.85000000', '16779.01000000', '16825.56000000', '16695.41000000', '16713.86000000', '16713.57000000', '16806.09000000', '16690.21000000', '16678.02000000', '16573.58000000', '16668.95000000', '16619.81000000', '16631.72000000', '16750.00000000', '16704.83000000', '16659.11000000', '16763.47000000', '16995.06000000', '17083.01000000', '16947.38000000', '17153.93000000', '17322.19000000', '17639.35000000', '17808.66000000', '17638.37000000', '17685.22000000', '17677.64000000', '17624.15000000', '17596.78000000', '17659.38000000', '17693.64000000', '17739.42000000', '17680.64000000', '18030.71000000', '18369.33000000', '17623.39000000', '17780.19000000', '18063.70000000', '18211.02000000', '18110.00000000', '18250.00000000', '18249.99000000', '18024.03000000', '17882.89000000', '17683.11000000', '17873.88000000', '17793.71000000', '17890.45000000', '17775.92000000']
Convert the items in close to floats, and it should work fine. In your minimal exmaple, something like:
close = [float(i) for i in close]
should do it.
In your original code you have a dataframe, rather than a list; you could use df["Close"][0:50].astype(float) as you plot the data in that case
figure.add_subplot(fc="#15151c").plot(df["Close time"][0:50], df["Close"][0:50].astype(float), "-g")

Related

I can't seem to pass on an object to another class in Python/Tkinter

I have an object which I want to pass to a new frame through a method in another frame class. I found a solution that looked similar to what I was after and tried it, however, the object doesn't get passed. In fact, I got an error message saying "Value after * must be an iterable, not PackingList", where PackingList is the class which the object is made out of. I tried to instead get the "name" attribute of the object and pass it to the next frame, but it just returns an empty tuple. I am really stuck and I appreciate some help.
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side = "top", fill = "both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for F in (Homescreen, Menuscreen, Create, ShowUpcoming, ShowAll, OpenList, Search, Edit):
frame = F(container, self, *args, **kwargs)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(Homescreen)
def show_frame(self, container, *args, **kwargs):
frame = self.frames[container]
frame.tkraise()
...
class ShowAll(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
tk.Label(self, text = "Alla packningslistor", font = ("Times new roman", 30)).place(x = 110, y = 0)
self.controller = controller
objectList = PK.main()
objectOpen = PK.showAll(objectList)
self.radiobutton_list = []
self.objectList = objectList
for i in range(len(objectOpen)):
radiobutton = tk.Radiobutton(self, text = objectOpen[i], command = functools.partial(self.objectToOpen, idx = i)).place(x = 150, y = 100 + i*30)
self.radiobutton_list.append(radiobutton)
def objectToOpen(self, idx):
objectID = self.objectList[idx]
return self.controller.show_frame(OpenList, *objectID)
class OpenList(tk.Frame):
def __init__(self, parent, controller, *objectID):
tk.Frame.__init__(self, parent)
#lala = getattr(objectID, "name")
#print(lala)
As I said I tried to pass just the name of the object but it prints out as an empty tuple in the next frame class.
I did not understand your question. But here are my corrections to your App class. I hope these corrections can help your understanding of Python and tkinter and debug the rest of your codes.
If you need more detailed help, it will be helpful if you can more specific by stating in the comment section what you want to do with classes App, ShowAll, and OpenList (or their method), and I will see how I can help you by elaborating my answer further.
import tkinter as tk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__()
self.container = tk.Frame(self)
self.container.pack(side="top", fill="both", expand=True)
self.frames = {}
colors = ('white', 'black', 'red', 'green', 'blue', 'cyan', 'yellow', 'magenta')
frames = ("Homescreen", "Menuscreen", "Create", "ShowUpcoming", "ShowAll", "OpenList", "Search", "Edit")
col=0
for C, F in zip(colors, frames):
print(f'{F=}')
self.frames[F] = tk.Frame(self.container, background=C, width=100, height=50)
self.frames[F].grid(row=0, column=col, sticky="nsew")
# col += 1 # uncomment this to see all frames
self.show_frame('Create') # you should see red
def show_frame(self, container):
self.frames[container].tkraise()
if __name__ == "__main__":
app = App()
app.mainloop()

Update Tkinter progressbar from function called (by button click), function is in separate document

I am trying to update progressbar in tkinter.
First of i have two documents.
document 1: conatins GUI
document 2: Contains functions, that are called when pressing the button widgets attached to the GUI.
When i perform a calculation within document 2 i want to update the progress bar which is in document 1.
An exaple of the code is as follows. (just to mention, this is my first script in python, so please correct me if im wrong in any of the coding)
#Document 1
from Document2 import *
import tkinter as tk
from tkinter import *
from tkinter import messagebox
from tkinter import ttk
from tkinter import font as tkfont # python 3
from PIL import ImageTk, Image
from tkinter.ttk import Progressbar
class TEST(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.resizable(self, width=False, height=False)
tk.Tk.title(self, "APP NAME")
tk.Tk.iconbitmap(self, filepath_NAME_icon)
tk.Tk.geometry(self, "465x262")
#self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (ProjectingPage):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("ProjectingPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class ProjectingPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent, bg=bg_color)
self.controller = controller
Button_get_TK = Button(self, text="Indsæt terrænkote",
font=("Calibri", btn_font_size, "normal"),
width=std_button_width,
bg=bg_color_button,
fg=fg_color_button,
borderwidth=size_border_width,
activebackground=act_bg,
command=Get_TK)
Button_get_TK.place(x=12, y=166)
Button_get_TK.update()
self.progress = Progressbar(self, orient = HORIZONTAL,
length = 100, mode = 'determinate')
self.progress.pack()
def UpdateProgressBar(self, data):
self.progress.start()
self.progress.update_idletasks()
and
#Document 2
import Document1 as KTP
from Document1 import *
def Get_TK():
for i in range(0,100):
test_progressbar = KTP.ProjectingPage
test_progressbar.UpdateProgressBar(i)
I have trimmed down my code to just the relevant part. I need to know the principals of getting my progressbar to update by calling a function from a separate document.
I really hope someone can help me. thanks in advance :-)
I wouldn't uses elements from Document1 as hardcoded in Document2 but as argument in function.
#Document 2
# without imports from Document1
def Get_TK(item):
test_progressbar = item.ProjectingPage
for i in range(100):
test_progressbar.UpdateProgressBar(i)
And then I would use lambda to assing function with values
command=lambda:Get_TK(self.UpdateProgressBar):
I would said that sending as argument is consistent with the principle of The Zen of Python
Explicit is better than implicit.
But if I would have to use Get_TK in ProjectingPage to access element in the same class ProjectingPage then I wouldn't put it in separated file but directly in ProjectingPage
class ProjectingPage(tk.Frame):
def Get_TK(self):
for i in range(100):
self.UpdateProgressBar(i)

Reaching an Object Outside of the Class in Python

I have started to learn Python recently and I am trying to make a basic GUI. I stucked at some point as you imagine. I found that code from the internet (possibly in stackoverflow) and am trying to modify it for the GUI which I want to make.
All code;
# imported necessary packages etc.
class tkinterApp(tk.Tk):
# __init__ function for class tkinterApp
def __init__(self, *args, **kwargs):
# __init__ function for class Tk
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack()
container.pack_propagate(0)
# initializing frames to an empty array
self.frames = {}
# iterating through a tuple consisting
# of the different page layouts
for F in (LoadPage, StartPage):
frame = F(container, self)
# initializing frame of that object from
# startpage, page1, page2 respectively with
# for loop
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky ="nsew")
self.show_frame(LoadPage)
# to display the current frame passed as
# parameter
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def load():
try:
import data
except:
print("Error...")
# first window frame loadpage
class LoadPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
top_container = tk.Frame(self)
top_container.pack()
top_container.pack_propagate(0)
lbl_title = tk.Label(top_container, text = "TITLE")
lbl_title.pack(side="bottom")
lbl_title.pack_propagate(0)
center_container = tk.Frame(self)
center_container.pack()
center_container.pack_propagate(0)
a_image = ImageTk.PhotoImage(Image.open(r"images/image.png"))
image_area = tk.Label(center_container, image = a_image)
image_area.image = a_image
image_area.pack(side = "top", pady=50)
image_area.pack_propagate(0)
b_image = ImageTk.PhotoImage(Image.open(r"images/image.png"))
btn_load = tk.Button(center_container, image = b_image, command=lambda:[load(), controller.show_frame(StartPage)])
btn_load.image = b_image
btn_load.pack(pady=10)
btn_load.pack_propagate(0)
lbl_load_inf = tk.Label(center_container, text = "INFO...")
lbl_load_inf.pack(pady=5)
lbl_load_inf.pack_propagate(0)
bottom_container = tk.Frame(self)
bottom_container.pack()
bottom_container.pack_propagate(0)
# second window frame startpage
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
top_container = tk.Frame(self)
top_container.pack()
top_container.pack_propagate(0)
lbl_title = tk.Label(top_container, text = "TITLE")
lbl_title.pack(side="top")
lbl_title.pack_propagate(0)
toolbar = tk.Frame(top_container)
toolbar.pack(side="bottom")
toolbar.pack_propagate(0)
btn_1 = tk.Button(toolbar, text ="BUTTON_1", \
command = lambda : controller.show_frame(StartPage))
btn_1.place(relheight=1, width=220, relx=0)
btn_2 = tk.Button(toolbar, text ="BUTTON_2", \
command = lambda : controller.show_frame(StartPage))
btn_2.place(relheight=1, width=200, relx=0.18)
center_container = tk.Frame(self)
center_container.pack()
center_container.pack_propagate(0)
figure = plt.Figure()
ax = figure.add_subplot(111)
chart_type = FigureCanvasTkAgg(figure, center_container)
chart_type.get_tk_widget().place(relx = 0.10, rely = 0.3, relwidth = 0.6, relheight = 0.4)
df["Column"].value_counts().sort_values().plot(kind='barh', legend=True, ax=ax)
ax.set_title('Title')
bottom_container = tk.Frame(self)
bottom_container.pack()
bottom_container.pack_propagate(0)
# Driver Code
app = tkinterApp()
app.mainloop()
If you look at the StartPage class, there is a code block in init function;
figure = plt.Figure()
ax = figure.add_subplot(111)
chart_type = FigureCanvasTkAgg(figure, center_container)
chart_type.get_tk_widget().place(relx = 0.10, rely = 0.3, relwidth = 0.6, relheight = 0.4)
df["Column"].value_counts().sort_values().plot(kind='barh', legend=True, ax=ax)
ax.set_title('Title')
at this code block there is a DataFrame (df). It comes from data.py (imported via load function which triggered by a button in LoadPage). I said it comes from but I should have said it should come from. Unfortunately I could not get the data. DataFrame imported perfectly but somehow I cannot reach that df. How can I reach i? Possibly it is about class system but I cannot figure it out.
I got the error;
NameError: name 'df' is not defined
Note: Code is a bit mess right now, I know. I will modify more in future. I am trying to learn how Tkinter, GUI, Python works just right now. Please pardon me for that messy code :)

Preloading windows to avoid Tkinter visual glitches during frame load

Immediately during the first ~1 sec after I've landed on a new page in my GUI, I'm seeing numerous visual glitches before the window arrives at the proper layout (before/after screenshots below).
UPDATE:
The below code will give the desired error. I feel like the initial frame is being merged with the next frame upon calling the show_frame function, and posit that the initial frame must actually be manually hidden from view before preloading (hiding/loading) the next frame. Any help on this is greatly appreciated - and thank you to all who have taken a look so far.
import tkinter as Tk
from tkinter import font as tkfont
from tkinter import filedialog, ttk #browse directories; widget support
class Manifold(Tk.Tk):
def __init__(self, *args, **kwargs):
Tk.Tk.__init__(self, *args, **kwargs)
#custom font options:
self.title1_font = tkfont.Font(family='Helvetica',size=13) #normal type
#customized ttk GUI theme:
GUItheme = ttk.Style()
GUItheme.theme_use('alt')
container = Tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F,geometry,title,options,wait in zip((StartPage,PageOne),
("532x279","528x270"),
("","Experimental Data"),
((False,False),(True,False)),
(100,100)):
page_name = F.__name__
frame = F(container, self)
self.frames[page_name] = (frame,geometry,title,options,wait) #puts all pages in stacked order
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name): #show a frame for the given page name
frame, geometry, title, options, wait = self.frames[page_name]
self.geometry(geometry) #changes between window sizes
self.title(title) #changes titles of windows
self.resizable(*options) #changes ability of user to resize each window
self.withdraw()
frame.tkraise() #raises window to top
self.after(wait,self.deiconify) #preload page before viewing
self.update_idletasks()
class StartPage(Tk.Frame):
def __init__(self, parent, controller):
Tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background='black') #set window background color
#page one button:
button1 = ttk.Button(self, text="Page 1",
command=lambda: controller.show_frame("PageOne"))
button1.grid(row=0,column=0,sticky='W')
class PageOne(Tk.Frame):
def __init__(self, parent, controller):
Tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background='gray15') #set window background color
self.grid_columnconfigure(0,weight=1000) #for resizing window horizontally
#average volume filename:
self.label1 = Tk.Label(self, text="Average Volume Filename:",fg="gray90",bg="gray25",font=controller.title1_font)
self.label1.grid(row=0,column=0,ipadx=10,ipady=0,sticky='W')
self.label1.config(height=1)
self.entry1 = Tk.Entry(self,textvariable=Tk.StringVar(),highlightbackground="black",width=50)
self.entry1.grid(row=1,column=0,sticky="WE")
self.entry1.insert(0," .mrc, .spi")
self.entry1.configure(state="disabled") #prevent typing
self.browse1 = ttk.Button(self,text="Browse",
command=self.browse_button1)
self.browse1.grid(row=1,column=1,sticky='W')
#gathers volume input:
def browse_button1(self):
self.entry1.configure(state="normal") #unlocks typing for program
self.label1.config(fg="gray90",bg='gray25') #standard colors, or reset on additional wrong input
content_initial = self.entry1.get()
if __name__ == "__main__":
app = Manifold()
app.mainloop()
Page One:
Transition:
Page Two:
Okay, I've figured it out. Using my above code (in the Update section of my initial question), I made two changes. The first is right under the main Class structure:
class Manifold(Tk.Tk):
def __init__(self, *args, **kwargs):
Tk.Tk.__init__(self, *args, **kwargs)
#preload windows (avoids watching widgets load in real time):
self.withdraw() #hide window
self.after(0,self.deiconify) #unhide window asap
The second is in the show_frame loop, with the preceding wait tuple (within the chunk starting with for F, geometry,etc. set to (10,10,10,10):
def show_frame(self, page_name): #show a frame for the given page name
frame, geometry, title, scaling, wait = self.frames[page_name]
self.quit() #seems to be important in exiting out of previous window entirely
self.geometry(geometry) #changes between window sizes
self.title(title) #changes titles of windows
self.resizable(*scaling) #changes ability of user to resize each window
self.withdraw()
frame.tkraise() #raises window to top
self.after(wait,self.deiconify) #preload page before viewing
self.update_idletasks()
If anyone else ends up running into something like this, I hope this helps!
Remove all calls to update until your are ready for your UI to be visible, and don't use after(0, ...) because the zero means that code will run before tkinter has had a chance to process any other events, including requests to redraw portions of the screen.
Hide your Toplevel or Tk instance(s) that is/are glitchy until after a certain amount of time has passed:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except:
import Tkinter as tk
def hide(*toplevel_or_tk_instance_s_):
for each in toplevel_or_tk_instance_s_:
each.withdraw()
def show(*toplevel_or_tk_instance_s_):
for each in toplevel_or_tk_instance_s_:
each.iconify()
each.deiconify()
if __name__ == '__main__':
root = tk.Tk()
my_toplevel1 = tk.Toplevel(root, bg='red')
my_toplevel2 = tk.Toplevel(root, bg='green')
hide(root, my_toplevel1, my_toplevel2)
root.after(1000, show, root)
root.after(2000, show, my_toplevel1)
root.after(3000, show, my_toplevel2)
root.mainloop()

placing class defined tkinter object on an individual frame when many are defined using tk.Tk

Following a suggestion that I got from Sentdex I have coded a multiple page Python/Tkinter application which among other things provides a time-moving graph on a single frame of a suite of many frames that live under tk.Tk. The coding of a moving graph was slightly complicated so I chose to define the canvas in a class: GrpCanvas(tk.Canvas).
My problem is that this program structure seems to cause the canvas object to appear on all 21 of my page-frames! How can I manage the code so that the graphcanvas=GrpCanvas(HomePage) only appears on that page? I have commented out some parent definitions to show what I have tried to do (and failed). I am using Python 3.4.4.
I show the code (cut down as much as I can to show the problem) below:
#Avoiding canvas on all pages when pages are managed using tk.Tk
import tkinter as tk
sinewave_points=[] #Generated by a sin function of time.
#class GrpCanvas(self, parent):
class GrpCanvas(tk.Canvas):
#def __init__(self, parent):
def __init__(self, parent, controller):
tk.Canvas.__init__(self, height=340, width=594, bg='white')#, x=pos_x, y=pos_y):
self.place(x=180, y=80)
def set_y_scale(self, sinewave_points):
self.scale=100 #actually calculated from a scaling algorithm (adapting to amplitude of sinewave_points)
return self.scale
def define_graph(self, scale, sinewave_points):
# create x-axis
self.horizontal=self.create_line(0, 170, 594, 170, width=2)
for i in range(13): #used to be 26
x = 20 + (i * 48)
self.x_scale=self.create_text(x, 175, font=("", 6),\
anchor='n', text='{}'.format(((12/3) * i)-24))
# y-axis
self.vertical=self.create_line(20, 330, 20, 10, width=2)
self.y_scale=self.set_y_scale(sinewave_points)
if self.y_scale == 100:
for i in range(21):
self.y = int(330 - (i * (320/20))) #In fact there is an slgorithm to scale the y-axis
#print(i, self.y)
self.y_axis=self.create_text(17, (self.y), font=("", 6), anchor='e',\
text='{}'.format(int((((200/320)*(320/20)) * i)-\
100)))
for i in range(len(sinewave_points)):
self.x, self.y = (i+20) , int(-1*self.scale*sinewave_points[i])+ 170
self.history=self.create_oval(self.x - 1, self.y - 1, self.x + 1,\
self.y + 1, width=0, fill='purple')
class Moving_Sinewave(tk.Tk):
def __init__(self, *args, **kwargs):
#Initialising Tkinter
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, 'Sinewave Moving Plotter')
tk.Tk.geometry(self, '800x480')#This is the size of the screen (in pixels)
container = tk.Frame(self)
container.pack(fill='both', expand= True)#(side="top", fill="both", expand = True)
container.grid_rowconfigure (0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (HomePage,
SystemConfigPage,
ConfigAlarmsPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
frame.configure(background= 'ivory2'),
self.show_frame(HomePage)
def show_frame(self, cont):
frame=self.frames[cont]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self, parent, controller):
self.controller=controller
tk.Frame.__init__(self, parent)
global time1, time2, time4, time5
sysconfigbutton=tk.Button(self, text= 'System\nConfiguration',
command=lambda: controller.show_frame(SystemConfigPage),
height=2, width=12)
sysconfigbutton.place(x=20, y=80)
#graphcanvas=GrpCanvas(tk.Frame) #works with: class GrpCanvas(tk.Canvas):
#def __init__(self, parent):
#graphcanvas=GrpCanvas(HomePage) #works with: class GrpCanvas(tk.Canvas):
#def __init__(self, parent):
#graphcanvas=GrpCanvas(HomePage(tk.Frame))
graphcanvas=GrpCanvas(HomePage, controller.tk)# works with: class GrpCanvas(tk.Canvas):
#def __init__(self, parent, controller):
graphcanvas.define_graph(graphcanvas.set_y_scale(sinewave_points), sinewave_points)
# This actually plots the points
class SystemConfigPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
configalarmsbutton=tk.Button(self, text= 'Configure\nAlarms',
command=lambda: controller.show_frame(ConfigAlarmsPage),
height=2, width=12)
configalarmsbutton.place(x=20, y=180)
class ConfigAlarmsPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
backbutton=tk.Button(self, text= 'Back',
command=lambda: controller.show_frame(HomePage),
height=2, width=12)
backbutton.place(x=20, y=380)
app = Moving_Sinewave()
app.mainloop()
The first argument to GrpCanvas needs to be the parent widget in which the canvas is to appear. In this specific case you should use self, since you want it to be in the home page and you are creating it as part of creating HomePage:
graphcanvas=GrpCanvas(self, controller.tk)
You also need to pass this argument on to the __init__ of the parent class, which you are neglecting to do. To fix that, change this:
tk.Canvas.__init__(self, height=340, ...)
... to this:
tk.Canvas.__init__(self, parent, height=340, ...)
What was happening is that because you didn't pass in the parent, the widget was using the root window as the default. And because you were using place, and because this widget was getting created last (and thus was at the top of the stacking order) it was appearing on top of all of the pages.

Categories

Resources