 Today it's all about how do we get this into a larger application. All right, so traits. Traits is part of the in-thought tool suite, and we haven't really talked about this very much, but along with SciPy and NumPy, there's also another open source library that's put out by in-thought that has as its base a library called Traits that provides some capabilities such as initialization, validation, observation, and visualization of Python class attributes, and I'll show what I mean by that in a few minutes. But essentially it's giving you kind of a nice syntax for describing information about the variables in your classes. Kiva is a drawing library that's based on the display PDF notion of trying a building a library that has to draw lines on a 2D canvas or lines and shapes using a display PDF like API. So it's kind of like the PDF rendering of documents, but being able to do that for screens or for display on your computer in your programs, and it's a really nice tool set. It's a little bit like using OpenGL for the 2D world, and it really supports quite a few things like hafine transforms and alpha blending and things like that. Sitting right on top of that is enable, which is more, as soon as you draw something in Kiva, it's just pixels on the screen, and enable you actually put objects down on a canvas, and so you have boxes and circles that have properties like radius and size, and you can move those around and click on them and that sort of thing. And then sitting on top of that again is Chaco, which is a plotting library for doing a lot of interactive plotting. And unfortunately that one's going to, I'll just show a couple of demos, but because the time squeeze, that one's going to get left out today. MyAvi is a tool set that Prabhu has built for doing 3D visualization. It's based on VTK and then envisages a application framework for putting together plug-ins in different disciplines or areas into a single application, and Prabhu will spend significant effort on that as well today. All right, so at the base of this I've said is traits. Well, what does it do? Well, these are the five areas. We've talked a little bit about classes in the first day, and you can remember you might have a rectangle, and it might have a width and a height or something like that. And typically in Python, you just declare those in the self. You just add an attribute to yourself in your init function, and you assign the value that you want there. Well, traits allow us to define these variables or the variables that a class is going to have at the class level instead of just doing it during the init method. And they really provide these five capabilities. Initialization, meaning you can specify default values. Validation, meaning you can do some type checking. Delegation, we're not going to talk too much about that, but you may say, I don't want to keep track of this attribute. I want my parent to keep track of this attribute, maybe a last name for a child. They might delegate that to their parent instead of keeping track of their last name on their own. Notification, this is a nice pattern in traits where a published subscriber, an observer pattern where you can listen for any change on an attribute in a class. And then visualization, you can build, because there's a little more information here, you can describe these things, these traits enough so that you can get a view up, a dialogue window that would allow you to manipulate these, or you can create views that get embedded in larger applications. And then the last thing is documentation. As you'll see, the way that you declare traits, they're right at the top of your class, and you're encouraged to put doc strings and that sort of thing right around them to describe them. And so it's very easy to go and look at somebody else's class and see exactly what the attributes that they have on that class are. A little bit like going and reading a C++ header file to see what the attributes are declared on an object. All right, so this is actually going to be very interactive. There's a set of demos here, and most of the people here don't have laptops. You'll see these during the tutorial this afternoon when you're at a machine. But if you're going to run these, you can run most of them at the IPython prompt. Some of them are going to throw exceptions. That's normal. That's what they're supposed to do. They'll say that in the program, but we'll see some tracebacks come up. The other thing is some of these start a GUI. And so some of those examples have to be run outside of IPython. So I'll note that at the top of the files. So just be aware of that if you're following along. All right, so here's the very first example of describing a class of traits. When you're using traits, you import from the traits.api library or the nthought.trates.api. And this is a convention that we've started using to help separate things out, instead of putting all of this information in the nthought.trates init file that's in a package, that we've chosen now to have all of the inits in the nthought library be empty for packages, and all of the interfaces for packages are going in these API modules. So we import has traits and float, then we're going to derive our class rectangle from has traits. So you notice that right up here. And this is just a simple rectangle class with two traits, and those two traits are the width and the height. And notice that we've declared these both as float traits. And you can specify an optional value here. We haven't. So these are going to default to initializing themselves to zero. And so now notice there is no init method or anything in this class, but if I come down here and I say rect equal rectangle, then I get a rect.width is equal to zero. I can set this rect.width to one. That works fine. I can set width to two. That works fine. But if I come in and I try to set this to a string, all of a sudden I get this trace back that tries to be pretty informative. The width trait of the rectangle instance must be a value of type float, but a value of one was specified. And so here it can make out, because you told it was a float, it can make out pretty good error message here. And that's fairly nice. All right. So we can just run this on the command line just as well. Or we can do pi cat rect one. So there's our class. And here's the main that I just showed you pretty much. The same thing. And so if we run this and indeed it ran, we get these default values, and then I try to print out these messages that tell you this is normal. It gets the exception, and there's the error that we saw. All right. So that's showing really a declaration or type checking capability on this. Also we've got a default value out of this. Well, what happens is we want to specify a different default value for our traits. We can just go ahead and stick that in there as an argument to this float trait. So width equal float one, height equal float two. Now if I ask for what are these default values, that's what the values are. So that's how initialization works. You always have an initial value for these guys. All right. You notice before that I wasn't able to get this rectangle right to the width or to the width to one as a string. Well, we can change that if we want to. There are other traits. You can define any trait you want actually. We're not going to get into how do you define traits, but they're just Python code. So you can define your own class and it can handle validation however it wants. And in this case there's a C float class that's a casting float, what that stands for. So if you give something to it, it basically does a float operation on that item. And if it gets converted, it's happy as it can be. So here we can see setting the wreck to height to 2.0, that worked. However, the width is still only allowing a float. And so if we look at that, let's do, so there's the, so here we have that same little class that we just played with or set up and we'll run that. And again, we assigned a string to C float and it should be 2 and it indeed is 2. So it changes the string to a floating point value. But when we again try to assign it to the height or to the width, we're out of luck. It doesn't work. There are zillion traits, different kind of traits. You can define your own, there are a lot that are already built for you. You can build very complex ones. But there are core set that you use a whole lot. And these are kind of the basic types that are in Python. So bool, complex, float, int, long, stir, all of these are in Unicode and they all are available as traits that you can use. You just have to import them from inthought.trates.api. They're available for your use. And this table just shows you what the corresponding Python type is and also what the default values are. So one of the questions that comes up quite often when talking about traits is what is the cost of doing this? And we're actually, I guess, on traits 2 and traits 3 is kind of baking in the oven as we speak. It's almost ready. There's not as large of a jump from traits 2 to traits 3 as there was from traits 1 to traits 2. Traits 1 was completely implemented in Python. Traits 2 is largely implemented in C. And so what this table shows you is if you're asking for an attribute off of a class, this shows you the time that's required. And we have speed up over here compared to accessing an attribute off of a new style class. And that's a class derived from object in Python. Old style is just if you declare a class without a base. And then global module lookup is if you just look up an attribute off of a module. And so using this as a baseline, there's also a trait I didn't mention called any. If you declare a trait any, that just means I don't care what this object is. It can take on any value it like. And so there's not any type checking there. And traits are actually a little bit faster than accessing attributes off of new style classes. You get a speed up of 1.6 using traits. And these are probably all pretty much in the noise here. A range trait checks to make sure a value is between an integer is between 10 and 20 or something like that. And so the speed here, you don't pay a penalty really for gets. For sets you pay a little bit of a penalty for anything but any trait. But it's not very high. At least for these basic types. The basic traits. Now as soon as you start listening to traits, you start, well I guess you don't pay anything on get because other objects are only going to listen to when traits change. So when you ask for an attribute, there's no cost to it. However on the sets you see over here, as soon as you add an observer that's listening to a change on your trait, we'll talk about this in a moment. You get this huge drop in speed. And that's because when you do that, you have to call a Python function every time you set that attribute. Still typically if you want to have some kind of observer you're going to have to make a function call anyways, right? To make some other action happen whenever these traits change. So this isn't really a downside of traits. It's really the notion of having observers. You have the cost of calling other functions to update their values whenever you change yours. And then delegation. You remember I talked about having a family or having a parent and a child. Well if you ask for an attribute here and it's delegated over here, then it has to do some work to go find that object, look up the value and return it to you. So delegation. You pay a bit of a speed price on git attributes and set attributes. And delegation can be chained as many times as you want. And so if you chained it a lot longer than just one level deep, then it gets slower and slower as you go. So where do you use traits? So you'll see the rest of the day will be looking at technologies that use traits. And so if you look at this list of things that I listed in the beginning, one of the things that people immediately jump on on traits is the big deal here is that it adds this validation or this type checking to Python. That's actually, I guess delegation is maybe the least important in my mind. But validation in my mind is not the strong suit or it's a nice feature but it's not the critical feature that's provided here. The critical features that come about here are one, the documentation. You can read classes very clearly. And somebody can read and know what default values are right off the bat because they're declared right there with the object. It simplifies your classes a lot of times because of this. The big deals, though, are notification. You have this observer pattern, which we'll get into. And the other big deal is visualization. You get GUIs without much effort. At least you get one cut of a GUI. If you want a very fancy GUI, you have to do a lot of effort. You never get out of that work. So basically traits are providing a way of describing your object in a more standard way so that other objects can look at them, find out information from them, about them, how they work, and hook up observers to them, listen to different changes and that sort of thing. Make sure objects are more easier to hook up to other things. One of the descriptions has been that it's actually providing a component layer to Python. All right, so now that we've looked at this, let's look at some other capabilities of traits. Here we're going to define a property. And so I have a class here that I called foo. And instead of declaring a trait as an int or something like that, I've said this is a property. And I have a shadow value that this is a convention we use with an underscore. This is saying this is a protected variable. I don't want other people in the outside world to look at this variable. That's not part of my interface. And then what you can do, once you have a property here, you can define, there's a convention in traits, if you define an underscore get underscore value method, then this is the get method for this value. If you define an underscore set value, that's the set value for this property, excuse me. So here when we ask for a value, and when we ask for foo.value, then this method is going to get called. And it should print out this get method, and it's going to return to you this shadow value, this underlying value that we've declared. If we call a set value, when you hand in the value, it prints out set value, and it's also going to set that value into the shadow. So this is kind of a control mechanism. Value is a control that maybe you want to do some validation or do some work before you set something in this underlying shadow value. So if we look at this, there's our little method there, and now if I run this, then you see the code that I executed here. I created a foo object, I set the value equal to one, and then I asked for the value that came from that. And this get value and set, or the set value property method was called, and then the get value method was called. So, and we print out these statements in there. Alright, so let's look at a few other examples that are a little more involved. So here's an example that we have, and I've just defined a class called water tank, and it has a water level that's a property. And then we have a shadow variable, or something that we just declared along with our water level. We have this protected value that's actually, water level is a property. So it's going to go through method access to get or set the value for water level. Under score water level is actually a floating point value that is actually setting the water level in our tank. And then we also have a water tank height. What is the height of our tank? So when you fill up the water tank, the highest you can ever fill, unless you have some fancy water tank, is to the top level of the tank. After that the water is going to spill over the top edge, right? So here, let's see it return here. So we have a get method that's very simple. If we ask for the water level up here, we're just going to return that underlying water level that we're kind of hiding from the user. And the reason you might want to do this is because the set water level is a more advanced method here. When you get a value in, the first thing you need to do if you're going to set a new water level is make sure that it's lower than the top of the tank, right? It can't be higher than the top of the tank. So if it's less than the top of the tank, then we set it to the same value. If it's not, then we set it to the height of the water tank. You can make different choices here. You could raise an error if you wanted to, other different types of things, but we're just basically using that to clip the height that the tank can be. And so here if we run this, here's a little bit of code down here that we're going to create our water tank. Then we're going to print what the height is. It should start out, or the water tank height should be 100. Then we're going to try to set the water level to 110, and it's going to clip it to 100. So let's try that first. Indeed, this worked. The tank height was set to 100. We set the water level to 110, but it did clip it to 100. So that's nice. We protected ourselves on that. But look what happened here. I came in and I just tried to set the water tank level to a stream. Well, that doesn't make much sense, right? We don't want to be able to do that sort of thing. But because the comparison operator between the value that came in, we can compare a stream to an integer or to a float here. This actually, it doesn't throw any errors. It just sets it to the water. Some, you know, you're not quite sure which, if it's going to go through the if statement or the else statement. It's kind of an ambiguous thing. We don't really want this to do something and set the water level to 100 here. We would rather raise an error, right? I mean, we don't want people to be able to set the water level to 100. And so, I mean, to a hello. So if we look at... No, not run. Pi cat. So if we look at another one here, what I've done in this case is I can supply a... to the property method, I can supply a trait that I want this to be. And what this is going to do is basically, yeah, this is a property, but I want you to use the validation of a float on this guy. And so, the water level is not going to be allowed to take on any values except what would also pass in through a float trait. And so now, if we run pretty much the same code that we did before, when we try to print our water level here, or set our water level to hello, we should get an exception raised. And indeed, that's what happened. We end up down here, the water level trait must be a type of float, meaning hello was set. So we protected ourselves now from maybe unpleasant behavior. All right. Oh, and there's also the capability, and this is... we end up doing this sort of thing quite a bit. So we have a method here. We have our same rectangle, and we're starting to add a few new attributes to it that are helpful, or at least one here. We have a width and a height, but we also have a property here called area. And so area is really just the self.width times self.height, right? That's the area of our rectangle. But we don't want to be able to set an area, right? It's really a read-only property that always has to be calculated whenever the width or the height are set. And so here, if we run this method then we run and here's the demo code that just ran. We created a rect is equal to rectangle. Now what is the default width and what's the default height? And then rect.area actually calls this method, and it always calculates instead of having a value here, a specific value that it returns. It always calculates it from its width and its height. So it's always up to date. There's also a method of caching these variables. If you've ever calculated this and you have information that it hasn't changed, you have to set up what the dependencies of variables are to say that this depends on other variables. I think I'll show an example of that later. But you can cache that value so that if those variables that depends upon haven't changed, you just immediately get the value back instead of having to recalculate it. So that's a handy feature that's available. Alright, so we've defined are there questions up to here? A property. And we noted that we can specify that a property has a specific trait type, like we said that this property was a float. But you may want to come along and add your own validation routine, right? That does something more complex or different than float. And so when you create a property, you actually have it has this signature that you can pass in. If you just pass in a trait, then it actually uses that trait's validate method. However, you can pass in your own get method so you don't have to use the nomenclature we specified where you say underscore set underscore height or underscore width. You can actually define some method named foo if you want to and f get equal foo will be used for the validation process. And there's also an f set method. And then there's a validate method and I'm not going to talk about these over here as much. But basically you can specify the f get f set and this validate and let's look at I think I have one here, pycat property validate method. So here I've declared two methods here called validate and validate even. So these are going to be validation methods. And validation methods expect to get the object that's the self that you see running around in these objects. So if we have a rectangle, for example this object is going to be the rectangle itself, the rectangle object. Then the name is the name of the trait that's being set and the value so if we were setting the width that would be width and then the value is going to be the actual value that the user is trying to set into this trait. And what we have here is in our validate odd we're going to print validate and we're just going to print out something so that you see that these execute. And then we're going to make sure that the value is indeed odd and if it is then we return the value. Otherwise we raise what's called a trait error. And when trait errors get raised by the validators that's what's printing out those little messages at the bottom that says this is not a string or you were supposed to put in a float and you gave me a string. So we have a validate odd and validate even and now if we want to declare this an odd value and an even value or they don't have to be named this they could be named foo and bar but you can set the validate method to validate odd and validate even. And then what we're going to do is when we get these values we're just going to save them out into a shadow trait just like we've been doing underneath all of our properties. There are other ways of doing this. This is a convenient one to demo. And so now if we have code and we set our foo.odd value equal three it'll print out our odd value. If we set the even value to two that'll work but if we try to set our odd value to four we're going to get a trait error and we're going to catch that here and just print this out and same there. So now we can run this so in each of the validate methods we printed out the actual object this is the repper for an object it just tells you it's a foo object and tells you the memory address and then the name of the trait we tried to set and the value and so it looks like it's working as we as we wrote it. So this is a nice feature you can just define a little function that you want and you can attach that as a validation on a property very quick pattern to being able to validate the values that are coming into your objects. Alright so that's kind of the basics we're going to try to fly through I only have about 25 minutes here and so we're going to try to fly through notification and show how that works alright so notification traits provides a very convenient way of doing a listener pattern on these attributes that you've declared and you can declare them statically that means in your class using a method or you can declare them dynamically by having something else listen for changes on your class and we'll show how these work. Here's a simple example and here we're declaring a class called amplifier it has traits and it has a volume and we haven't seen this trait but hopefully it makes some sense you have a range from 0 to 11 and the default value here is 5. Alright so now we have this this is done by convention again whenever you have a method that has you'll notice the volume here it's a protected method they're always protected but if you have volume that's the same name as here if you have volume changed or volume underscore changed you can create this method and any time this value changes this method is going to be called as well now note that this is not the validator or the property that's checking the value before it comes in or that sort of thing this is actually after the value's been set all the traits have been checked the values have been changed to its new value this method is going to be called and here it's called its old value the one that it had prior to this and it's new value there are a lot of signatures for this but this is one of them and now if we set this to 11 then it's going to print out a message for us so the demo code for this is we create our amplifier we set the volume to 11 and this one goes to 11 gets printed out if we call volume equal or set volume equal 11 again notice that nothing happens and the reason that nothing happens here is the value is already at 11 there wasn't actually a change so this is an observer pattern you can get in trouble sometimes with a lot of events firing and so this is one of the methods for preventing that you only fire the trait changed events when the object the value actually changes so here we go with pycat amplifier one so we have our amplifier it's range, volume and then here's the demo code that we just ran or showed so I can just run this it'll run that little piece of code down here at the bottom so we create our amplifier the dot volume equal 11 and it printed out this one goes to 11 we set the volume to 11 again nothing happens so that's the simplest kind of trait change handler that you can have just a static listener is what this is called on the class now if you have a method named like this if you come in and you misspell volume so if we come in here and I misspell volume now if I run this nothing happens right because that's not it doesn't find that there's a trait listener for this this trait because the name didn't match you can have multiple different signatures for these trait change methods so the simplest one is just to declare it with the self argument or where it doesn't take any arguments basically the method doesn't the second option is I just want to get the new value the second option is I need the old and the new and the fourth is you can actually have it where it also passes in its name and the old and new and so the name here is going to be volume so that's the name of the trait that's changing so all of those are valid signatures it depends upon what you're doing which one you need to use I use this one a whole lot but all of these come into play at some point so dynamic traits so now we have our amplifier and instead of wanting I want somebody else to listen to the change on my amplifier I don't want to have to set it in my class well the simplest way to do that this is if you just declare a simple method here called printer takes a single value and we're just going to print the new value now when we create our amplifier here only has a volume now we haven't put any static trait handlers on it but now we create our amplifier and we set on trait change and it has this is a method that's hooking up this is a hook up method to hook up a trait to a listener and what we do is the handler or the listener method method here is printer or method that we function that we define up here and then we only want it to hook up to volume if you don't specify a name I believe it go it hooks up to any trait so it listens to any trait change on the class is that that's correct okay but here we've specified volume so now when we specify spinal tap dot volume we should call this class so let's look here let's see pie cat so here's our amplifier here's our print method and now we'll hook up the trait change listener we'll set the value to 11 we'll set it to 5 and we also have a bar float this was probably from another demo actually but we'll set a bar float to 20 and note that the trait change is going to happen for either volume or bar here alright and you can also remove say on trait change but you specify remove equal to true then that removes the trait handler from volume right so now we're removing this printer method from volume and now if we set the volume to 9 hopefully we won't get any printouts and so let's look at running them so here we set the volume to 11 we got the print out from our printer method new value equals 17 we set the volume to 10 new value is 10 we set the bar value to 20 that got called set the volume to 20 our new value to 20 now we remove this trait change listener from the name volume now if I set the volume nothing happens because we no longer have that listener sitting there hooked up alright so the dynamic listeners have a slightly different notification signature it's not very different but you'll you can define with no arguments it's just going to get fired whenever anything or whenever an object changes but doesn't get any information you can specify that it only gets the new value or you can specify that it gets the name and the new value name of the trait or the object so you know we don't have a reference to self here because it's not a static handler attached to the class this is an external observer so we may want to get the object namely the amplifier in our case passed in with the name and the new and then the observer here you can also pass in the full signature is object name old new so that's all the information that you would have as well on a static trait change listener so another common thing to do is have a trait a class or a trait called an event and events just fire whenever a new value is set to them and you know here's an example of you know we've hooked up with sometimes this is a common pattern and observer patterns the first thing you do is you hook up listeners to all your traits it might be the first process you do and then you start building your application and it works great for a day or two or three or whatever it is but your application gets bigger and bigger and bigger and then you start using your objects in new ways and maybe you have some view that's hooked up some 3D geometry that's hooked up and listening to your object and then you go through a loop where you change all of the traits a million times very quickly your 3D view starts jittering I mean because it's trying to keep up with all of these trait changes it's just firing too many events so a common thing is to say no you don't want to listen to all the trait changes that occur I want to have explicit control over when updates occur or when something happens and so here's a this is a common pattern and this is a it's not used enough let me say in the way that people use the observer pattern this is the solution to a lot of problems it also you have to have the user has more control so that it's more work but it solves a lot of problems here we have width and height then we created an event called updated so now we have a rect is equal to a rectangle on trait change we're hooking up this method to the updated method and then we might set the width and the height and then we tell okay now you're updated I've changed all your values and this is done explicitly this could be done internally from the class in a method or it could be done explicitly you know externally to the class and this now will print out the information of what the rect width and height are so this is just a method of being more explicit about your control over when things fire so traffic light one this is an example where we have a more complex trait everything we've done so far is very simple but here's an enumerated type that allows a traffic light to be green, yellow, or red and so now we can set by default it's going to be the first value so light.color is green if we try to set it to blue we get an error so it will only take on one of these values I'm going to blaze through some of these to just give you ideas and not run them and list are kind of interesting things you can create define a list of objects in a class and this starts getting into some of the really strong powers of what traits offers in programming models but here we have a list A we can also define it that it's only a list of strings we can also say that it's only a list that will take a class that's one we define a class called person some place and that's all that it will take I'm not going to go over the last so here we have something like students equals list of strings we have a method called student changed and if we assign a new list into students then this is the method that gets called so this would print out the entire class has changed however there's also the potential that somebody goes in and they just change one element they delete something out of our list add something like that so then in that case this method fires so this is kind of another keyword type method so students students items changed you get an event in this case or a little object that hasn't added and removed in an index that tells you what objects have been added or removed from this from your class and so here you can print out what has been added what has been removed so we create a class we assign in the students to John, Jane and Jill and we get this method fired up here that tells us the entire class has changed if we append build a new person to our class says student added tells you what the index was and what the item that was added is if we delete items then items are removed and tells you what items are removed this is useful in a lot of places you run into this a lot and this looks a little bit this may be useful kind of thinking about some of the things that probably was going to do but you do have an array we spend all day talking about NumPy arrays so there's a trait that says you know an array this is the old style I need to update this this uses type code equal float that's what numeric used to use the new one would be d type equal float but you can declare an array that's of this type here how many rows it has but it has to have three columns so now we can create our mesh and have our points and triangles that are associated in this mesh and we can add them in there I'm not going to go through that much more because I need to get to these pieces an instance object if you have a family you created a class person you have a family you can say dad is an instance of person and the second set of arguments the default value for dad usually is none but if you say args equal and give what the arguments are then it's going to call a nip method for this class with these args for the default value here so dad is going to be default to a string John Doe to a man named John Doe now mom is going to have an instance of person but she's going to be Jane Doe because we're going to specify that the default keyword arguments for the name first name passed in to the person is Jane and notice you can always use for any whenever you initialize has traits class you can always pass in as keywords any of the trait names and that will be assigned in as the value for that trait and a daughter and you can either explicitly refer to person or you can refer to it as a string and this allows you to if you haven't declared the class person yet this is the approach you want to use okay this is the cool piece of this imagine you have a class that has a teacher and a set of students it's an instance of person you have a list of persons now a person has a name and an age on it so here again we have some magic names and we say age change for teacher so this actually hooks up a listener to listen for the age changing on the teacher it's not listening for something changing on it's not listening for the teacher changing it's listening for the age changed on the teacher it will also update if the teacher changed because if you change teachers then you have a new age more than likely that's for the teacher now for students we have a list of students you have 20 or this gets a little bit towards what you were talking about you maybe have 100 students in the class well what happens if an age changes on one of those students and here you can hook up a single listener that listens for any change in the age on any of those students and that's a this is an amazingly powerful pattern you run into this a whole lot and when you do this without this the code expands into lines I mean you know it's going to be multiple lines and we had a lot of code before this pattern was put into traits where we had bugs where we just did a cut and paste error of the little pattern that we used this saved a lot of headache it's a nice feature alright so simple UI the other thing that happens with traits is you have a simple employee has a first and last name and a gender and a social security number so we talk to somebody asked about more complex traits we have a trait called a social security number trait here I'm going to create an employee and then call configure traits and I get a UI immediately and the reason that we get a UI for this is configure traits can inspect this and it says listen I know what a UI for a string ought to look like I know what a UI for an enumerated type this is going to be a drop down box male female and social security trait is actually just a string with a regular expression so I'm going to call we'll call that class here and so here I can sit here and change this if I go in and change social security number from the US it's three digits, two digits, four digits orange red if you have a value that doesn't match the pattern that's allowed very nice set of capabilities if we want to undo it will undo we can redo okay so that may or may not be the UI you want but that's a very quick way to get up a UI you haven't had to do a whole lot of work right alright we'll just go quickly to let's see table so I'm just going to show you because we don't have time here we imagine you have a list of people in a class well one of the displays for this is actually just a table right and you define a table and here we define the order that the retired first last gender how this person is set up we can sit down here and you can construct a new one by just typing in a new person here whatever you want and that's added an item to our list of items in the class there's since the update to 2.8 we get a little bit of deprecation warnings here but this is a nice capability I mean you can quickly if you have a database of objects they just pop these up in these classes there's a cheap and cheerful way of doing this and then you keep getting a little more complex over time the trade 5 one you can you'll look at those in the demos this afternoon you can see that that it's a little bit of work but still you have that fairly rich capability there and then the last one I want to pop up here is so here we have a class called poly it has three traits A,B and C which are just coefficients to a quadratic polynomial an x array that's what we want to feed into this polynomial and then y is going to be a property and it's going to be calculated this is going to be y is equal to ax squared plus bx plus c and those we put in these traits that say depend on A,B,C and x so that means that listen whenever any of these values change this property needs to fire a trade change event so that somebody listening will grab that value we put in this fairly long item here that's this Chaco plot item that sets up I want to plot an x and y and give some information about how we want it plotted and then we have some editors down here for A,B and C range editor for negative 5 to 5 set up the width and height and then we set up our get y you remember this was a property and it just returns the polynomial value here alright we also have a default value for x I'm not going to go into that but if we run this then then we get a plot here and I have my sliders down here and as I change those I plot updates and so again there's not a whole lot of code here to be able to put together something that does a fairly nice job for you alright so I didn't get to any of the Chaco stuff should I show any of those or no no alright do it alright so we'll do Chaco right quick if I can find the okay so we're not going to go into Chaco I just want to give you some ideas of the kind of plots that you can create with Chaco so here's an interaction so that was the end of traits we're short on time so I'm not going to take any more questions but this is just showing a fairly large data set about 55 60,000 points here on these plots and then what you can do is on this top plot if I come in and I interact I can just add a little overlay there and now I've zoomed in on that region and this range here is tracking the zoom region here so you can move this around you can come in and grab these edges and change that and the plot updates and so this is the kind of plot that you create with Chaco is these very interactive plots it has an architecture for supporting this stuff fairly well and being fast I mean that was a large set of points alright let's go over to basic and just show so here's another example that we might run so you have a scatter plot this is a pseudo 3D plot you have three values you're plotting X and Y axis and then color is a third value and we have a color bar over here and you can come over here and select a range and all the other guys and you just see the ones in the area in that range that you want and so you can change this it's a nice way of interacting with your data and we'll do one more so here we have an image right that has a contour we have an image and overlaid a contour on top of it we have a color bar and then if I come in and I do a cross cut in here then you're seeing the the cross bars that are shown here and then on each axis well I can't move my mouse and show you unfortunately but you can see as I move this around what you're seeing on the bottom is the Y cut through here and what you're seeing on the left is the X cut and then we have a dot that's showing the color in that area so this is the sort of thing a lot of times you want to build these really interactive plots instead of just taking up a single plot and Chaco provides the tools for doing that