How do I plot multiple files in a single graph? - python

I am new to programming. This program I have here is to read and plot 'n' files of xvg format to compare the graphs.
I want the program to be able to let me add as many xvg files as I want and plot them all in a single graph(each of different color) so that they can be compared.
I wrote the program and was able to plot the graph for only a single file at a time. Each file is opening up in a new window.
from tkinter import *
import matplotlib.pyplot as plt
import numpy as np
from tkinter import filedialog
plt.rcParams.update({'font.size':15})
root = Tk()
root.title("Graph plotter")
root.geometry("900x800")
def processxvg(filename):
x, y = [], []
with open(filename) as f:
for line in f:
if line[0] != "#" and line[0] != "#":
cols = line.split()
if len(cols) == 2:
x.append(float(cols[0]))
y.append(float(cols[1]))
return x,y
def random_color():
levels = range(32,256,32)
return tuple(random.choice(levels) for _ in range(3))
def browsefunc():
global filename
filename = filedialog.askopenfilename()
pathlabel.config(text=filename)
def addbox():
browsebutton = Button(root, text="Browse", command=browsefunc)
browsebutton.pack()
my_label = Label(root, text= "Browse the xvg file in the dir", font =("Ariel", "20") )
my_label.pack()
pathlabel = Label(root)
pathlabel.pack()
def clicked1():
(x, y) = processxvg(filename)
f = plt.figure()
f.set_figwidth(20)
f.set_figheight(10)
plt.plot(x,y)
plt.xlabel("Time (ns)", fontsize="35", labelpad=25)
plt.ylabel("RMSD (nm)", fontsize="35", labelpad=25)
plt.legend()
plt.show()
add_files_button = Button(root, text ="Add files", command = addbox)
add_files_button.pack()
plotbutton = Button(root, text ="Plot", command = clicked1 )
plotbutton.pack(pady = 10)
root.mainloop()

You are currently creating a new figure object every time the clicked1 function is called. The simplest solution would be to bring the figure creation outside of the function definition. I would also explicitly use the axis object to ensure everything plots on the same axis:
f, ax = plt.subplots(figsize=(20, 10))
ax.set_xlabel("Time (ns)", fontsize="35", labelpad=25)
ax.set_ylabel("RMSD (nm)", fontsize="35", labelpad=25)
plt.ion() # Enable interactive plotting
def clicked1():
(x, y) = processxvg(filename)
ax.plot(x,y)
ax.legend()
plt.show()
Ideally you would not use global variables, but instead pass ax as an argument to clicked1.

Related

finding peaks in a vibration signal

