Using Docker to run Manim in Jupyter notebooks

If you want to develop Manim animations easily the a Jupyter notebook makes as great working environment. However it can be fiddly to get set up.

Luckily there is a pre-built Docker image that can get you up and running with two simple commands:

cd <your working directory>
docker run --rm -it -p 8888:8888 -v "%cd%:/manim" manimcommunity/manim jupyter lab --ip=0.0.0.0

In the console you will then see a URL looking something like http://127.0.0.1:8888/?token=xxxxxxx. Cut and paste this into your browser and you are away laughing.

For Linux you will need to tweak the %cd% bit and use pwd instead so:

cd <your working directory>
docker run --rm -it -p 8888:8888 -v "$(pwd):/manim" manimcommunity/manim jupyter lab --ip=0.0.0.0

These commands mount the current directory into the docker container, so any notebooks or videos you create will be saved into that directory and won’t be lost when you stop the container.

Finally to create an animation put the following code into two separate cells in a new notebook:

from manim import *

and

%%manim SquareToCircle

class SquareToCircle(Scene):
    def construct(self):
        circle = Circle()  # create a circle
        circle.set_fill(PINK, opacity=0.5)  # set color and transparency

        square = Square()  # create a square
        square.rotate(PI / 4)  # rotate a certain amount

        self.play(Create(square))  # animate the creation of the square
        self.play(Transform(square, circle))  # interpolate the square into the circle
        self.play(FadeOut(square))  # fade out animation

When you run the notebook you will see the rendered animation (and it will be saved into a media sub-directory). The %%manim line is the magic instruction to trigger Manim to render the specified scene.

Using Docker to run Jupyter notebooks

If you are messing with data then, you can’t beat a Jupyter notebook as a working environment. Not only are they super easy to use but they are effective ways of sharing your workings and findings.

Even better, the Jupyter project have a created a bunch of Docker containers that contain all the tooling you need which, makes getting up and running as simple as running a two simple commands:

cd <your working directory>
docker run --rm -it -p 8888:8888 -v %cd%:/home/jovyan/work jupyter/datascience-notebook

In the console you will then see a URL looking something like http://127.0.0.1:8888/?token=xxxxxxx. Cut and paste this into your browser and you are away laughing.

For Linux you will need to tweak the %cd% bit and use pwd instead so:

cd <your working directory>
docker run --rm -it -p 8888:8888 -v $(pwd):/home/jovyan/work jupyter/datascience-notebook

If you need to sudo to install something you will need to run the container as root and set the GRANT_SUDO environment variable:

docker run --rm -it -p 8888:8888 -u root -e GRANT_SUDO="yes" -v %cd%:/home/jovyan/work jupyter/datascience-notebook

Lastly the jupyter/datascience-notebook container generally has all you need but if you are doing something specfic, there are a bunch of other options, including ones that contain R, Tensorflow, Scipy and Apache Spark support. See https://jupyter-docker-stacks.readthedocs.io/en/latest/using/selecting.html for more info

Tech Tip: Start a simple web server

Python ships with a handy little web server that will serve up the files in the folder from which it is run. This is really handy for development.

Run the following command to start the server:

python -m SimpleHTTPServer

Or if you are using Python 3, run:

python -m http.server

L is for Logo and wee little turtles

Logo was one of first programming languages (after BASIC) that I really learned in depth. The most famous aspect of Logo is its turtle graphics which simulates a tiny turtle to which you can give commands such as forward, backward, left turn and right turn. As the turtle moves on the screen it draws a line behind it.

With its graphical feedback, turtle graphics is an ideal way to introduce people to programming. Today I thought I’d go over some examples. I’m not going to use Logo but rather the Python programming language which has a turtle graphics module.

First steps, install Python and then launch IDLE (the Python installer should have created a short-cut). Now enter in the following (press Enter at the end of each line):

from turtle import *
showturtle()

You should see window with a black arrow in it. This is the turtle. Now type

forward(100)

The turtle should now move forward 100 turtle steps. Next enter the following lines:

right(90)
forward(100)
left(90)
forward(100)

The right and left commands turn the turtle the number of degrees you specify. It gets a little tedious to type these out the whole time so there is a shorthand. Try these commands:

bk(50)
fd(50)
rt(45)
lt(45)

Ok let’s try something more interesting. We are going to draw a square but first let’s clear the screen:

clearscreen()

Now the square:

fd(100)
rt(90)
fd(100)
rt(90)
fd(100)
rt(90)
fd(100)
rt(90)

Nice. But what if you want to draw lots of squares. It would get very boring typing out all those commands over and over again. Let’s tell the computer how to draw a square (note the indentation of the lines, these are important):

def sq():
    fd(100)
    rt(90)
    fd(100)
    rt(90)
    fd(100)
    rt(90)
    fd(100)
    rt(90)

Now we can just type:

sq()

to draw a square! Try this:

sq()
rt(5)
sq()
rt(5)
sq()

Shiny, we are getting a neat pattern forming… but once again it’s too tedious. So enter this:

clearscreen()
speed(0)
for i in range(6):
    sq()
    rt(60)

The speed command makes the turtle move faster so we don’t have to wait. The for statement gets the computer to repeat a set of commands and the range(6) command creates the numbers 0 to 5, which means that the commands sq() and rt(60) are repeated 6 times. Lets add a fd command in each iteration (step) of the loop:

clearscreen()
speed(0)
for i in range(72):
    sq()
    rt(5)
    fd(20)

And we get a donut type thing. Finally lets go crazy and write a new command called polyspi that calls itself!

def polyspi(angle,inc,side,times):
    if times > 0:
        fd(side)
        rt(angle)
        polyspi(angle,inc, (side + inc),(times - 1))

This is called recursion and because it changes it’s side and times values when it calls itself, we_ _can generate all sorts of interesting patterns such as:

clearscreen()
speed(0)
polyspi(90,5,50,50)

polyspi Example 1

or

clearscreen()
speed(0)
polyspi(95,1,50,100)

polyspi Example 2

or

clearscreen()
speed(0)
polyspi(117,3,25,200)

polyspi Example 3

To find out more check out the Python turtle documentation. Have fun!

Tech Tip: Change AngularJS template delimiters

I have recently been doing some development with the Bottle Python web app framework. Unfortunately it’s simple template system uses the same template delimiters as Angular (“{{” and “}}”). Worse you cannot change these delimiters in Bottle.

Fortunately you can change them in Angular using the following:

var myApp = angular.module('talkpoint', [], function($interpolateProvider) {
    // set custom delimiters for angular templates
    $interpolateProvider.startSymbol('[[');
    $interpolateProvider.endSymbol(']]');
});

Which given a Controller looking like this:

myApp.controller('TodoCtrl', ['$scope', function($scope) {
    $scope.todos = [
        {text:'learn angular', done:true},
        {text:'build an angular app', done:false}];
}]);

Allows you to write Angular template code looking like this:

<div ng-controller="TodoCtrl" class="row">
  <ul >
    <li ng-repeat="todo in todos">
      <input type="checkbox" ng-model="todo.done">
      <span class="done-[[todo.done]]">[[todo.text]]</span>
    </li>
  </ul>
</div>