Web Adventures: evaluating what to learn

The past few weeks I’ve been greatly distracted while writing. Trying to build a supporting app for my dissertation and the inertia kick from chemdoodle web components brought me to learning Java / JavaScript. I’ve known for sometime that I need to learn web-dev for OpenChemArt (amongst other things), but haven’t put serious thoughts into it. Being a python coder with ancient C++ experience, none of this is familiar grounds.

Continue reading

Scientific Data Visualization: Learning Enthought Traits (2)

In the last section, we looked at some basic things that the Enthought Traits package can do for you.  In this section we’ll take a look at customizing the graphic interface, and build upon this familiarity to do some interactive graphing in the next.

Last time we made a class of objects called Subjects, which has age and happiness as attributes.  (Again, the color code is Class, instances, attributes, and methods.)  Let’s warm up by adding traited name and phone attributes:

Note that on line 5/6 we asked for the name and phone to be a String object, as opposed to the native python type str.  Python objects are case-sensitive, and many traited objects look like their native counterpart but with capitalized first letter – Int instead of int, Float instead of float and so on.  Keeping everything else the same, running this program gives us this interface:

Note that String doesn’t seem to be very appropriate here, even though we wanted those – separators.  People shouldn’t be able to enter U78-8902 as their phone numbers!  This is where the variety of traited objects come in handy.  Here, we could enforce the structure of phone numbers by the use of the traited RegEx object:

RegEx stands for regular expression, and these objects uses the second argument as a regular expression for what values are allowed.  Regular expressions are fairly large a topic to tackle and I’ll leave that for you to explore.  The line here, however, means that we’re only going to accept 3 digits (“\d”) followed by either a period or a dash, then 3 digits, another ./-, and 4 more digits.  The interface will help prevent anyone from trying otherwise:

Notice how the field turns red, and the “OK” button is disabled.  This is looking good – but all of the attributes are ordered alphabetically, and we really want the name to come first.  It would also be nice to change the window’s name from “Edit Properties” to something else.  How do we do that?

It turns out that the Subject .configure_traits() method first looks for a View object within Subject, and only do the default interface when there are no View objects to be found.  So let’s add in a View object called Subject.traits_view:

Here I have also added a gender attribute, of Enum type, which allows us to choose from a set of values contained in a list (or tuple).  This gives us an output that looks like this:

Our traits_view object contains several instances of Item, which themselves reference values from the (self.)name/phone/… attributes.  (Would this be considered an example of delegation?)  These Item()s are then displayed in that sequence.

Note that View objects contain attributes that specify “something” – e.g., whether the window is resizable or what its title should be.  In fact, this is general of traited objects, and you can query what is available to that object by looking up the API reference on code.enthought.com (as an example, the one for View is here).

Sometimes you may wish to have more than one view for an object – for example, we may want a publicly available interface for bob that doesn’t contain his phone number.  We can do that by defining multiple views and specifying which one to use:

If no view is specified (for example, when bob.configure_traits() is called), the instance of View named traits_view take precedence over others.

Before we close this section, I’d like to point out that when you supply gender (an Enum) to a View(), the View object is actually constructing a “default editor” for how to display the item.  This look can be customized (see figure below), and more instructions on that can be found at the Editor Factory page.

And this concludes the second part, where you’ve learned to define and customize multiple interfaces for objects containing multiple traited types.  That’s alot of ground already!  In the next section, we’ll consider the case where we didn’t measure (age:happiness) for bob on a single date, but instead did a longitudinal study where we look at how his happiness and wealth changes over the years, and do some interactive graphing of his “happiness time series”…

Scientific Data Visualization: Learning Enthought Traits (1)

A few months ago I proposed a new analysis for my thesis data.  The trouble was that I have only a faint scent of the direction, and have no algorithm, nor the means to find out what that algorithm ought to be.  I knew it must involve some automation – afterall, there is ~30Gb of data – but the impasse was the lack of live interaction with my data, where I can explore the different transformation options.

