Author Archives: Corran Webster


About Corran Webster

Corran is Enthought's European consulting director, and has been with Enthought as a scientific software developer and Python instructor since 2008. Corran has a B.S. from the University of New South Wales and a Ph.D. in pure mathematics from UCLA and has held positions at the University of Nevada, Las Vegas and Texas A&M University, working primarily in operator algebras and functional analysis. Prior to joining Enthought, he was Chief Scientist at Compudigm International working on machine learning with self-organizing maps and large data visualization methods. Corran wrote his first Python code back in the days of Python 1.3 and has used it as his primary programming language for over 20 years.

Traits and TraitsUI: Reactive User Interfaces for Rapid Application Development in Python

The Enthought Tool Suite team is pleased to announce the release of Traits 4.6. Together with the release of TraitsUI 5.1 last year, these core packages of Enthought’s open-source rapid application development tools are now compatible with Python 3 as well as Python 2.7.  Long-time fans of Enthought’s open-source offerings will be happy to hear about the recent updates and modernization we’ve been working on, including the recent release of Mayavi 4.5 with Python 3 support, while newcomers to Python will be pleased that there is an easy way to get started with GUI programming which grows to allow you to build applications with sophisticated, interactive 2D and 3D visualizations.

A Brief Introduction to Traits and TraitsUI

Traits is a mature reactive programming library for Python that allows application code to respond to changes on Python objects, greatly simplifying the logic of an application.  TraitsUI is a tool for building desktop applications on top of the Qt or WxWidgets cross-platform GUI toolkits. Traits, together with TraitsUI, provides a programming model for Python that is similar in concept to modern and popular Javascript frameworks like React, Vue and Angular but targeting desktop applications rather than the browser.

Traits is also the core of Enthought’s open source 2D and 3D visualization libraries Chaco and Mayavi, drives the internal application logic of Enthought products like Canopy, Canopy Geoscience and Virtual Core, and Enthought’s consultants appreciate its the way it facilitates the rapid development of desktop applications for our consulting clients. It is also used by several open-source scientific software projects such as the HyperSpy multidimensional data analysis library and the pi3Diamond application for controlling diamond nitrogen-vacancy quantum physics experiments, and in commercial projects such as the PyRX Virtual Screening software for computational drug discovery.

 The open-source pi3Diamond application built with Traits, TraitsUI and Chaco by Swabian Instruments.

The open-source pi3Diamond application built with Traits, TraitsUI and Chaco by Swabian Instruments.

Traits is part of the Enthought Tool Suite of open source application development packages and is available to install through Enthought Canopy’s Package Manager (you can download Canopy here) or via Enthought’s new edm command line package and environment management tool. Running

edm install traits

at the command line will install Traits into your current environment.


The Traits library provides a new type of Python object which has an event stream associated with each attribute (or “trait”) of the object that tracks changes to the attribute.  This means that you can decouple your application model much more cleanly: rather than an object having to know all the work which might need to be done when it changes its state, instead other parts of the application register the pieces of work that each of them need when the state changes and Traits automatically takes care running that code.  This results in simpler, more modular and loosely-coupled code that is easier to develop and maintain.

Traits also provides optional data validation and initialization that dramatically reduces the amount of boilerplate code that you need to write to set up objects into a working state and ensure that the state remains valid.  This makes it more likely that your code is correct and does what you expect, resulting in fewer subtle bugs and more immediate and useful errors when things do go wrong.

When you consider all the things that Traits does, it would be reasonable to expect that it may have some impact on performance, but the heart of Traits is written in C and knows more about the structure of the data it is working with than general Python code. This means that it can make some optimizations that the Python interpreter can’t, the net result of which is that code written with Traits is often faster than equivalent pure Python code.

Continue reading

PyCon 2010 Report

I just got back from PyCon, where I gave my tutorial on Traits, met all sorts of smart and interesting people, listened to some great talks, ate more food than I probably should have, and got less sleep than I probably needed. It was really nice to see talks and posters about things that people are doing with Python in science at a general-purpose conference.

Highlights for me:
Dave Beazley’s awesome talk on Python’s Global Interpreter Lock (GIL) and its curious behaviour. If you do any programming with threads in Python you have to make sure that you watch the video it’s a clear, understandable and unflinching look at some of the weird behaviour that you can get from CPU-bound threads in Python. The take-home message of his talk for scientific programmers: With current versions of Python, there is little point of running intensive pure-Python computations in parallel using threads and doing so on multiple core machines may severely degrade computation time. Dave showed a simple example where a computation split into two threads on two cores took twice as long as the same computation in one thread on one core. Fortunately NumPy releases the GIL for most of its operations, but his talk highlights something that we should all keep in mind.

Wes McKinney’s new Pandas package for data series analysis. I didn’t get to see his talk, but I got to spend a fair amount of time talking to Wes and his package was generating quite a bit of buzz in the financial and numerical computing open spaces. It’s an early release, but there have been several projects I’ve been involved in over the past couple of years where the Pandas data structures would have been invaluable. I’m looking forward to being able to use it in the future in projects that I’m working on.

Altogether, a great time. Thanks to everyone who dropped by the Enthought booth and talked with us, and we’ll see you in Atlanta at PyCon 2011 next year!

A Perspective on Numpy

In a former life, before joining Enthought, I was a researcher in operator algebras, a field of mathematics which can be briefly summed up as the study of certain sets of “infinite-dimensional matrices.” My first reaction when seeing numpy (actually, numerical python, this was a while back) was “A matrix module! In Python! Show me more!”

But then I looked a little deeper, and my second reaction was “Why on earth would you not have the product of two arrays be the matrix product?” And then: “And why is function application element-wise?”

From the point of view of an operator algebraist everything interesting comes out of non-commutative multiplication, and clearly the “right” way to apply a function to a matrix is

f(A) = U f(D) U *

where A = U D U * is a unitary diagonalization of A, and f is applied just to entries on the diagonal of D. The fact that this only works for unitarily diagonalizable matrices was a minor concern for me at the time… after all I was a pure mathematician!

Since then, particularly in a more recent life as a scientist at a data visualization company, I’ve come to appreciate the way that numpy slices and dices arrays of numbers. And numpy now meets me half-way with a first-class matrix type, so I can at least write A*B and have it mean what I want it to.

But for those who still think that numpy made the wrong choice for applying functions to arrays…

from numpy import *
def mfunc(func):
    def new_func(x):
        x = mat(x)
        if not allclose(x*x.H, x.H*x):
            # matrix is not normal-ish
            raise ValueError, "matrix must be normal"
        # matrix is normal-ish
        e, U = linalg.eig(x)
        return U*mat(diag(func(e)))*U.H
    return new_func

Which you can then use as:

mexp = mfunc(exp)

for any ufunc, or as a decorator on your own functions:

def f(x):
    return cos(x) + 1.0j*sin(x)

When I showed this to Travis Oliphant, he pointed out that scipy already has a function linalg.funm which does something similar to the above, but not as a decorator. So if you have scipy, you can instead use:

import scipy.linalg
def mfunc(func):
    def new_func(x):
        return scipy.linalg.funm(x, func)
    return new_func