Reputation: 909
I have been working on a gui to display a graph of values by two indices. That works fine as a standalone py file. I have made a gui that will successfully plot and clear a plot on a frame on canvas. I cannot figure out how to merge the two. The issue is in my plotData function (I have added and commented out a version of it that works very well with a simpler graph). I know my problem is in these lines below because I am using both plt and plot1, but now I don't know anymore what either of them do.
#fig1=plt.figure(1)
if len(blob0)>0:
plt.plot(blob0_et, blob0_acc, "s", color="blue", markersize=10, label = '0')
if len(blob1)>0:
plt.plot(blob1_et, blob1_acc, "s", color="red", markersize=10, label = '1')
if len(blob2)>0:
plt.plot(blob2_et, blob2_acc, "s", color="green", markersize=10, label = '2')
plot1 = fig.add_subplot(111) # adding the subplot
plot1.plot(y) # plotting the graph
plot1.set_title ("Circle Calibration, Accumulator vs Edge Threshold", fontsize=12)
plot1.set_ylabel("Accumulator", fontsize=14)
plot1.set_xlabel("Edge Threshold", fontsize=14)
Full Code
import tkinter.filedialog
import os
import tkinter as tk
from tkinter import ttk
import matplotlib
matplotlib.use("TkAgg") # this is the backend of matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import easygui
from matplotlib.legend_handler import HandlerLine2D
import simple_data
import ETvACCUM3
root = tk.Tk()
root.title("Tab Widget")
root.geometry("500x350")
tabControl = ttk.Notebook(root)
tab1 = ttk.Frame(tabControl)
tab2 = ttk.Frame(tabControl)
tab3 = ttk.Frame(tabControl)
tab4 = ttk.Frame(tabControl)
tabControl.add(tab1, text ='Tab 1')
tabControl.add(tab2, text ='Tab 2')
tabControl.add(tab3, text ='Tab 3')
tabControl.add(tab4, text ='Tab 4')
tk.Grid.rowconfigure(root, 0, weight=1)
tk.Grid.columnconfigure(root, 0, weight=1)
tabControl.grid(column=0, row=0, sticky=tk.E+tk.W+tk.N+tk.S)
#=====================================================================
# TAB 2
#=====================================================================
#=====================================================================
# my_frame_1 and its contents
#=====================================================================
# creating a frame (my_frame_1)
my_frame_1 = tk.Frame(tab2, bd=2, relief=tk.GROOVE)
my_frame_1.pack(side=tk.LEFT, anchor=tk.N, fill=tk.BOTH, expand=True)
#---------------------------------------------------------------------
# the figure that will contain the plot
fig = Figure(figsize = (5, 5), dpi = 100)
#=====================================================================
# frame2 and widgets it contains.
#=====================================================================
def plotData():
fig.clear()
file = easygui.fileopenbox(msg=None, title=None, default="/Users/.../Desktop/tk_gui_grid/", filetypes = None, multiple = False)
print('\n', "This is the selected file:", file, '\n')
# load data as a pandas dataframe
df = pd.read_csv(file, sep='\t', lineterminator='\n')
# make a smaller array by using the loc
df = df.loc[:,['Accum', 'EdgeThr','NumberOfBlobs']]
blob0 = []
blob1 = []
blob2 = []
blob0 = df[df['NumberOfBlobs'] == 0][['Accum', 'EdgeThr']]
blob1 = df[df['NumberOfBlobs'] == 1][['Accum', 'EdgeThr']]
blob2 = df[df['NumberOfBlobs'] == 2][['Accum', 'EdgeThr']]
blob0 = blob0.values.tolist()
blob1 = blob1.values.tolist()
blob2 = blob2.values.tolist()
print('blob2: ',blob2, '\n'*3)
fontTitle = {'family': 'arial',
'color': 'darkred',
'weight': 'normal',
'size': 16,
}
fontAxisLabels = {'family': 'helvetica',
'color': 'darkblue',
'weight': 'normal',
'size': 16,
}
if len(blob0)>0:
blob0_acc, blob0_et = map(list, zip(*blob0))
if len(blob1)>0:
blob1_acc, blob1_et = map(list, zip(*blob1))
if len(blob2)>0:
blob2_acc, blob2_et = map(list, zip(*blob2))
#fig1=plt.figure(1)
if len(blob0)>0:
plt.plot(blob0_et, blob0_acc, "s", color="blue", markersize=10, label = '0')
if len(blob1)>0:
plt.plot(blob1_et, blob1_acc, "s", color="red", markersize=10, label = '1')
if len(blob2)>0:
plt.plot(blob2_et, blob2_acc, "s", color="green", markersize=10, label = '2')
plot1 = fig.add_subplot(111) # adding the subplot
plot1.plot(y) # plotting the graph
plot1.set_title ("Circle Calibration, Acc vs ET", fontsize=12)
plot1.set_ylabel("Acc", fontsize=14)
plot1.set_xlabel("ET", fontsize=14)
toolbar = NavigationToolbar2Tk(my_canvas, my_frame_1)
toolbar.update()
my_canvas.get_tk_widget().pack(side = tkinter.TOP, fill = tkinter.BOTH, expand = 1)
my_canvas.draw_idle()
plt.axis([0,250,0,50])
plt.xlabel('Edge Threshold', fontdict = fontAxisLabels, fontsize = 12)
plt.ylabel('Accumulator', fontdict = fontAxisLabels, fontsize = 12)
plt.title('Accum vs Edge threshold', fontname='arial', color=('black'),fontdict = fontTitle,fontsize = 10)
plt.legend(loc = "upper right")
def getDataFile():
file = easygui.fileopenbox(msg=None, title=None, default="/Users/.../Desktop/tk_gui_grid/", filetypes = None, multiple = False)
print('\n', "This is the selected file:", file, '\n')
# load data as a pandas dataframe
df = pd.read_csv(file, sep='\t', lineterminator='\n')
print(df)
return df
"""
# this function successfully placed a simple plot onto the canvas when the button was pressed
def plotData():
fig.clear()
y = simple_data.some_yVals() #imported from a function in another module
plot1 = fig.add_subplot(111) # adding the subplot
plot1.plot(y) # plotting the graph
plot1.set_title ("Circle Calibration, Accumulator vs Edge Threshold", fontsize=12)
plot1.set_ylabel("Accumulator", fontsize=14)
plot1.set_xlabel("Edge Threshold", fontsize=14)
toolbar = NavigationToolbar2Tk(my_canvas, my_frame_1)
toolbar.update()
my_canvas.get_tk_widget().pack(side = tkinter.TOP, fill = tkinter.BOTH, expand = 1)
my_canvas.draw_idle()
"""
def clearPlot():
fig.clear()
my_canvas.draw_idle()
my_canvas = FigureCanvasTkAgg(fig, master = my_frame_1) # creating the Tkinter canvas containing the Matplotlib figure
my_canvas.get_tk_widget().pack() # placing the canvas on the Tkinter window
my_canvas.draw()
#create another frame(my_frame_2)
my_frame_2 = tk.Frame(tab2, bd=2, relief=tk.GROOVE)
my_frame_2.pack(side=tk.RIGHT)
#---------------------------------------------------------------------
button1 = tk.Button(my_frame_2, text = "Browse \nfiles", command = getDataFile, relief = tk.GROOVE, bg = "red", padx =20,pady =20 )
button1.pack(side="top", fill="x")
button2 = tk.Button(my_frame_2, text = "Plot \nData", command = plotData, relief = tk.GROOVE, bg = "red", padx =20,pady =20 )
button2.pack(side="top", fill="x" )
button3 = tk.Button(my_frame_2, text = "Clear \nPlot", command = clearPlot, relief = tk.GROOVE, bg = "red", padx =20,pady =20 )
button3.pack(side="top", fill="x")
button4 = tk.Button(my_frame_2, text = "Doggy", relief = tk.GROOVE, bg = "red", padx =20,pady =20 )
button4.pack(side="top", fill="x")
root.mainloop()
print('\n'*4)
*** Desired output ***
Any knowledge that helps me understand how to get the plots onto the canvas and to understand the difference between plt.plot and plot1.plot
Upvotes: 0
Views: 231
Reputation: 69116
You should read about the difference between the matplotlib object-oriented interface and the pyplot
interface.
In your case you have mixed the two:
pyplot
interfacewhen you call plt.plot
, matplotlib will create an Axes instance if one does not already exist, or if one does, it will plot on the current Axes.
You create an Axes instance called plot1
using plot1 = plt.subplots(111)
, and then call the function plot
from that instance: plot1.plot()
. Anything you call from an Axes instance will be displayed on that Axes.
This issue likely comes because an Axes instance is created from your first plt.plot
, but then you call plt.subplots
and possibly create a different Axes instance which is used for everything afterwards.
In my opinion, it is usually better to use the object-oriented approach, since that way you always know where things you plot are going to end up. Its almost always a bad idea to mix the two approaches, as things end up getting confused somewhere.
Note that in the documentation and in many examples you will see around the web, the Axes instance is often called ax
or ax1
, rather than plot1
which you have here. Both will work just fine, but that might help to keep in mind when looking at examples elsewhere.
Its hard to tell exactly, and you don't say quite what your desired outcome is, but I think you probably want something like this. Create the plot1
Axes instance before you plot blob0
, blob1
or blob2
, then call plot1.plot
for those three plotting functions too. That should ensure it all turns up on the same Axes.
plot1 = fig.add_subplot(111) # adding the subplot
if len(blob0)>0:
plot1.plot(blob0_et, blob0_acc, "s", color="blue", markersize=10, label = '0')
if len(blob1)>0:
plot1.plot(blob1_et, blob1_acc, "s", color="red", markersize=10, label = '1')
if len(blob2)>0:
plot1.plot(blob2_et, blob2_acc, "s", color="green", markersize=10, label = '2')
plot1.plot(y) # plotting the graph
plot1.set_title ("Circle Calibration, Acc vs ET", fontsize=12)
plot1.set_ylabel("Acc", fontsize=14)
plot1.set_xlabel("ET", fontsize=14)
Its probably not required, but if you are changing to the object-oriented interface, you might as well go the whole way and change it everywhere. For example, these lines:
plt.axis([0,250,0,50])
plt.xlabel('Edge Threshold', fontdict = fontAxisLabels, fontsize = 12)
plt.ylabel('Accumulator', fontdict = fontAxisLabels, fontsize = 12)
plt.title('Accum vs Edge threshold', fontname='arial', color=('black'),fontdict = fontTitle,fontsize = 10)
plt.legend(loc = "upper right")
should become:
plot1.axis([0,250,0,50])
plot1.set_xlabel('Edge Threshold', fontdict = fontAxisLabels, fontsize = 12)
plot1.set_ylabel('Accumulator', fontdict = fontAxisLabels, fontsize = 12)
plot1.set_title('Accum vs Edge threshold', fontname='arial', color=('black'),fontdict = fontTitle,fontsize = 10)
plot1.legend(loc = "upper right")
Upvotes: 2