The need for two different geometric plotters arises because i want to display a sophisticated GUI with text, entry fields, pictures, buttons, alongside an animated matplotlib graph on a FigureCanvasTkAgg with a NavigationToolbar2Tk. The NavigationToolbar2Tk fails to work when any geometric plotter other than pack() is used. I have tried over the course of the week several different methods of putting the NavigationToolbar2Tk into its own frame, but in the examples, only a single frame exists. I came to the conclusion that ideally, splitting my frame ~ PageOne ~ into two subframes or instantiating two frames which make up page one.
I have several frames as shown in my code below and my knowledge of python is rudimentary so i don't have the imagination or know how to circumvent this problem. I have gutted my code to show the problem concisely and Included my Imports.
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
from matplotlib.pylab import *
from matplotlib import style
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import matplotlib.dates as dates
import matplotlib.ticker as mticker
import tkinter as tk
from tkinter import ttk
from tkinter import *
from PIL import Image, ImageTk
from mpl_toolkits.axes_grid1 import host_subplot
from gpiozero import CPUTemperature
import time
import datetime as dt
import pandas as pd
import numpy as np
#************************************************************************#
# Format Graph_1 [ax1] onto fig1 at subplot [ row = 1, col = 1, index = 1 ]
# Set Figure Text
font = {'size' : 9}
matplotlib.rc('font', **font)
# Setup Figure
fig1 = Figure()
# Define Axis 1 for Vin and Vout
ax1 = fig1.add_subplot(1, 1, 1)
#subplots_adjust(left=0.05, bottom=0.10, right=0.55, top=0.8, wspace=0.2)
ax1.minorticks_on()
ax1.grid(b=True, which='major', color='k', linestyle='-')
ax1.grid(b=True, which='minor', color='k', linestyle=':')
ax1.set_title("PI3740 Paramaters", fontsize = 12)
ax1.set_xlabel("Relative Time (s)", fontsize = 10)
ax1.set_ylabel("Voltage (V)", fontsize =10)
# Define Axis 2 for Iout Which is tied to Axis 1's X-Axis
ax2 = ax1.twinx()
ax2.set_ylabel("Output Current (A)")
# Parameters
x_len = 500 # Resolution [Number of Points in Window]
x_max = 2 # X-Axis Range [ (Step)ms Samp^-1 * (x_len)Samp = X_Range]
y_range = [0, 50] # Range of possible Y values to display
# Create figure for plotting
steps = (x_max/x_len)
stepms = steps * 1000
xs = np.arange(0, x_max, steps) # xs is a list from 0 to 10 in steps of 0.01 [A list refers to a 1D Array]
ys1 = [0] * x_len # ys is a list indexed from ys[0] to ys[999] all containing 0 # Vin
ys2 = [0] * x_len # ys is a list indexed from ys[0] to ys[999] all containing 0 # Vout
ys3 = [0] * x_len # ys is a list indexed from ys[0] to ys[999] all containing 0 # Iout
ax1.set_ylim(y_range) # Y-Axis Voltage Range Set
ax2.set_ylim(0, 10) # Y-Axis Current Range Set
ax1.set_xlim(0, x_max) # X-Axis Shared Relative Time Range Set
# Create a blank line. We will update the line in animate
line1, = ax1.plot(xs, ys1, 'b-', label = "Vin")
line2, = ax1.plot(xs, ys2, 'g-', label = "Vout")
line3, = ax2.plot(xs, ys3, 'r-', label = "Iout")
# Create a Legend
ax1.legend([line1, line2],[line1.get_label(), line2.get_label()])
ax1.legend(bbox_to_anchor = (0.,0.99,1.,.102), loc = 3, ncol = 2, borderaxespad = 0., frameon = False)
ax2.legend([line3],[line3.get_label()])
ax2.legend(bbox_to_anchor = (1.00,0.99), loc = 'lower right', borderaxespad = 0., frameon = False)
#************************************************************************#
#**********************Animation Function********************************#
# This function is called periodically from FuncAnimation
def updateData(self):
# Drop down menu event flags
global ChartLoad
# Graph variables
global xs
global ys1
global ys2
global ys3
if ChartLoad == True:
# Read temperature (Celsius) from TMP102
temp_c = cpu.temperature
temp_c1 = temp_c + 5.0
temp_c2 = temp_c - 35.0
# Add y to list
ys1.append(temp_c)
ys2.append(temp_c1)
ys3.append(temp_c2)
# Limit y list to set number of items
ys1 = ys1[-x_len:]
ys2 = ys2[-x_len:]
ys3 = ys3[-x_len:]
# Update line with new Y values
line1.set_ydata(ys1)
line2.set_ydata(ys2)
line3.set_ydata(ys3)
return line1, line2, line3,
#************************************************************************#
#*******************Tkinter Window Initalization*************************#
class MyApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self,"EMEA Vicor Charging Application ")
img=tk.PhotoImage(file='/home/pi/Pictures/Vicor_Icon1.png')
self.tk.call('wm','iconphoto',self._w,img)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
#*********************************************************
#******Function Required to Display Seperate Pages********
self.frames = {}
for F in (StartPage, HomePage, PageOne):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
#*********************************************************
#*********************************************************
#Start Page - Agreement
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#Page One - Primary Terminal
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
tk.Frame.__init__(self, parent, bg = "white")
# Two Frames Need to be Established on Page One (Which is a “Higher Order Frame”)
my_window = Tk()
frame_name = Frame(my_window)
frame_addr = Frame(my_window)
label_f = Label(frame_name, text = "Check")
label_f.grid(row = 0, column = 0)
label_g = Label(frame_addr, text = "Correct")
label_g.grid(row = 0, column = 0)
frame_name.grid(row = 0, column = 0)
frame_addr.grid(row = 0, column = 1)
#my_window.mainloop()
app = MyApp()
app.geometry("1010x700")
ani = animation.FuncAnimation(fig1, updateData, blit = True, interval = stepms)
app.mainloop()
Page One will contain my Canvas for the Graph and Tool Bar. however to simplify the problem into its fundamental, getting two frames to make up "Higher Order" frame PageOne, with each subframe containing a label. When I run the code, another window opens with the two labels displayed. This is more progress than from other solutions that i can't implement/don't understand, producing error messages i can't respond to. I am self taught at python, and have been following tutorials from the community. I just need some help implementing the solution. If I've gutted my code to much i can provide a more comprehensive code snippet. But the essence of the problem is, while displaying one of several frames on a Tkinter Window which move to the foreground when requested, how do you split one of these "High Order" frames into two frames as to allow two different geometric plotters to be used to structure each one.
Resources Used So Far: https://www.youtube.com/watch?v=Mxk4cMBaH3g&list=PL6lxxT7IdTxGoHfouzEK-dFcwr_QClME_&index=37&t=0s [Most Recent Attempt - Trying to Simplify the problem]
how to make two split up screen ( canvas) inside the python tkinter window
http://www.openbookproject.net/courses/python4fun/tkphone1.html
matplotlib Navigation Bar error 'FigureCanvasTkAgg' object has no attribute 'manager' in tkinter
Displaying Matplotlib Navigation Toolbar in Tkinter via grid [Hit the Same Problem - One Master Frame Split Into Two Sub Frames] [This Link is probably has the answer in it and if that is the case, apologies for repeating a question already asked on stack overflow)
EDIT. To Expand Further for Clarity take the code below:
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
#import Tkinter as tk # python 2
#import tkFont as tkfont # python 2
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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 (StartPage, PageOne, PageTwo):
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("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page Two",
command=lambda: controller.show_frame("PageTwo"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
how would i get PageTwo to compose of two different frames so i can use two different geometric plotters (pack() and grid()).