 Good afternoon. I want you all to welcome Catherine showing us how to do computer art with Python. Thank you for coming. My name is Catherine and for five years I was a graduate student in physics at the University of Waterloo. Now the University of Waterloo in their Faculty of Science offers a computational science degree. It's a cross-departmental degree program that tries to teach people without very much programming experience but a lot of enthusiasm for science. How to use programming to be more efficient at science. And during my time as a grad student I was the teaching assistant for the computational physics classes which used Python to be very basic Python to teach physics concepts such as classical mechanics, integrating differential equations, stuff like that. And today I'm going to tell you about a Python library that I've been writing that was inspired by my time as a teaching assistant. So every great software development project begins with a great user story. So for this presentation let's imagine that our user is the freshman meme guy. So the freshman meme guy is a computational science student. He has no prior programming experience to the computational physics class that he took and he's also a big fan of Quidditch. And the midterm for computational physics came on the day after the intramural Quidditch finals so he flunked his midterm and now he's looking for some extra credit. And his university professor says okay the midterm mark will be ignored if you can make me a nice pretty animated visualization of your Keplerian planet simulation. So the freshman meme guy goes off to Google and he looks for 3D drawing options in Python and the first thing that he finds is processing in Python mode. So has anyone used processing in this audience? It's pretty awesome in my humble opinion. It was created by Ben Fry and Casey Reese in 2001 while they were part of the MIT Media Lab. Processing is the name of the project, the IDE and the programming language and it's targeted at artists and beginners. And in recent years it has a Python programming mode. So the freshman meme guy looks up the sample code to draw a red spinning cube and he finds this and it's all human readable. He doesn't quite understand variable scoping so the global word is kind of magic to him but otherwise it makes sense. There's one method called setup that executes once when the program starts and then there's one method called draw that executes every single time the frame or the window is drawn to. And it produces something sensible that looks like this. So the freshman meme guy is happy. He goes off with processing and implements his planets and goes to try to pull out his simulation and put it in processing. But the first thing he encounters when he tries to import sci-pi is this import error no module named sci-pi. And now this makes our freshman meme guy very upset. Because he is absolutely sure that he has sci-pi installed on his computer and in his Python environment. I mean he's been using it all semester for his classes. So he encounters this problem because the Python mode in processing is kind of a veneer over a Java under belly. So he gives up on that approach and goes back to Google. The next thing he finds is pyopengl. So pyopengl is one of the Python bindings. To opengl it's like how pyqt is to qt. So he looks up the sample draw spinning cube example in pyopengl. So the imports look friendly. He just has to import the graphics library and then the graphics library utility tools. Like with the processing demo there's one method that executes once on setup. It's really confusing to him because he doesn't know what any of these things are doing. But it only happens once so that's fine. He can just ignore it for now. Then he looks at the method that is going to execute every single time. And you should not do this. But the method that comes up the most often in really basic opengl tutorials to draw a cube is to draw six quadrilaterals, one for each side. Now you should not do this if you're going to do any high performance stuff but it's kind of the simple way of drawing a cube. But to do this you have to draw four vertexes, one for each corner of each quadrilateral. And this is what the entire code to draw a cube looks like. And then you can create a window using the utility tools. So our undergrad looks up the example. It's like, okay, well this makes sense. This is what I expected to be drawn. And then he goes off and says, well, I'll just figure out how to draw spheres with this. So he goes to the opengl group and downloads the opengl cheat sheet. Now the problem with that is that the opengl cheat sheet is not actually an opengl cheat sheet. It's not a single sheet. It is actually a 13-page Adobe PDF document. And the first page in nine-point font is everything just about buffers. Now keep in mind that this is a computational science student and not a computer science student. He's only had maybe three months at most of programming and he does not even know what a pointer is. And to be honest, as a Python user, I don't really like to use pointers either, so I can understand his woes. So this makes him upset. He goes back to Google. He looks again. He finds a module called Piglet. So Piglet is also an opengl binding, but it has submodules for windowing in multimedia. And it can produce the same sorts of animations that pyopengl does. So the undergrad looks at the code. It all seems logical. The imports look logical. The code to actually update his animation and draw a window looks really nice. Like he can understand what a window is, he can understand having a clock that he has to schedule to update, and he can understand running his app. So this makes him happy. So then he's like, okay, great. I'm going to continue with this. Let's look at the actual code for drawing a cube. And he sees exactly the same thing that he saw in pyopengl, and now on top of that, there's the scary at symbol because he has not been taught decorators, and he doesn't even want to try to figure out what that is. And again, the actual drawing of the cube is the same. So this makes him unhappy. All right, so the final option he comes across is called vPython. So just from background on vPython, it was created by David Sherer in 2000 to replace CT, which is what they were using to teach computational physics at Carnegie Mellon. It is currently maintained by Bruce Sherwood, who was one of the original developers of CT. And it was designed specifically for helping students learn physics through programming. How it works is that all of the actual OpenGL calls are written in C++, and that gets compiled to a module called Cvisual, and then the actual windowing is based on WX Python and sort of just hooks into this compiled Python module. And just as an example of how this is used in classes that are going on today, this is some vPython for teaching students Newton's second law, f equals ma. If you remember back to your high school physics, you might have had a similar lab to this that involved launching beanbags at your classmates. This is a great innovation because it prevents any beanbag launching related injuries. But basically you create a ball, you add a velocity to it, you apply the force of gravity to it, and then you integrate the force of gravity onto the velocity, and then you can also demonstrate the additivity of forces by subtracting a drag force. So just to give you an example, this is what it would actually look like on your screen, and you can see what the effect of drag is. No beanbags hurt in the process. All right, so the undergrad looks up the code for drawing a red spinning cube, and it is five lines. It's super nice, and it all makes sense to him. And on his Windows laptop, it looks like this. So based on that, he creates his visualization, it all looks good on his laptop, and then he uploads it to the physics marking server, which is running Ubuntu, and a few minutes later, he gets an email from his prof while he's still in this euphoric mood that says, there is no Debian package for WX Python 3. Can you please come to my office and show me your animation? And now this is a problem for the undergrad meme because his physics prof is a nice guy, but he tends to go on about how great physics and programming is, and he really just wants to get back on the soccer field and continue his quidditch practice. So that ultimately makes him upset. So what I'm trying to communicate in this user story is that writing really simple graphics libraries that are kind of platform-independent is really hard. So what if we had an openGL helper? So the idea here is vPython established a really nice API. So what if we extract that from the C++ code, but let some other Python project that has already done a lot of hard work on making openGL cross-platform Python hooks do the heavy lifting. And then the final thing we want to do is obscure the windowing. So this is one advantage that Piglet has over PyOpenGL is that they make the windowing really easy. All right, so the first thing that I have to do if I'm going to build this thing is decide which openGL binding I'm going to use. And PyOpenGL has support for a lot more of openGL, and it also currently has support for 3.5 while as Piglet appears to be kind of a dead project right now. And so this is where I made the first fatal flaw in creating this library because I picked Piglet. And the reasons I did that were just number one, it has much better documentation, something to keep in mind when I'm writing my own stuff. And secondly, I was kind of an openGL noob at the start and the extra app and window libraries make things really easy. All right, so this is the package that I created. It's a helper for Piglet or Piglet Helper. It has a submodule called objects, which contains geometric primitives, and it has a submodule called utils that has mathematical primitives for doing transformations. And I let Piglet.gl interact with OpenGL, and then I use Piglet's window and app things to handle the display. All right, so I'm going to do a few just comments on implementation before I just go off and show the animated GIFs. So converting from C++ to Python is not... Unfortunately, it's not as easy as just doing a search replace on curly braces. There are several things you can do in C++ that you cannot do in Python, for example, having multiple method declarations. And the way that I chose to do this and still have the same functionality is to use the getItemSetItem and length operators on classes. So just as in the previous slide, I would initialize a vector by passing it three numbers, passing it nothing, which would initialize it to zero, or passing it another pointer to an array. I can pass it any object which has length greater than two or three, and then assign the first element to x, second element to y, third element to z. Now, the second fatal flaw that I did was decide to go with pep styling on this project, and so this project was built back in 2001, where I don't even think Pepe was written back then. So that meant that I changed everything slightly, so it doesn't like lowercase object names. It also doesn't like single character properties. So these are the types of changes I made. And now, given that I'm making all these changes to the API, how do I make sure things don't break? And since this is a beginner talk, I'm just going to explain how to use continuous integration. So I use Travis CI, which is free as in beer, but not free as in speech. So every time I commit a new change to GitHub, it runs set up Py for Python 2.7 through 3.4. It pilots, and then it runs the unit tests. Now, this provides a unique challenge in this situation, which is that Travis CI runs on a headless server, but OpenGL requires a display to draw to, even if you just want to load the modules. And this is something that I had trouble with, because my naive solution is just, well, let's render to a still image, and then we'll just compare the images from previous builds to this current build. However, I'm having trouble with that because it seems like I should be able to use Xdummy, but that requires the NVIDIA X driver, and then the NVIDIA X driver doesn't seem to work correctly on headless systems, but I know this should be theoretically possible because other projects have done these things, and if you have done this before, please talk to me afterwards. So my alternative right now is just to mock GL. So in the mock module in Python, there is a useful decorator called patch, and what that allows you to do is that in your unit test, you can just replace any time that an object is called, you replace it with another object. So in box, box will import piglet.gl as GL, and then in my patch, I'm just going to replace GL with my own fake GL, and then my own fake GL module has all the function primitives, but it does essentially nothing. Now, this is kind of cheating in a way, but I'm not really testing OpenGL. I'm really just testing that my modules all work when they call each other and that everything imports correctly. All right, so now that I've talked about some boring implementation details, I'm just going to go over some functionality. So these are the geometric primitives implemented. There's an arrow, sphere, cube, cone, cylinder, ellipsoid ring, and pyramid. And then there's also things called lights and scenes. So a scene object contains information about the camera position and some details about the default lights. The lights are non-renderable objects that you can stick in the scene. And then the objects can either be drawn into the scene by passing them to the scene as an... or sorry, the scene has a list of objects. You can either add the object to that list or you can pass the scene to the object's draw method. So just to clarify what I mean, I have a box and a scene. I can either render the box in the scene by passing scene as an argument to render or by appending the box to the scene and then setting up the scene. All right, so just to finalize, this is what the freshman's code would look like in Piglet Helper. So I've, in addition to everything else, just created a default scene with a default camera position and some default lights. And you can just create that using vSetup and it will automatically add any objects you call after that to that scene. You define an update function just as you would with any of the other ones and then you can run the scene. And I've also added a really useful utility for generating objects. And this is really great if you want to spam your Twitter profile with animated GIFs. And that is what it looks like. All right, so I started this project last year after getting really frustrated about getting visual working with Python 3. The original developers of vPython had the same problem, but they decided to take a different approach, which was, since they do mostly teaching stuff, to switch to a Jupyter Notebooks-type environment. So they switched from OpenGL to WebGL. And they created this JavaScript library called Glowscript, which allows you to use vPython syntax in WebGL. And then they created this website called Glowscript.org, where you can type in Python code and have it render on the web. However, just like processing in Python mode, this doesn't give you access to everything else in Python. And then the other module they created was called vPython Jupyter. So they use 0mq to actually do the communication and to feed some JSON back into Jupyter to render in the Jupyter Notebook. And they're using the actual Glowscript JavaScript library that they've hosted on Glowscript.org to actually render this. And this is what it looks like. It's not quite the same because you have to define these scene variables. But again, it looks very, very similar to vPython Classic Edition. All right, so for future work on Piglet Helper, so I made two fatal flaws, as I said. The first one is that I made styling changes to match modern styling. And I think this was a really bad idea because the people who used this library all operate out of textbooks, and textbooks don't update as fast as the Internet. So it doesn't make sense to make a library that doesn't match the old API. So I think my first step is going to be to undo that. I also haven't implemented 3D Text, which is something that is available in vPython. And then finally, I think I need to switch off of Piglet because it does not have support for Python 3.5. And now, a few days before the conference, it came to my attention that vizpy probably could do a very similar thing. And a year ago, when I started this, I looked into vizpy, and they had not yet implemented some objects trying, but now they have. So if you're looking for something that is more fully featured, that is probably a lot more stable, and another benefit is that it implements... It works with several different backgrounds. So it works with PyQt4, PyQt5, and Piglet and PyOpenGL with a little bit of work. You should really check out vizpy. So this is the sample rotating cube code that I have found that is the simplest, I think, for vizpy. And as you can see, it's not quite as dead easy as you might want it to be, but it's still very, very nice. So that's what I would suggest you use instead of my library. But just as a final experiment, I really want to try to communicate what sort of wonderful things can happen when you lower the barriers of entry to 3D drawing, just like what processing has been able to do. Because a lot of us here in the audience are experts in a certain domain, but we probably aren't experts in OpenGL, but we are still humans, and humans have eyeballs, and humans like looking at things. So just as a crazy experiment, a few days before the conference, I decided what if I feed a Piglet helper into the distributed evolutionary algorithms project and use a scikit image to judge the similarity of images generated. So the idea is I'm going to try to generate the Python logo using a Piglet helper attached to an evolutionary algorithm. And so this is what you see. It's not the greatest because of the artificial limitations I put onto the search space for the evolutionary algorithm, but you can see that it eventually learns from just a mix of chaos to put yellow spheres in the bottom half and blue spheres in the top half. Anyway, thank you. Any questions? So you said Piglet is kind of a dead project. Have you got in touch with the developers or saw the mailing list because there's appearing to be some activity, some renewed activity around Piglet now? Oh, no, I hadn't. But that's very exciting to hear. Did you also have a look at game engines because they might provide similar functionalities to maybe sometimes an easier package? Can you repeat what that... Did you have a look at game engines? There are some game engines available for Python? Oh, game engines. Yeah, I looked into Pygame and it had a lot of cruft that I wasn't particularly interested in for game development, but perhaps I should look at it again. Anymore? Oh. Hi, thanks for the talk. It's really interesting. You've used the kind of college university student as the target. I wonder what are your thoughts for creating 3D graphics for somebody who might be seven years old? So the reason that I use a university undergraduate student is that in Canada, where I'm from, we have really terrible computer science education. So even though students... I believe personally that students who are seven who can read English would totally be able to use V-Python, typically students don't encounter their first programming class until their first year of university. One more question to you, Hasbither. What do you think about processing Python mode? So... I really should have just pressed the home button, but whatever, my finger will get a workout. Okay, so the first one that I went over was processing in Python mode. And as I said, this didn't really work for the application because you aren't able to access the full Python stack. And I've looked into trying to incorporate the Python stack into processing in Python mode, and the thing is that I hate Java way too much to invest any more time in that. Thank you, Catherine. Thank you all. Thank you.