I am new in python and I just graduated and my thesis was about vibratory analysis, so when I started learning python. I wanted to make an an app that reads the signal and gives spesific informations about the graph such as peaks, here is what I have for now
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd
import matplotlib.pyplot as plt
from matplotlib.widgets import Cursor
import numpy as np
import os
Raw_1 = []
Raw_2 = []
clean_1 = []
clean_2 = []
# create the root window
root = tk.Tk()
root.title("Yazid ")
root.resizable(True, True)
root.geometry("400x400")
# full screen
class FullScreenApp(object):
def __init__(self, master, **kwargs):
self.master = master
pad = 3
self._geom = "200x200+0+0"
master.geometry(
"{0}x{1}+0+0".format(
master.winfo_screenwidth() - pad, master.winfo_screenheight() - pad
)
)
master.bind("<Escape>", self.toggle_geom)
def toggle_geom(self, event):
geom = self.master.winfo_geometry()
print(geom, self._geom)
self.master.geometry(self._geom)
self._geom = geom
def select_file():
filetypes = (("text files", "*.txt"), ("All files", "*.*"))
# get the txt file
filename = fd.askopenfilename(
title="select file", initialdir="/", filetypes=filetypes
)
# Get the raw list
for line in open(filename, "r"):
lines = [i for i in line.split(" ")]
Raw_1.append(lines[0].replace(",", "."))
Raw_2.append(lines[1].replace(",", "."))
# clean means get rid of the first three lines
for item in Raw_1[3:]:
clean_1.append(item)
for item in Raw_2[3:]:
clean_2.append(item)
# convert to float (geting the X and Y axes)
x = [float(i) for i in clean_1]
y = [float(i) for i in clean_2]
# plotting the points
fig = plt.figure()
ax = fig.subplots()
ax.plot(x, y, color="r")
ax.grid()
# naming the x axis
plt.xlabel(Raw_2[0])
# naming the y axis
plt.ylabel(Raw_1[0])
# title graph
fname = os.path.splitext(filename)[0]
name = os.path.basename(fname)
plt.title(name)
# Defining the cursor
cursor = Cursor(ax, horizOn=True, vertOn=True, useblit=True, color="r", linewidth=1)
# Creating an annotating box
annot = ax.annotate(
"",
xy=(0, 0),
xytext=(-40, 40),
textcoords="offset points",
bbox=dict(boxstyle="round4", fc="linen", ec="k", lw=1),
arrowprops=dict(arrowstyle="-|>"),
)
annot.set_visible(False)
# function to show the plot
plt.show()
# open button
open_button = ttk.Button(root, text="Open a File", command=select_file)
open_button.pack(expand=True)
# run the application
root.mainloop()
I am removing the first three lines because the first line contains the name of each column and the next two lines have some transient (I have more than 1600 values)
My code gives the following result
I want it to mark those peaks and give me their value on the y axes
and thank you
You could start with scipy.signal.find_peaks. In the documentation you will find how to do an example like this.
The orange crosses are the points selected with find_peaks, you have several parameters to tune, and it will probably be more productive than if you try to implement from scratch. After that if your can do a better job what is done by that function you can contribute to the library with your implementation.

How to plot an automatic graph using mouse without clicking MATPLOTLIB

