Date

So, I'm taking the leap and migrating from Wordpress to pelican. Less than year ago I switched to Wordpress from an ancient Zope site and was happy to have something that worked easily. I was very busy at the time and I guess I felt old and didn't want to deal with hacking just to make a blog post. However, when I tried to experiment with d3 and wordpress it was ugly, even though there were some plugins to help. And when I tried to include an IPython notebook, all I could do was an <iframe> embed, and that was ugly both visually and technically.

Recently, I've been playing more with IPython and had more familiarity with the git-o-sphere. I'd like to blog more with code and technical stuff, and I was taken with the seamlessness of Jake Vanderplas's Pythonic Perambulations. I also like the nice mix of static html and dynamic widgets and services, so I decided to give it a go. Currently, the site is being published to GitHub pages at cranmer.github.io, but I'm going switch it over to theoryandpractice.org soon. I'm still conflicted if I should use GitHub's hosting or my current hosting service since I'm paying for a flask server and I don't plan on giving that up.

Anyways, I'll say I drew heavily on these resources:

Great! Now I can render_math like $e^{i\pi}+1 = 0$ and include a little block of python with pygments

    def main():
        print 'welcome to Pelican'

I was able to export my wordpress site to XML and import using the pelican-import tool. The images were a bit of a disaster, so I had to manually change all of that. I was also able to make the URLs to my posts to keep the old wordpress convention. I haven't yet moved the site to theoryandpractice.org, but this will keep the links working if/when I do.

Workflow issues:

I'm happy to use virtualenv, but it's not quite clear to me the best way to use it for pelican development. Should I be using virtualenv for my pelican installation, which I then use to build my site (which I think of as some data); or am I using virtualenv to encapsulate all my site's dependencies (themes, plugins, etc.) ? Currently, I'm not using git submodules, b/c I've heard they are somewhat evil (TM). This also affects the use of ghp-import... am I using the same repository for my pelican content and configuration as I use to deploy? Currently, I have a separate repository for pelican source and the rendered html.

Issues:

  • How do I style the liquid literal {% include_code learnEmbedding.py lang:python learnEmbedding %}
  • {% youtube %} tag working, but
    • does it work with start/end time?
    • does it support change to height/width of iframe?