After numerous blunders on my self-devised curriculum, I’m now well on my path, and helped tremendously along the way by the Enthought Traits python package.  Traits offer a nice view at the top but has a pretty slippery learning curve on the way.  I’ve constantly wished that there’s a single QuickStart tutorial that takes me from 0 to 100mph.  Here’s my attempt at a 20->40 tutorial: this assumes some general knowledge of python – Software Carpentry is a good resource to get started – and ends at what I know.

Part I: What does Traits do?

“A manifest type definition library for Python that provides initialization, validation, delegation, notification, and visualization.”

The official definition reads like gibberish to a novice pythonista.  Let’s do an example: say we would like to conduct a study correlating happiness with age.  We’d probably want to make a class of subjects, which contains a variable that contain the subject’s age and happiness.  In the absence of the traits package, this would probably look like:

That’s the baseline we’re working from – it represents the data but does not do much beyond that.  To enter data, I would have most likely written a text prompt that says, “What is the subject’s age? (press enter when finished)“, and write that input into Bob.age.  It gets the job done, but is neither convenient nor pretty (what do you do when you want to go back and change things up?)  [Color code: instance of object, attributes, class, methods]

Compounding that, to err is human, and sooner or later I’ll find myself entering Jane.age as 455 instead of 45.  Both are perfectly fine integers, and python would accept them without skipping a beat even though they aren’t feasible human ages.  To keep these from happening, we’ll need to write some code to make sure that the integers are reasonable, that is, some code to validate the values.  Then to make life easier, we’ll try to make ourselves a pretty graphical interface instead of the text prompt, and life just got a whole lot messier.

With traits, you would instead write code like this – not too much different than what we had:

Since this is our first example, let’s look at this line by line, and compare it with our base class.

line 1, 2: These import the enthought libraries for this scenario.  (These are installed if you use the Enthought Python Distribution – it’s redundantly painful to do it on your own.)

line 4: This subclasses Subject to HasTraits.  That is, Subject now inherits all the goodness that HasTraits have – the whole “initialization, validation, delegation, notification, and visualization” bit.

line 5: Instead of saying age is an integer, we talk about age as (an instance of) a Range object as setup by Enthought Traits.  We’ll talk more fully about what this means when we look at the UI, but for now, you can see that this attribute will only accept values between 15 and 100, and is trained to complain if someone tries to enter 1000.

line 6: Range objects can hold floating point numbers too.  Sweet 🙂

line 9:  We construct a Subject, and call him bob.  At this point, bob has an age (30) and happiness (50.0) already.

line 10bob is a Subject, which is in turn also an (object that) HasTraitsHasTraits (and its descendents, like bob) have a method called configure_traits(), whose function is to launch a graphical interface of itself.  For the case of bob, that default interface looks like:

This looks pretty good for essentially no efforts on our part – and we can do a whole lot more with just a little bit more effort.  At this point though, let’s go back and look at what used to be gibberish:

“Enthought Traits is a manifest type definition library for Python that provides initialization, validation, delegation, notification, and visualization.”

Initialization means that there is a default age and happiness, set by the programmer (you).  If you do not define the default explicitly as we did here, the object holds a default value as defined by the Traits package.

Validation means that some basic checking is in place.  For example, if we try to enter happiness = 450.0 for bob, the following window pops up (“you can be too happy”):

Delegation… we won’t deal with that at all here.

Notification… we’ll look at this when we move onto some basic plotting.  But imagine we have calculated an average happiness for someone who’s 30 years old, and now bob is suddenly a great deal happier.  So we enter the value 100.0 for bob.happiness.  If happiness is not traited, the global happiness will stay where it is, because it doesn’t know that it ought to be recomputed.  But since Subject.happiness is traited, it has the ability to notify the global happiness to recompute itself accordingly.  This is really useful when you start connecting different pieces together with a graphical interface.

Visualization is the pretty slider you see.  bob, age, and happiness are all Traited objects, so they can be edited easily with an interface that makes good sense.

In the basic sense, this example showcases what the Traits package can do above and beyond the native python types.  Besides Range, the Enthought package comes with a great many other useful traited objects: you can find a list of them here.  The linked page is one from the Traits User Manual, which as full of information but as a novice I found rather dense and difficult to read.

In the next section, we’ll look at making some simple modifications to the interface that Subject presents.