I have the code:
import time
import numpy as np
from scipy.optimize import fmin_tnc
from enthought.traits.api import *
from enthought.traits.ui.api import *
class Minimizer(HasTraits):
iteration = Int(0)
run = Button
def callback(self, x):
self.iteration += 1
print self.iteration
time.sleep(0.5)
def func(self, x):
return (x**2).sum()
def fprime(self, x):
return 2*x
def minimize(self):
x0 = np.random.rand(50)
fmin_tnc(self.func, x0, fprime=self.fprime, messages=0, callback = self.callback)
def _run_fired(self):
self.minimize()
traits_view = View(Item('iteration'), UItem('run'))
m = Minimizer()
m.configure_traits()
After running the above and pressing Run button i expected the 'iteration' attribute will be updated in the GUI at each iteration, but this is not the case. I suspect that this is because this value is changed by callback from C. What should be done to update the user interface in these circumstances?
Regards,
Marek
The call to m.configure_traits() is blocking, which means execution of your script will not continue past that line until you close the window created by that call. In other words, m.minimize does not get called while the window is open.
I found the solution. Simply, 'minimize' method have to be non-blocking, so implementing minimization in separate thread, like this:
def minimize(self):
x0 = np.random.rand(50)
#fmin_tnc(self.func, x0, fprime=self.fprime, messages=0, callback = self.callback)
import thread
thread.start_new_thread(fmin_tnc, (self.func, x0), {'fprime':self.fprime, 'messages':0, 'callback':self.callback})
will result in updating the UI at real-time...
Thanks,
Marek
Related
I think my question was not very clear before..
I'm trying to create a class module that includes a function does a mutiprocessing of a ctpyes function.
I'm re-posting a working small code.
All I want to do is to remove the code below and call the function directly from my class. But it seems very hard since ctypes object is not picklable.. Is there a way to resolve this issue? Even a small hint will be appreciated!! Will I have to switch to using cython instead of ctypes? will that even help?
def myc(x):
return a.funct(x)
Below is the working code.
from ctypes import *
from ctypes.util import find_library
import multiprocess as mp
class ctest():
def __init__(self):
self.libapr = cdll.LoadLibrary(find_library('apr-1'))
self.libapr.apr_fnmatch.argtypes = [c_char_p, c_char_p, c_int]
self.libapr.apr_fnmatch.restype = c_int
def funct(self,x):
y=self.libapr.apr_fnmatch(x, 'name.ext', 0)
return y
def mymult(self,func,xlist):
pool=mp.Pool(20)
res=pool.map(func,xlist)
pool.close()
return res
if __name__ == "__main__":
a=ctest()
def myc(x):return a.funct(x)
print a.mymult(myc,['*.txt','*.ext'])
Below is what I want to do.
from ctypes import *
from ctypes.util import find_library
import multiprocess as mp
class ctest():
def __init__(self):
self.libapr = cdll.LoadLibrary(find_library('apr-1'))
self.libapr.apr_fnmatch.argtypes = [c_char_p, c_char_p, c_int]
self.libapr.apr_fnmatch.restype = c_int
def funct(self,x):
y=self.libapr.apr_fnmatch(x, 'name.ext', 0)
return y
def mymult(self,func,xlist):
pool=mp.Pool(20)
res=pool.map(func,xlist)
pool.close()
return res
if __name__ == "__main__":
a=ctest()
a.mymult(a.funct,['*.txt','*.ext'])
I am trying to do a multigraph window for plotting different data using pyqtgraph. I have a working version with no threads using timers for getting the data. I also tried a threaded version but it seems to have no performance boost when use htop for visually inspecting the CPU Usage.
I am new to GUIs and Threads so I followed this code that I saw in a youtube tutorial. It uses a QThread to get the CPU usage using psutil.cpu_percent in intervals of 0.1 seconds and then updates a progress bar.
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
import progress
import sysinfo
class MainUIClass(QtGui.QMainWindow, progress.Ui_MainWindow):
def __init__(self, parent = None):
super(MainUIClass, self).__init__(parent)
self.setupUi(self)
self.threadClass = ThreadClass()
self.threadClass.start()
self.connect(self.threadClass, QtCore.SIGNAL('CPU_VALUE'),
self.updateProgressBar)
def updateProgressBar(self, val):
self.progressBar.setValue(val)
class ThreadClass(QtCore.QThread):
def __init__(self, parent = None):
super(ThreadClass, self).__init__(parent)
def run(self):
while 1:
val = sysinfo.getCPU()
self.emit(QtCore.SIGNAL('CPU_VALUE'), val)
if __name__ == '__main__':
a = QtGui.QApplication(sys.argv)
app = MainUIClass()
app.show()
a.exec_()
I tried using cProfile for comparing performance but it throws lot of stuff that couldn't read, so I use the example of the progress bar to average the cpu usage after 10 seconds. Sorry if my measure performance method is so poor.
My two codes for benchmarking are
Threaded Version with a very consistent average CPU Usage of 64%:
import sys
from pyqtgraph.Qt import QtCore
from pyqtgraph.Qt import QtGui
import pyqtgraph as pg
import numpy as np
import time
class GraphWindow_Thread(pg.GraphicsWindow):
def __init__(self, rows, cols, titles):
super(GraphWindow_Thread, self).__init__()
# Code to draw the GUI
self.rows = rows
self.cols = cols
self.titles = titles
self.plots = [] # List of PlotItems
self.curves = [] # List of PlotDataItems in each PlotItem
for i in range(self.rows):
for j in range(self.cols):
p = self.addPlot()
self.plots.append(p)
if titles != [] or len(titles) == 1:
p.setLabel('left', self.titles[i+j+1])
p.setDownsampling(mode='peak')
p.setClipToView(True)
pp = p.plot(pen=(155, 255, 50))
pp1 = p.plot(pen=(55, 130, 255))
self.curves.append((pp, pp1))
self.nextRow()
# Thread to get the data and redraw plots
self.thread_graph = DataThread()
self.thread_graph.start()
self.connect(self.thread_graph, QtCore.SIGNAL('DATA_VALUE'),
self.update_plots)
def set_titles(self, titles):
for i, p in enumerate(self.plots):
p.setLabel('left', titles[i])
def update_plots(self, data, dataD):
for curve in self.curves:
curve[0].setData(data)
curve[1].setData(dataD)
class DataThread(QtCore.QThread):
def __init__(self, parent = None):
super(DataThread, self).__init__(parent)
def run(self):
while 1:
data = np.random.random((30,))
dataD = np.random.random((30,))
self.emit(QtCore.SIGNAL('DATA_VALUE'), data, dataD)
time.sleep(.1)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
gui = GraphWindow_Thread(2,3,[])
gui.show()
app.exec_()
No Thread Version with a very consistent average CPU Usage of 65%:
import sys
from pyqtgraph.Qt import QtCore
from pyqtgraph.Qt import QtGui
import pyqtgraph as pg
import numpy as np
import time
class GraphWindow(pg.GraphicsWindow):
def __init__(self, rows, cols, titles):
super(GraphWindow, self).__init__()
# Code to draw the GUI
self.rows = rows
self.cols = cols
self.titles = titles
self.plots = [] # List of PlotItems
self.curves = [] # List of PlotDataItems in each PlotItem
for i in range(self.rows):
for j in range(self.cols):
p = self.addPlot()
self.plots.append(p)
if titles != [] or len(titles) == 1:
p.setLabel('left', self.titles[i+j+1])
p.setDownsampling(mode='peak')
p.setClipToView(True)
pp = p.plot(pen=(155, 255, 50))
pp1 = p.plot(pen=(55, 130, 255))
self.curves.append((pp, pp1))
self.nextRow()
# Timer to redraw plots
timer = QtCore.QTimer(self)
self.connect(timer, QtCore.SIGNAL('timeout()'),self.update_plots)
timer.start(100)
def set_titles(self, titles):
for i, p in enumerate(self.plots):
p.setLabel('left', titles[i])
def update_plots(self):
np.random.seed()
data = np.random.random((30,))
dataD = np.random.random((30,))
for curve in self.curves:
curve[0].setData(data)
curve[1].setData(dataD)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
gui = GraphWindow(2,3,[])
gui.show()
app.exec_()
The full app is meant to be a window with multiple tabs, each one with a GraphWindow in which each graph uses a Thread for plotting different data.
What am I missing? Why my threaded version does not represent a performance improvement?
I have written a small executable script. This program only works when I use a print-statement (at the end of the on_start()-method of the QDialog()class). Please, take a look in the on_start()-method of the QDialog-class.
As you can see I create an a task_thread- and work_object-instance. But, when I execute this script without print-statement nothing happens - no Traceback or other error messages.
Where is the bug? I guess the problem is that I create the instances at the local level - I am not sure. How can I fix it?
import sys
from time import sleep
from PyQt4.QtCore import QThread, pyqtSignal, Qt, QStringList, QObject, QTimer
from PyQt4.QtGui import QVBoxLayout, QPushButton, QDialog, QProgressBar, QApplication, \
QMessageBox, QTreeWidget, QTreeWidgetItem, QLabel
def create_items(total):
for elem in range(total):
yield elem
class WorkObject(QObject):
notify_progress = pyqtSignal(object)
fire_label = pyqtSignal(object)
finished = pyqtSignal()
def __init__(self, parent=None):
QObject.__init__(self, parent)
def add_items(self):
total = 190000
x = (total/100*1)
a = x
counter = 0
for element in create_items(10000):
counter += 1
self.notify_progress.emit((element))
self.fire_label.emit((counter))
if counter == x:
x += a
sleep(1)
if not self.keep_running:
self.keep_running = True
break
def run(self):
self.keep_running = True
self.add_items()
def stop(self):
self.keep_running = False
class MyCustomDialog(QDialog):
finish = pyqtSignal()
def __init__(self, parent=None):
QDialog.__init__(self, parent)
layout = QVBoxLayout(self)
self.tree = QTreeWidget(self)
self.label = QLabel(self)
self.pushButton_start = QPushButton("Start", self)
self.pushButton_stopp = QPushButton("Stopp", self)
self.pushButton_close = QPushButton("Close", self)
layout.addWidget(self.label)
layout.addWidget(self.tree)
layout.addWidget(self.pushButton_start)
layout.addWidget(self.pushButton_stopp)
layout.addWidget(self.pushButton_close)
self.pushButton_start.clicked.connect(self.on_start)
self.pushButton_stopp.clicked.connect(self.on_finish)
self.pushButton_close.clicked.connect(self.close)
def fill_tree_widget(self, i):
parent = QTreeWidgetItem(self.tree)
self.tree.addTopLevelItem(parent)
parent.setText(0, unicode(i))
parent.setCheckState(0, Qt.Unchecked)
parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
def on_label(self, i):
self.label.setText("Result: {}".format(i))
def on_start(self):
self.tree.clear()
self.label.clear()
task_thread = QThread(self)
work_object = WorkObject()
work_object.fire_label.connect(self.on_label)
work_object.notify_progress.connect(self.fill_tree_widget)
work_object.finished.connect(task_thread.quit)
self.finish.connect(work_object.stop)
work_object.moveToThread(task_thread)
task_thread.started.connect(work_object.run)
task_thread.finished.connect(task_thread.deleteLater)
timer = QTimer()
# I set the single shot timer on False,
# because I don't want the timer to fires only once,
# it should fires every interval milliseconds
timer.setSingleShot(False)
timer.timeout.connect(work_object.stop)
timer.start(0)
task_thread.start()
print
def on_finish(self):
self.finish.emit()
def main():
app = QApplication(sys.argv)
window = MyCustomDialog()
window.resize(600, 400)
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
You are right, work_object is created as a local instance.
Here is a simple solution:
work_object = WorkObject()
self.work_object = work_object # Add this line
I am trying to invoke a method from combo box selected change event
with lambda expression but I am stuck with following error
TypeError: () takes no arguments (1 given)
I think I have passed 1 argument as per the method definition, could somebody please help me where I am wrong
or any other combobox selected change event code will be great help!
please note my code
self.boxWidget[boxName].bind("<<ComboboxSelected>>", lambda:invoke_Setting_Group(self))
def invoke_My_method1(self):
print "expand another window"
I am trying to pass the first class object to the second python script file for variable value assigning easeness.I tried to use this combox event change code without lambda then I noticed that this method is getting called automatically so I used lambda to prevent this automatic method calling
Sorry I am not having the knowledge on lambda expression usage; here I used only to prevent the automatic method execution. Without lambda expression I noticed my combo box function starts automatically, I did not understand why it happens so?
I am using TKinter python 2.6
More Detailed Code of above:
#Main_GUI_Class.py
##----------------------
import sys
class App():
def __init__ (self,master,geometry=None,root=None):
try:
self.master=master
if not root:
self.root=Tkinter.Toplevel(master)
def initUI(self):
try:
self.master.title("GUI")
menubar = Menu(self.master)
self.root.config(menu=menubar)
fileMenu.add_command(label='Open')
submenu_ncss.add_command(label='Model Setting',command=lambda:Combo_Expand_Script.Call_Model_Setting(self))
##----------------------
def main():
r = Tkinter.Tk()
r.withdraw()
r.title("GUI Sample")
r.wm_iconbitmap(Pic1)
v = App(r)
r.mainloop()
if __name__ == "__main__":
main()
##Combo_Expand_Script.py
##-----------------------
import sys
import Tkinter
import Main_GUI_Class
def Call_Model_Setting(self):
try:
self.PopUpWin = Toplevel(bg='#54596d',height=500, width=365)
self.PopUpWin.title("POP UP SETTING")
#Combo Boxs in Pop Up
boxNameGroup="boxSetting"
boxPlaceY=0
for Y in range(4):
boxName=boxNameGroup+str(Y)
if Y == 0:
boxPlaceY=50
else:
boxPlaceY=boxPlaceY+40
self.box_value = StringVar()
self.boxWidget[boxName] = ttk.Combobox(self.PopUpWin, height=1, width=20)
if Y== 0:
self.boxWidget[boxName]['values'] = ('A', 'B')
self.boxWidget[boxName].current(1)
if Y== 1:
self.boxWidget[boxName]['values'] = ('X', 'Y')
self.boxWidget[boxName].bind("<<ComboboxSelected>>",lambda:invoke_Setting_Group(self))
self.boxWidget[boxName].place(x=180, y = boxPlaceY)
#Buttons in Pop Up
self.btnApply = tk.Button(self.PopUpWin,width=10, height=1,text="Apply",relief=FLAT,bg=btn_Bg_Color,command=lambda: treeDataTransfer(self,0))
self.btnApply.pack()
self.btnApply.place(x=75, y = 460)
self.btnCancel = tk.Button(self.PopUpWin,width=10, height=1,text="Cancel",relief=FLAT,command=lambda: deleteTreeNodes(self))
self.btnCancel.pack()
self.btnCancel.place(x=170, y = 460)
except IOError:
print "Error: data error"
def invoke_Setting_Group(self):#, event=None
try:
#self.boxName.current(0)
self.boxWidget["boxSetting3"].current(0)
self.PopUpWin['width']=1050
self.PopUpWin['height']=700
self.btnApply.place(x=500, y = 550)
self.btnCancel.place(x=600, y = 550)
self.txtWidget={}
lsttxtSetting = ['1', '2','3 ','4','5 ','6','7','8','9','10']
for t in range(10):
txtName=txtNameGroupTS+str(t)
if t == 0:
txtPlaceY=120
else:
txtPlaceY=txtPlaceY+30
self.txtWidget[txtName] = Text(self.groupSettingFrame,height=1, width=10,borderwidth = 2)
self.txtWidget[txtName].insert(INSERT, lsttxtSetting[t])
self.txtWidget[txtName].pack()
self.txtWidget[txtName].place(x=200, y = txtPlaceY)
except IOError:
print "Error: Group Settings Popup error"
def turbDataTransferBind(self):
for P in range(0,3):
boxName="boxSetting"+str(X)
dataSettingbox=self.lstTurb[X]+" "+self.boxWidget[boxName].get()
self.root_node_Setting = self.tree.insert( self.root_node_ChildSetting["ChildSettingNode"], 'end', text=dataSettingbox, open=True)
def treeDataTransfer(self,dlgTurbFlag):
self.treeDataTransferBind()
print "data tranfer sucess"
def deleteTreeNodes(self):
print "delete nodes"
command= and bind expect function name - without () and arguments - so in place of
If you use
.bind("<<ComboboxSelected>>", invoke_Setting_Group(self) )
then you use result from invoke_Setting_Group(self) as second argument in .bind(). This way you could dynamicly generate function used as argument in bind
TypeError: () takes no arguments (1 given)
This means you have function function() but python run it as function(arg1)
You run lambda:invoke_Setting_Group(self) but python expects lambda arg1:self.invoke_Setting_Group(self)
You could create function with extra argument
def invoke_My_method1(self, event):
print "expand another window"
print "event:", event, event.widget, event.x, event.y
And then you could use it
.bind("<<ComboboxSelected>>", lambda event:invoke_Setting_Group(self, event))
BTW: it looks strange - you have class App() but in second file you use only functions instead of some class too.
I am using Tkinter to create a GUI for a program I am writing that will adjust some Zigbee controlled LED lights that I have. I am using a loop to create multiple copies of a Scale that I'm going to use as a brightness slider. I manage to create the sliders properly, but I am having difficulties actually adjust the sliders correctly. Here's my code:
import simplejson as json
import requests # submits http requests
from Tkinter import *
from ttk import Frame, Button, Label, Style, Notebook
# MD5 hash from http://www.miraclesalad.com/webtools/md5.php
myhash = "d9ffaca46d5990ec39501bcdf22ee7a1"
appname = "dddd" # name content isnt relevant
num_lights = int(3)
class hueApp(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self, *args, **kwds):
# title the app window
self.parent.title("Hue controller")
self.style = Style()
# create grid layout
self.columnconfigure(0, pad=3)
self.columnconfigure(1, pad=3)
self.columnconfigure(2, pad=3)
self.rowconfigure(0, pad=3)
self.scale=[]
self.val=[]
for i in range(num_lights):
print 'i=', i, type(i)
self.val.append(i+1)
print 'val=', self.val, type(self.val)
self.scale.append(Scale(self, from_=255, to_=0, command=lambda i=self.val: self.brightness_adj(i,light_id=i)))
print self.scale[i]
print 'i = ', i, type(i), '\n\n'
self.scale[i].set(150)
self.scale[i].grid(row=1, column=i)
if i == 2:
print '\n', self.scale, '\n'
print self.val, '\n'
self.scale[i].set(200)
self.centerWindow
self.pack()
def brightness_adj(self,light_val, light_id):
#global bri_val
print 'light_id:', light_id, type(light_id)
print 'light_val:', light_val, type(light_val)
print self.val[int(light_id)]
#print int(light_id)
bri_val = self.scale[light_id-1].get()
print bri_val
light = light_id
global huehub
huehub = "http://192.168.0.100/api/"+ myhash + "/lights/" + str(light)
#brightness_logic()
reply = requests.get(huehub)
a=json.loads(reply.text)
#print bri_val
payload = json.dumps({"bri":bri_val})
sethuehub = huehub + "/state"
reply = requests.put(sethuehub, data=payload)
def centerWindow(self):
w = 250
h = 150
sw = self.parent.winfo_screenwidth()
sh = self.parent.winfo_screenheight()
x = (sw-w)/2
y = (sh-h)/2
self.parent.geometry('%dx%d+%d+%d' % (w, h, x, y))
def main():
root=Tk() #the root window is created
app=hueApp(root) #create an instance of the application class
root.mainloop()
if __name__ == '__main__':
main()
I realize that this code probably gives an error when you try to run it. Basically my problem is that the command for each scale is only send brightness_adj the value of the scale, but I can't get it to pass through the id of the light. I was trying to do this by sending through the index of the self.scale list that it is appended into when it is created. I need to know which light is being adjusted so that I can send a new brightness to the corresponding light bulb. I hope I was clear enough. Thanks in advance!
I'm a little confused about what you're trying to do with the line that assigns callback functions to the scale widgets:
self.scale.append(Scale(self, from_=255, to_=0, command=lambda i=self.val: self.brightness_adj(i,light_id=i)))
since self.val is a list, and you're sending it as both the light_val and the light_id arguments, which I would think should be integers.
Possible fix:
I'm guessing that you want each callback to send a different ID to the brightness_adj function depending on which scale it's assigned to. Here's how I would fix this up:
Add this function to your hueApp class namespace:
def brightnessCallbackFactory(self, id):
return lambda light_val:self.brightness_adj(light_val, id)
Then change the callback assignment line from the above to this:
self.scale.append(Scale(self, from_=255, to_=0, command=self.brightnessCallbackFactory(i)))
That should create callback functions that retain the ID value in their internal namespace and assign them to the corresponding scale widget.