Notes on getting notebook to work

  • IPython command line worked, but import IPython wasn't working. Was a virtualenv issue, did a pip install (very fast) and all good now.
  • Adding the EXTRA_HEADER doesn't work until the _nb_header.html is generated. If there is no check for the file, the devserver has problems.
  • I wasn't sure where to put the {% if EXTRA_HEADER %} code, but found that it should go in themes/base.html. Unfortunately, the _nb_header isn't playing well with the pelican-bootstrap3 theme... the notebook is styled, but the menu, buttons, and headers of the rest of the page are modified.
  • ok, made _nb_header_minimal only taking the last ~113 lines of _nb_header that have the script to call mathjax on the notebook (else the math doesn't render for the imported notebook) and the highlight style. That gives me the basics to make the notebook look reasonable.
  • another idea to wrap notebook

Notes on themes:

  • see note above about where to stick the EXTRA_HEADER for the IPython notebok.
  • using Bootstrap3 to get the twitter and recent publication feeds to have a nice responsive layout on homepage

Some fun

Ok, enough talk. Let's try a few cells from my IPython notebook of a Spirograph Animation for fun. I'll type:

{% notebook downloads/notebooks/Spirograph3d.ipynb cells[9:10] %}

and that produces:

A Spirograph Animation with matplotlib and iPython

This notebook is inspired by the blog post on Pythonic Perambulations.

License: BSD (C) 2014, Kyle Cranmer. Feel free to use, distribute, and modify with the above attribution.

When teaching Physics I at NYU I gave a challenging problem to my students to use change of coordinates with rotations and translations to derive the parametric equation for a spirograph. They also had to solve for the velocity and acceleration. It was hard, but a lot of students liked it. In the process, I made some pretty plots and posted them to Flickr. When I saw Jake's awesome animation examples, I had to try it out with something novel.

In [1]:
%pylab inline
Populating the interactive namespace from numpy and matplotlib

Now we'll create a function that will save an animation and embed it in an html string. Note that this will require ffmpeg or mencoder to be installed on your system. For reasons entirely beyond my limited understanding of video encoding details, this also requires using the libx264 encoding for the resulting mp4 to be properly embedded into HTML5.

In [2]:
from tempfile import NamedTemporaryFile

VIDEO_TAG = """
 {0}" type="video/mp4">
 Your browser does not support the video tag.
"""

def anim_to_html(anim):
    if not hasattr(anim, '_encoded_video'):
        with NamedTemporaryFile(suffix='.mp4') as f:
            anim.save(f.name, fps=20, dpi=70,extra_args=['-vcodec', 'libx264', '-pix_fmt', 'yuv420p'])
            video = open(f.name, "rb").read()
        anim._encoded_video = video.encode("base64")
    
    return VIDEO_TAG.format(anim._encoded_video)

With this HTML function in place, we can use IPython's HTML display tools to create a function which will show the video inline:

In [3]:
from IPython.display import HTML

def display_animation(anim):
    plt.close(anim._fig)
    return HTML(anim_to_html(anim))

Now define a class for the spirograph.

In [4]:
class spirograph():
    def __init__(self,a,b,f,noZ=False):
        self._a=a #number of teeth on small gear
        self._b = b #number of teeth on outer wheel
        self._rho = f*a #radius of pen from center of small wheel (in units of tooth spacing) [redundant with below]
        self._f = f  #fraction of the inner wheel's radius for where the pen goes.
        self._noZ = noZ #a switch so that the z-component of the spirograph traces time.
    def inspect(self):
        print self._a, self._b, self._f
    def graph(self,t0):
        #if t0==0: self.inspect()
        a=self._a
        b=self._b
        rho=self._rho
        f=self._f
        lengthscale=5.*2*np.pi/b #scale the spirograph so outer ring is ~5 in graphing coordinates
        timescale=min(a,b)/gcd(a,b) #scale timing so that when t0=2π the spirograph is a closed curve
        return (lengthscale*((b-a)*cos(timescale*t0)+rho*cos(-(1.*b/a -1.)*timescale*t0)),
                lengthscale*((b-a)*sin(timescale*t0)+rho*sin(-(1.*b/a -1.)*timescale*t0)),
                0 if self._noZ else 5+5*t0 )
In [5]:
import numpy as np
from numpy import sin, cos

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.colors import cnames
from matplotlib import animation
from fractions import gcd

# Solve for the trajectories (if t->2pi the spirograph will complete)
t = np.linspace(0, 2.1*np.pi, 500)

noZswitch=True
myspiros = [spirograph(a=63,b=96,f=0.6,noZ=True),spirograph(a=63,b=96,f=0.8,noZ=True),
            spirograph(a=51,b=96,f=0.6,noZ=True),spirograph(a=51,b=96,f=0.8,noZ=True)]
N_trajectories = len(myspiros)


x_t = np.asarray([[myspiro.graph(t0) for t0 in t] for myspiro in myspiros])
In [6]:
#use the right sum http://stackoverflow.com/questions/17313853/unexpected-typeerror-with-ipython
#maybe there's a better way?
import __builtin__
sum = __builtin__.sum
In [7]:
#3-d plotting with minimal modifications from Jake's lorentz system example
# Set up figure & 3D axis for animation
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1], projection='3d')
ax.axis('off')

# choose a different color for each trajectory
colors = plt.cm.jet(np.linspace(0, 1, N_trajectories))
for c in colors:
    print c

# set up lines and points
lines = sum([ax.plot([], [], [], '-', c=c)
             for c in colors], [])
pts = sum([ax.plot([], [], [], 'o', c=c)
           for c in colors], [])

# prepare the axes limits
ax.set_xlim((-25, 25))
ax.set_ylim((-35, 35))
ax.set_zlim((5, 55))

# set point-of-view: specified by (altitude degrees, azimuth degrees)
ax.view_init(30, 0)

# initialization function: plot the background of each frame
def init():
    for line, pt in zip(lines, pts):
        line.set_data([], [])
        line.set_3d_properties([])

        pt.set_data([], [])
        pt.set_3d_properties([])
    return lines + pts

# animation function.  This will be called sequentially with the frame number
def animate(i):
    # we'll step two time-steps per frame.  This leads to nice results.
    i = (2 * i) % x_t.shape[1]

    for line, pt, xi in zip(lines, pts, x_t):
        x, y, z = xi[:i].T
        line.set_data(x, y)
        line.set_3d_properties(z)

        pt.set_data(x[-1:], y[-1:])
        pt.set_3d_properties(z[-1:])

    ax.view_init(90*cos(np.pi*i/500.), 0.3 * i)
    fig.canvas.draw()
    return lines + pts
[ 0.   0.   0.5  1. ]
[ 0.          0.83333333  1.          1.        ]
[ 1.          0.90123457  0.          1.        ]
[ 0.5  0.   0.   1. ]

Now make the animation and display it

In [8]:
anim = animation.FuncAnimation(fig, animate, init_func=init,
                               frames=500, interval=30,blit=True)
display_animation(anim)
Out[8]: