Real-time matplotlib plotting within tkinter class object fed by multiprocess module queue - class

I have a fairly generic problem where I have a tkinter gui. I'm spawning sub-windows as sub-classes, and those sub-windows launch computationally heavy processes with unknown time-delays using the multiprocess package. This computationally heavy process occasionally pushes a result into a queue, which is monitored by a graphing loop using matplotlib in the main process of the sub-window class. Using multiple different approaches, which work in other contexts, I've been unable to get this graph to update live with a pretty basic python 3.11 install.
I'm sure there are multiple fundamental things with the packages I'm using which I do not understand. I'm fundamentally a hardware guy, and I hack and slash my way to self-automation (or self-replication) when necessary. I'm working very hard to move away from Matlab and Igor so I can compile things for free w/o spending forever creating my own classes. This particular lunatic greatly appreciates any help the broader community could throw him now that he's wandered in from the wilderness. I am open to broad answers. If the most correct is 'learn QT5', I will. I'm at a dead end.
The first approach uses solution from: Python realtime plotting
This approach works just fine as-is in my python install when I run it directly from console. It doesn't work when launched within spyder for some known issues. It breaks down when i run it directly from console within my class:
# -*- coding: utf-8 -*-
"""
Spyder Editor
This is a temporary script file.
Made by Matthew Earl Wallace the Reed
"""
#import os
import time
import numpy as np
#import cv2
#import scipy as sp
import matplotlib.pyplot as plt
#import matplotlib as mpl
try:
from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg
except ImportError:
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk as NavigationToolbar2TkAgg
#from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
#import scipy.ndimage as nd
#from scipy.optimize import curve_fit, differential_evolution, least_squares
#import warnings
import multiprocess
#from IPython import get_ipython
#get_ipython().run_line_magic('matplotlib','qt')
#from scipy.interpolate import interp1d
#import dill
import tkinter as tk
#from tkinter import filedialog
#import glob
#import os.path
#from scipy.stats import linregress
#from scipy.stats import norm as normdist
#from copy import deepcopy
#from scipy.signal import find_peaks, peak_widths
#import matplotlib.colors as colors
#from tkinter import messagebox
#from datetime import date
#import threading as td
#import pyautogui as pg
#import multiprocessing as mp
#import time as time
from functools import partial
class trueautoLOL(tk.Toplevel):
def __init__(self,parent):
super().__init__(parent)
lengthtarget=float(tk.simpledialog.askstring('length','feed me length'))
tolerance=float(tk.simpledialog.askstring('Tolerance','Mas o menos'))
uniformitytarget=float(tk.simpledialog.askstring('Uniformity','What\'s good brother?'))
self.geometry('300x200')
self.title('I\'m a horrible window love me anyway')
q=multiprocess.Queue()
def genplot(parent):
global line,ax,canvas, fig, x,y, li
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
# some X and Y data
x = [0]
y = [0]
li, = ax2.plot(x, y,'o')
# draw and show it
fig2.canvas.draw()
plt.show(block=False)
genplot(self)
def optloop(q):
print("Istarted")
uniformity=np.random.rand(1)*100
length=np.random.rand(1)*100
error=200
counter=0
while uniformity>uniformitytarget or length>lengthtarget+tolerance or length<lengthtarget-tolerance:
time.sleep(1)
theset=np.random.rand(1)*20
print(theset)
q.put(theset)
error=np.random.rand(1)*100
uniformity=np.random.rand(1)*100
length=np.random.rand(1)*100
counter=counter+1
print(q)
q.put('Q')
def updateplot(q):
try:
result=q.get(False)
print(result)
if result != 'Q':
print(result)
x=[0,1,2]
y=[0,result,2]
# set the new data
li.set_xdata(x)
li.set_ydata(y)
ax.relim()
ax.autoscale_view(True,True,True)
fig.canvas.draw()
plt.pause(1)
updateplot(q)
else:
print('done')
except:
print("empty")
self.after(500,updateplot,q)
theprocess=multiprocess.Process(target=optloop,args=[q])
theprocess.start()
print(theprocess.is_alive())
updateplot(q)
def autoLOL():
window=tk.Tk()
window.title("LOOOL")
window.geometry('900x250')
updateLOL=tk.Button(window, text="True AutoLOL", command=partial(trueautoLOL,window))
updateLOL.grid(column=3,row=3)
window.mainloop()
if __name__=='__main__':
autoLOL()
The second approach attempts to use the tkinter canvas directly (and was my chronological first approach, into which I hacked-and-slashed the approach above).
The notable thing about this approach is that it WORKS, but only when launched from within spyder on a bog-standard anaconda 3.9 install with the extra packages installed w/ pip, but not when launched from spyder with a manual installation on python 3.11.
I'd very much like to cite the source of the overall architecture, but I copied it over sufficiently long ago I can no longer find it...
# -*- coding: utf-8 -*-
"""
Spyder Editor
This is a temporary script file.
Made by Matthew Earl Wallace the Reed
"""
import os
import time
import numpy as np
import cv2
import scipy as sp
import matplotlib.pyplot as plt
import matplotlib as mpl
try:
from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg
except ImportError:
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk as NavigationToolbar2TkAgg
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import scipy.ndimage as nd
from scipy.optimize import curve_fit, differential_evolution, least_squares
import warnings
import multiprocess
from IPython import get_ipython
#get_ipython().run_line_magic('matplotlib','qt')
from scipy.interpolate import interp1d
import dill
import tkinter as tk
from tkinter import filedialog
import glob
import os.path
from scipy.stats import linregress
from scipy.stats import norm as normdist
from copy import deepcopy
from scipy.signal import find_peaks, peak_widths
import matplotlib.colors as colors
from tkinter import messagebox
from datetime import date
import threading as td
import pyautogui as pg
import multiprocessing as mp
import time as time
from functools import partial
class trueautoLOL(tk.Toplevel):
def __init__(self,parent):
super().__init__(parent)
lengthtarget=float(tk.simpledialog.askstring('length','feed me length'))
tolerance=float(tk.simpledialog.askstring('Tolerance','Mas o menos'))
uniformitytarget=float(tk.simpledialog.askstring('Uniformity','What\'s good brother?'))
self.geometry('300x200')
self.title('I\'m a horrible window love me anyway')
q=multiprocess.Queue()
def genplot(parent):
global line,ax,canvas, fig
fig=mpl.figure.Figure()
ax=fig.add_subplot(1,1,1)
canvas = FigureCanvasTkAgg(fig, master=parent)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
plt.show(block=False)
line, = ax.plot([1,2,3], [1,2,10])
genplot(self)
def optloop(q):
print("Istarted")
uniformity=np.random.rand(1)*100
length=np.random.rand(1)*100
error=200
counter=0
while uniformity>uniformitytarget or length>lengthtarget+tolerance or length<lengthtarget-tolerance:
time.sleep(1)
theset=np.random.rand(1)*20
print(theset)
q.put(theset)
error=np.random.rand(1)*100
uniformity=np.random.rand(1)*100
length=np.random.rand(1)*100
counter=counter+1
print(q)
q.put('Q')
def updateplot(q):
try:
result=q.get(False)
print(result)
if result != 'Q':
print(result)
line.set_ydata(1,result,10)
ax.draw_artist(line)
ax.relim()
ax.autoscale_view(True,True,True)
fig.canvas.draw()
canvas.draw()
plt.show(block=False)
self.after(500,updateplot,q)
else:
print('done')
except:
print("empty")
self.after(500,updateplot,q)
theprocess=multiprocess.Process(target=optloop,args=[q])
theprocess.start()
print(theprocess.is_alive())
updateplot(q)
def autoLOL():
window=tk.Tk()
window.title("LOOOL")
window.geometry('900x250')
updateLOL=tk.Button(window, text="True AutoLOL", command=partial(trueautoLOL,window))
updateLOL.grid(column=3,row=3)
window.mainloop()
if __name__=='__main__':
autoLOL()
I've tried multiple solutions to live-updates of a matplotlib plot using a tkinter gui where the plot needs to periodically update in an infinite loop while fed data asynchronously by another process. Those solutions each individually work in very specific contexts, but fail in the context of my class-based multiprocessing architecture. I am open to anything that will work when 1. Function calls need to be performed on functions defined outside the class 2. some global variables are defined outside the class for said function calls and 3. the plotting update can happen periodically.
I've been working on this on-and-off for a month. My sole purpose is to monitor and plot data which is periodically output. If this can be done through file I/O or whatever, I'll do anything, simple or obtuse.

This was mostly a problem with multiprocessing & not fully understanding the matplotlib backend. The source for the canvas-based multiprocessing approach wasn't protecting things with
if __name__=='__main__':
so I wasn't either. When the multiprocess.Process was pickling (or dill'ing, as multiprocess module does) it was trying to re-run the functions initializing the window, re-start plots etc, which was frustrating the matplotlib backend.
The version version of the code I got to work is below:
class trueautoLOL(tk.Toplevel):
def __init__(self,parent):
super().__init__(parent)
lengthtarget=float(tk.simpledialog.askstring('length','feed me length'))
tolerance=float(tk.simpledialog.askstring('Tolerance','Mas o menos'))
uniformitytarget=float(tk.simpledialog.askstring('Uniformity','What\'s good brother?'))
self.geometry('300x200')
self.title('I\'m a horrible window love me anyway')
q=multiprocess.Queue()
fig = plt.figure()
ax = fig.add_subplot(111)
# some X and Y data
x = [0,1,2,3,4]
y = [0,1,2,3,4]
li, = ax.plot(x, y,'o')
# draw and show it
if __name__=='__main__':
fig.canvas.draw()
plt.show(block=False)
# loop to update the dat
q=multiprocess.Queue()
def datagen(qq):
qual=100
while qual<100.5:
data = [np.random.rand(1)*4,np.random.rand(1)*4,np.random.rand(1)*4,np.random.rand(1)*4,np.random.rand(1)*4 ]
qq.put(data)
qual = np.random.rand(1)*102
plt.pause(2)
qq.put('Q')
def plotter(qq):
try:
y=qq.get()
if y!='Q':
# set the new data
li.set_xdata(x)
li.set_ydata(y)
ax.relim()
ax.autoscale_view(True,True,True)
fig.canvas.draw()
plt.pause(1)
plotter(qq)
else:
print('Done')
plt.pause(1)
except:
print("empty")
plt.pause(1)
plotter(qq)
if __name__=='__main__':
theprocess=multiprocess.Process(target=datagen,args=[q])
theprocess.start()
plotter(q)
def autoLOL():
window=tk.Tk()
window.title("LOOOL")
window.geometry('900x250')
updateLOL=tk.Button(window, text="True AutoLOL",command=partial(trueautoLOL,window))
updateLOL.grid(column=3,row=3)
window.mainloop()
if __name__=='__main__':
autoLOL()