I'm looking to plot Data automatically using mouse without clicking From a DZT file.
i Created a program in order to plot data as you can see in this graph:
As you can see in this picture, x axes going from 0 to 3525 ans every x is a signal so i have more than 3500 signals making this graph.
for exemple if i want to see the signal of x=999, it looks like this.
what i want really to do is every time when i pass my mouse without clicking on the graph it should plot it's signal automatically .
i try to use a lot of methods but rally i dont know how to do it.
i'll be grateful for your help
this is my file:
https://www.grosfichiers.com/mvabGETFfna
This is my program:
from tkinter import *
from tkinter import messagebox, filedialog
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import os
from readgssi import readgssi
root = Tk()
root.title("IHM")
root.geometry("1000x800")
Resources_frame = LabelFrame(root, bd=2, relief=GROOVE, text="Conversion Area")
Resources_frame.place(x=5, y=5, width=250, height=80)
lbl_ra = Label(Resources_frame, text="Select your File ")
lbl_ra.grid(row=0, column=0, sticky=W)
lbl_ra = Label(Resources_frame, text="Convert Selected file ")
lbl_ra.grid(row=1, column=0, sticky=W)
NumberOfSimples = ''
DataAScan = ''
Data = ''
xData = ''
xAxes = ''
def ReadDZT():
file_path = filedialog.askopenfilename()
file_name, file_extension = os.path.splitext(file_path)
print(file_extension)
if file_extension == '.DZT':
messagebox.showinfo("INFO", "Your DZT File Has Been Selected Successfully")
hdr, arrs, gps = readgssi.readgssi(infile=file_path, verbose=True)
TimeRange = hdr['rhf_range']
Samples = hdr['rh_nsamp']
X_Axes = np.array(range(0, Samples))
xAxes = X_Axes[2::1]
df = pd.DataFrame(arrs[0])
Data = df.iloc[2::1, 0::1]
fig2 = plt.figure()
plt.plot(xAxes, Data[999])
plt.show()
fig = plt.figure()
plt.imshow(Data, aspect='auto', cmap='bone')
plt.show()
elif file_extension == '.csv':
messagebox.showinfo("INFO", "Your CSV File Has Been Selected Successfully")
df = pd.read_csv(file_path)
NumberOfSimples = df.iloc[2::1, 0]
Data = df.iloc[::1, ::1]
DataAScan = df.iloc[2::1, 999]
fig1 = plt.figure()
plt.plot(NumberOfSimples, DataAScan)
plt.show()
fig2 = plt.figure()
plt.imshow(Data, aspect='auto', cmap='bone')
plt.show()
else:
messagebox.showwarning("WARNING", "You Have Been Selected a Different Format")
# =============Resources Buttons================#
btn_rs = Button(Resources_frame, relief=GROOVE, padx=8, pady=1, text="Browse", command=ReadDZT).grid(row=0,
column=1)
root.mainloop()
As indicated in the previous question Ploting a graph automatically using mouse coordinate (and I think this question should have been an edit of it), the mouse motion can be monitored with plt.connect('motion_notify_event', mouse_move). The slice of Data to be plotted in fig2 simply corresponds to the x-coordinate of the mouse, that is Data[int(event.xdata)] in mouse_move(event).
Therefore, in mouse_move(event), you:
Clear the axis: ax2.clear() (where ax2 is the AxesSubplot object of fig2)
Plot the slice ax2.plot(self.xAxes, self.Data[int(event.xdata)])
Update the figure fig2.canvas.draw_idle()
However, I had issues with using simultaneously the matplotlib figures and the tkinter GUI because of the separate event loops. Therefore I embedded the figures in the tkinter GUI directly (see e.g. https://matplotlib.org/3.4.0/gallery/user_interfaces/embedding_in_tk_sgskip.html).
I also put the graph related code in a class to keep the loaded data in attributes to avoid using global variables.
import tkinter as tk
from tkinter import messagebox, filedialog
import pandas as pd
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import numpy as np
import os
from readgssi import readgssi
class Graphs(tk.Toplevel):
def __init__(self, master=None, **kw):
tk.Toplevel.__init__(self, master, **kw)
self.rowconfigure(0, weight=1)
self.rowconfigure(2, weight=1)
# data
self.Data = []
self.xData = []
self.xAxes = []
self.line = None
# figure1 : 2D data map
self.fig1 = Figure()
self.ax1 = self.fig1.add_subplot(111)
self.canvas1 = FigureCanvasTkAgg(self.fig1, self)
self.canvas1.draw()
self.canvas1.get_tk_widget().grid(sticky='ewsn')
self.toolbar1 = NavigationToolbar2Tk(self.canvas1, self, pack_toolbar=False)
self.toolbar1.grid(sticky="ew")
# figure 2: slice plot
self.fig2 = Figure()
self.ax2 = self.fig2.add_subplot(111)
self.canvas2 = FigureCanvasTkAgg(self.fig2, self)
self.canvas2.draw()
self.canvas2.get_tk_widget().grid(sticky='ewsn')
self.toolbar2 = NavigationToolbar2Tk(self.canvas2, self, pack_toolbar=False)
self.toolbar2.grid(sticky="ew")
# bind plotting to mouse motion
self.canvas1.mpl_connect('motion_notify_event', self.mouse_move)
def mouse_move(self, event):
x = event.xdata
if len(self.Data) and x is not None: # there is something to plot
self.ax2.clear()
x = int(x)
self.ax2.plot(self.xAxes, self.Data[x])
self.line.set_data([x, x], [len(self.Data), 0])
self.canvas1.draw_idle()
self.canvas2.draw_idle()
def readDZT(self):
file_path = filedialog.askopenfilename()
file_name, file_extension = os.path.splitext(file_path)
if file_extension == '.DZT':
messagebox.showinfo("INFO", "Your DZT File Has Been Selected Successfully")
hdr, arrs, gps = readgssi.readgssi(infile=file_path, verbose=True)
Samples = hdr['rh_nsamp']
X_Axes = np.array(range(0, Samples))
self.xAxes = X_Axes[2::1]
df = pd.DataFrame(arrs[0])
self.Data = df.iloc[2::1, 0::1]
# clear plots
self.ax1.clear()
self.ax2.clear()
# plot slice
self.ax2.plot(self.xAxes, self.Data[999])
self.canvas2.draw_idle()
# plot 2D map
self.ax1.imshow(self.Data, aspect='auto', cmap='bone')
self.line = self.ax1.plot([999, 999], [len(self.Data), 0], 'r')[0]
self.ax1.set_ylim(len(self.Data), 0)
self.canvas1.draw_idle()
else:
messagebox.showwarning("WARNING", "You Have Been Selected a Different Format")
root = tk.Tk()
root.title("IHM")
root.geometry("1000x800")
Resources_frame = tk.LabelFrame(root, bd=2, relief=tk.GROOVE, text="Conversion Area")
Resources_frame.place(x=5, y=5, width=250, height=80)
tk.Label(Resources_frame, text="Select your File ").grid(row=0, column=0, sticky=tk.W)
tk.Label(Resources_frame, text="Convert Selected file ").grid(row=1, column=0, sticky=tk.W)
graphs = Graphs(root)
btn_rs = tk.Button(Resources_frame, relief=tk.GROOVE, padx=8, pady=1, text="Browse",
command=graphs.readDZT).grid(row=0, column=1)
root.mainloop()

Confusion over plt and plot to get a plot to display on canvas on a frame in Tkinter

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
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 interface
when 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.
Object-oriented interface:
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")

How to draw multiple lines on the same graph in tkinter?

I am new to tkinter and I need to be able to draw more than one line plot on the same chart each with its own legend. I can do this in matplotlib using show () but then the graph becomes separate from the GUI window. My code takes files from a file list I have created and then plots them on the screen but keeps overwriting each graph - Is there a way of doing this so all the line charts appear on the same chart in tkinter?
for item in myfile_list:
x, y = np.loadtxt(item + '_' + 'Test.csv', skiprows=1, usecols=[x_axis_column, y_axis_column],
unpack=True, delimiter=',')
# graph size in inches
fig = Figure(figsize=(5, 5))
a = fig.add_subplot(111)
a.plot(x, y, color='blue')
a.set_title("Title", fontsize=16)
a.set_ylabel("Y", fontsize=14)
a.set_xlabel("X", fontsize=14)
canvas = FigureCanvasTkAgg(fig, master=chart_frame)
# place graph in first row and column of chart_frame
canvas.get_tk_widget().grid(row=0, column=0)
canvas.draw()
toolbar_frame = Frame(plot_frame)
toolbar_frame.grid(row=1, column=0)
toolbar = NavigationToolbar2Tk(canvas, toolbar_frame)
toolbar.update()
output
# use tkchart module....
# https://pypi.org/project/tkchart/
# https://github.com/Thisal-D/tkchart
import tkchart
import tkinter
root = tkinter.Tk()
#create chart
chart_1 = tkchart.LineChart(master=root,width=1000 ,height=600
,chart_line_len=80 ,sections=True
,sections_count=10 ,values_labels=True
,values_labels_count=5 ,
max_value = 100)
chart_1.pack()
#create lines for chart
line_1 = tkchart.Line(master=chart_1 ,color="#00ff00" ,height=4)
line_2 = tkchart.Line(master=chart_1 ,height=4 ,color ="#ffff00")
value = [x for x in range(0,100)]
import random
def display():
chart_1.display(line=line_1 ,values=random.choices(value))
chart_1.display(line=line_2 ,values=random.choices(value))
root.after(500,display)
display()
root.mainloop()

stop tkinter mainloop disrupting matplotlib

hi I'm a student and I'm working with ktinker for the first time. I am currently trying to create a program that follows this order:
open a map in matplotlib
a popup window is called for users to enter in information
when the user clicks on the map grid the coordinates and user
info are stored in a dictionary
matplotlib generates a plot point on the location
The trouble is, when I call the popup window I have written in tkinter, calling the mainloop() function breaks the matplotlib window and it wont generate the plot points until the map window is closed.
getting rid of the mainloop fixes it but then means i cant get the data from the popup.
Anyone know how I can stop one from interfering with the other? i have to keep them in separate classes as Im meant to demonstrate modularity in my code.
here is the main code
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import popup1 as ap
__author__ = "k1221169"
__date__ = "$15-Nov-2015 11:29:21$"
markerList = []
xplots = []
yplots = []
desc = ''
title = ''
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(np.random.rand(10))
img = mpimg.imread('overland map 1.png')
imgplot = plt.imshow(img)
plt.ylim(ymax=1)
plt.xlim(xmin=1)
def mrkApnd(a,b):
a.update(b)
print a
markerList.append(a)
def onclick(event):
if spacecheck(event.xdata, event.ydata):
#print markerList[0]['x']
idx = np.abs(xplots - event.xdata).argmin()
print xplots[idx]
for i in markerList:
if xplots[idx] == i['x'] :
print i
#c = i
ap.useroutput(i)
else:
input1 = ap.userinput()
input2 = {'x':event.xdata, 'y':event.ydata}
input1['title'] = title
input1['desc'] = desc
mrkApnd(input1,input2)
drawMarks()
print input1
return markerList
cid = fig.canvas.mpl_connect('button_press_event', onclick)
def drawMarks():
plt.ion()
for i in markerList:
xplots.append(i['x'])
yplots.append(i['y'])
plt.plot(i['x'], i['y'], i['type'])
def spacecheck(x,y):
a = bool
if np.isclose(xplots, x, atol=50.0).any() and np.isclose(yplots, y, atol=50.00).any():
a=True
print 'yes'
return a
plt.draw()
plt.show()
and here is the popup code called from another file
from Tkinter import *
class popup1():
def __init__(self):
pass
def userinput():
pop = Toplevel()
pop.title("marker")
pop.geometry("300x500+200+200")
#string for title
frame = Frame(pop)
entry = Entry(frame)
entry.pack(side = TOP)
frame.pack( padx =20, pady =20)
#radius button for visibility
frame2 = Frame(pop)
selection = StringVar()
radio_1 = Radiobutton(frame2, text = 'Character', variable = selection, value = 'ob')
radio_2 = Radiobutton(frame2, text = 'Item', variable = selection, value = 'or')
radio_3 = Radiobutton(frame2, text='Event', variable = selection, value = 'oy')
radio_1.select()
radio_1.pack(side = LEFT)
radio_2.pack(side = LEFT)
radio_3.pack(side = LEFT)
frame2.pack(padx =30, pady =30)
#radius button for marker type
frame3 = Frame(pop)
visible = bool
check_1 = Checkbutton(frame3, text = 'GM Only', variable = visible, onvalue= True, offvalue= False)
check_1.pack(side = LEFT)
frame3.pack(padx =30, pady =30)
#string for user input
frame4 = Frame(pop)
entry4 = Entry(frame4)
entry4.pack(side = LEFT)
frame4.pack( padx =20, pady =20)
def infoPass():
#info1 = {'title': entry.get(), 'type': selection.get(), 'vis': visible, 'Desc': entry4.get()}
#info.update(info1)
#print info
pop.destroy()
#buttons
label = Label(pop, text="", height=0, width=100)
label.pack()
b = Button(pop, text="Cancel", width=20, command= pop.destroy )
b.pack(side='bottom',padx=5,pady=5)
b2 = Button(pop, text="Save", width=20, command= infoPass )
b2.pack(side='bottom',padx=5,pady=5)
info = {'title': entry.get(), 'type': selection.get(), 'vis': visible, 'desc': entry4.get()}
pop.mainloop()
return info
If i underdstood your question right, then try to add your own loop.
Remove pop.mainloop()
Make the code be a class for a cleaner code
class userinput:
def __init__(self):
#open your window here and style it etc. and:
self.data_sent = False
def infopass(self):
self.data_sent = True
#your infopass code here and
Create your own loop at the end of init:
def __init__(self):
#...
while self.data_sent == False:
root.update()
while data_sent == False:
pop.update()
Call your popup by
mypopup = userinput()
Good luck ;)

Categories

Resources