Skip to main content

GUIs are evil

Well, not really. Like most things a GUI is neither good nor evil, but a shade of something in between. However, for a while, before I caught myself, I was spending large amounts of time writing GUIs for analysis. Time that would have been better spent writing analysis code and debugging it and documenting it and writing papers as a result of it. I taped a piece of paper in front of my desk that said 'NO GUIs' to remind myself.

Programming a GUIs is a time trade. Creating a GUI trades time now for time later. The catch is that the time later usually goes to an 'end user' rather than you.

When to write a GUI:
  • A GUI for MATLAB or Python is good for code that will be repeatedly used to run analysis by people who have no interest in knowing the underlying code.
  • A GUI is good for tasks that have a strong visual component: this means analysis that is done by displaying data on screen on which you have to indicate things by clicking on them.
  • Your analysis code is all finished and documented and you are regularly running analysis with it and you are getting tired of some repeated typing or repeated actions. Again, first think if you could write a glue script (in Python for example) rather than a GUI.
When to resist the devil's call:
  • The code is for exploratory analysis that may or may not yield results.
    "But I need to see stuff graphically, and I need to click on things to select regions or points", you say. Yes, MATLAB has ginput (look it up) and matplotlib has connect that can connect mouse and keyboard events to a graph. Don't make a full blown GUI that also makes coffee. That is the dark side.
  • The code has no graphical component to it (besides loading data and creating graphs).
  • Your sketch of the GUI has nothing but buttons and text boxes with parameters: replace the GUI with a nice, commented parameter file where the parameters have names. With the time saved write more documentation, take your spouse/SO/friends out or play video games.
  • You are coding the GUI before you have coded the smaller programs the GUI will eventually call. That is the dark side. Write the analysis components first, then decide if it will need a GUI package.
Also see:

Comments

Popular posts from this blog

Python: Multiprocessing: passing multiple arguments to a function

Write a wrapper function to unpack the arguments before calling the real function. Lambda won't work, for some strange un-Pythonic reason.


import multiprocessing as mp def myfun(a,b): print a + b def mf_wrap(args): return myfun(*args) p = mp.Pool(4) fl = [(a,b) for a in range(3) for b in range(2)] #mf_wrap = lambda args: myfun(*args) -> this sucker, though more pythonic and compact, won't work p.map(mf_wrap, fl)

Flowing text in inkscape (Poster making)

You can flow text into arbitrary shapes in inkscape. (From a hint here).

You simply create a text box, type your text into it, create a frame with some drawing tool, select both the text box and the frame (click and shift) and then go to text->flow into frame.

UPDATE:

The omnipresent anonymous asked:
Trying to enter sentence so that text forms the number three...any ideas?
The solution:
Type '3' using the text toolConvert to path using object->pathSize as necessaryRemove fillUngroupType in actual text in new text boxSelect the text and the '3' pathFlow the text

Running a task in a separate thread in a Tkinter app.

Use Queues to communicate between main thread and sub-threadUse wm_protocol/protocol to handle quit eventUse Event to pass a message to sub-threadimport Tkinter as tki, threading, Queue, time def thread(q, stop_event): """q is a Queue object, stop_event is an Event. stop_event from http://stackoverflow.com/questions/6524459/stopping-a-thread-python """ while(not stop_event.is_set()): if q.empty(): q.put(time.strftime('%H:%M:%S')) class App(object): def __init__(self): self.root = tki.Tk() self.win = tki.Text(self.root, undo=True, width=10, height=1) self.win.pack(side='left') self.queue = Queue.Queue(maxsize=1) self.poll_thread_stop_event = threading.Event() self.poll_thread = threading.Thread(target=thread, name='Thread', args=(self.queue,self.poll_thread_stop_event)) self.poll_thread.start() self.poll_interval = 250 self.poll() self.root.wm_protocol("WM_DELETE…