Related

Python Bokeh FileInput Widget for DLIS file

I am trying a web app in bokeh where i import a dlis file through the widget fileinput.
I am using the following libraries
from dlisio import dlis
from pybase64 import b64decode
import io
def upload_file_dlis(attr, old, new):
print('upload_file_dlis')
decoded = b64decode(new)
f = io.BytesIO(decoded)
file_input_dlis.on_change('value', upload_file_dlis)
I have the following issue:
OSError: '<_io.BytesIO object at 0x000001CE6507CF40>' is not an existing regular file
I guess it is because dlis files are not handled by Io library.
What is the best way to work on this?
Do you have any suggestions?

How can I save the results of different runs in a compare runs experiment in Anylogic?

I want to save the results of different runs in a compare runs experiment in Anylogic in an excel sheet or to some variable or output so that I use these values for some further calculations. How can I do that
Another flexible way of doing this is by writing the results to CSV. This should work for any kind of simulation or experiment with AnyLogic.
You'd have to import standard external libraries into the environment and add code to the experiment to be executed at the end of a simulation run.
Under imports section you could have this:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.OutputStream;
import java.io.PrintStream;
First create a variable for the filename called csvFileName (you can call it whatever obviously). Then create a function in root called updateMyCSV() or something like that. This function would have a general structure of:
FileWriter pw = new FileWriter(csvFileName, true);
StringBuilder sb;
sb = new StringBuilder();
sb.append(<variablename>); sb.append(',');
Then repeat the above for each variable you want exported
Then finish the function with:
sb.append('\n');
pw.append(sb);
pw.flush();
pw.close();
Best use the build-in database and let it write to Excel at the end of all your runs.
Create a dbase table with columns such as "run_number", "replication_number", "experiment_parameter_X", "my_result_y". Each of your params on Main should get a column (at least those you vary) and each of the output values you are interested in.
This way, you can easily write your model results after each model run using the insertInto command (link).
Finally, just tick the "write to Excel" tickbox in your dbase, select the file and it will write all your raw results.
Also check the example models using the dbase, several use this approach

AttributeError for selfloop_edges()

When executing the following:
import networkx as nx
import matplotlib.pyplot as plt
import csv
with open("nutrients.csv") as file:
reader = csv.reader(file)
G = nx.Graph(reader) #initialize Graph
print(G.nodes()) #this part works fine
print(repr(G.edges))
G.selfloop_edges()#attribute of question
It's coming back with
AttributeError:"Graph" object has no attribute 'selfloop_edge'
Does anyone know what could be the issue?
You getting an error because this method has been moved from the base graph class into the main namespace, see Migration guide from 1.X to 2.0. So either you're looking at the docs of 1.X or using code from previous releases.
You need to call this method as:
nx.selfloop_edges(G, data=True)

Discord Module never used?

I'm relatively confused here, and upon trying to research for an answer, I'm not seeming to find anything that makes any sense to me. I have created a discord bot with 5 cogs, and in each one I import discord, os, and from discord.ext import commands In various other cogs I import other modules such as random as the case may be, but those are the three common ones.
The problem is that in every module, import discord is grayed out (PyCharm IDE), suggesting that is never used. Despite this, my bot runs perfectly. I don't seem to be able to use things like the wait_for() command, I presume it is because it is in the discord module? Am I not setting things up correctly to use this?
I will post the initial startup module and a small snippet of another module, rather than list module. If you need more information, let me know.
initial startup:
import discord
import os
from discord.ext import commands
token = open("token.txt", "r").read()
client = commands.Bot(command_prefix = '!')
#client.command()
async def load(ctx, extension):
client.load_extension("cogs." + extension)
#client.command()
async def unload(ctx, extension):
client.unload_extension("cogs." + extension)
for filename in os.listdir("./cogs"):
if filename.endswith('.py'):
client.load_extension("cogs." + filename[:-3])
client.run(token)
another module:
import discord
from discord.ext import commands
import os
import json
from pathlib import Path
class Sheet(commands.Cog):
def __init__(self, client):
self.client = client
#commands.command()
#commands.dm_only()
async def viewchar(self, ctx):
#Snipped code here to make it shorter.
pass
#viewchar.error
async def stats_error(self, ctx, error):
if isinstance(error, commands.PrivateMessageOnly):
await ctx.send("You're an idiot, now everyone knows. Why would you want to display your character sheet "
"in a public room? PM me with the command.")
else:
raise error
def setup(client):
client.add_cog(Sheet(client))
That just means that your code doesn't directly reference the discord module anywhere. You're getting everything through the commands module.
You can remove the import discord from your code without breaking anything, because the code that relies on it will still import and use it behind the scenes.

How to do SVM Tagging in NLTK Python on Unicode Data

Can anyone help me on how to use SVM tagging in NLTK Python.
I have the following code using TnT tagger. It works perfectly for me thereby generating the tagged output.
How to achieve the tagging with svm?
Kindly help.. thanks
import nltk
import re
import time
from nltk.corpus import indian
train_data = indian.tagged_sents('konkani.pos')[:300]
from nltk.tag import tnt
l = tnt_pos_tagger = tnt.TnT()
n=tnt_pos_tagger.train(train_data)
e = open('kkn-.txt',encoding='utf-8-sig').read()
print (tnt_pos_tagger.tag(nltk.word_tokenize(e)))