{
 "metadata": {
  "name": "Animations_and_Progress"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "Simple animations, progress bars, and clearing output"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Sometimes you want to print progress in-place, but don't want\n",
      "to keep growing the output area.  In terminals, there is the carriage-return\n",
      "(`'\\r'`) for overwriting a single line, but the notebook frontend does not support this\n",
      "behavior (yet).\n",
      "\n",
      "What the notebook *does* support is explicit `clear_output`, and you can use this to replace previous\n",
      "output (specifying stdout/stderr or the special IPython display outputs)."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A simple example printing our progress iterating through a list:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": true,
     "input": [
      "import sys\n",
      "import time"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from IPython.display import clear_output\n",
      "for i in range(10):\n",
      "    time.sleep(0.25)\n",
      "    clear_output()\n",
      "    print i\n",
      "    sys.stdout.flush()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The AsyncResult object has a special `wait_interactive()` method, which prints its progress interactively,\n",
      "so you can watch as your parallel computation completes.\n",
      "\n",
      "**This example assumes you have an IPython cluster running, which you can start from the [cluster panel](/#tab2)**"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from IPython import parallel\n",
      "rc = parallel.Client()\n",
      "view = rc.load_balanced_view()\n",
      "\n",
      "amr = view.map_async(time.sleep, [0.5]*100)\n",
      "\n",
      "amr.wait_interactive()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "You can also use `clear_output()` to clear figures and plots.\n",
      "\n",
      "This time, we need to make sure we are using inline pylab (**requires matplotlib**)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%pylab inline"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from scipy.special import jn\n",
      "x = np.linspace(0,5)\n",
      "f, ax = plt.subplots()\n",
      "ax.set_title(\"Bessel functions\")\n",
      "\n",
      "for n in range(1,10):\n",
      "    time.sleep(1)\n",
      "    ax.plot(x, jn(x,n))\n",
      "    clear_output()\n",
      "    display(f)\n",
      "\n",
      "# close the figure at the end, so we don't get a duplicate\n",
      "# of the last plot\n",
      "plt.close()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "A Javascript Progress Bar"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "`clear_output()` is still something of a hack, and if you want to do a progress bar in the notebook\n",
      "it is better to just use Javascript/HTML if you can.\n",
      "\n",
      "Here is a simple progress bar using HTML/Javascript:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import uuid\n",
      "from IPython.display import HTML, Javascript, display\n",
      "\n",
      "divid = str(uuid.uuid4())\n",
      "\n",
      "pb = HTML(\n",
      "\"\"\"\n",
      "<div style=\"border: 1px solid black; width:500px\">\n",
      "  <div id=\"%s\" style=\"background-color:blue; width:0%%\">&nbsp;</div>\n",
      "</div> \n",
      "\"\"\" % divid)\n",
      "display(pb)\n",
      "for i in range(1,101):\n",
      "    time.sleep(0.1)\n",
      "    \n",
      "    display(Javascript(\"$('div#%s').width('%i%%')\" % (divid, i)))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The above simply makes a div that is a box, and a blue div inside it with a unique ID \n",
      "(so that the javascript won't collide with other similar progress bars on the same page).  \n",
      "\n",
      "Then, at every progress point, we run a simple jQuery call to resize the blue box to\n",
      "the appropriate fraction of the width of its containing box, and voil\u00e0 a nice\n",
      "HTML/Javascript progress bar!"
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "ProgressBar class"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "And finally, here is a progress bar *class* extracted from [PyMC](http://code.google.com/p/pymc/), which will work in regular Python as well as in the IPython Notebook"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": true,
     "input": [
      "import sys, time\n",
      "try:\n",
      "    from IPython.display import clear_output\n",
      "    have_ipython = True\n",
      "except ImportError:\n",
      "    have_ipython = False\n",
      "\n",
      "class ProgressBar:\n",
      "    def __init__(self, iterations):\n",
      "        self.iterations = iterations\n",
      "        self.prog_bar = '[]'\n",
      "        self.fill_char = '*'\n",
      "        self.width = 40\n",
      "        self.__update_amount(0)\n",
      "        if have_ipython:\n",
      "            self.animate = self.animate_ipython\n",
      "        else:\n",
      "            self.animate = self.animate_noipython\n",
      "\n",
      "    def animate_ipython(self, iter):\n",
      "        print '\\r', self,\n",
      "        sys.stdout.flush()\n",
      "        self.update_iteration(iter + 1)\n",
      "\n",
      "    def update_iteration(self, elapsed_iter):\n",
      "        self.__update_amount((elapsed_iter / float(self.iterations)) * 100.0)\n",
      "        self.prog_bar += '  %d of %s complete' % (elapsed_iter, self.iterations)\n",
      "\n",
      "    def __update_amount(self, new_amount):\n",
      "        percent_done = int(round((new_amount / 100.0) * 100.0))\n",
      "        all_full = self.width - 2\n",
      "        num_hashes = int(round((percent_done / 100.0) * all_full))\n",
      "        self.prog_bar = '[' + self.fill_char * num_hashes + ' ' * (all_full - num_hashes) + ']'\n",
      "        pct_place = (len(self.prog_bar) // 2) - len(str(percent_done))\n",
      "        pct_string = '%d%%' % percent_done\n",
      "        self.prog_bar = self.prog_bar[0:pct_place] + \\\n",
      "            (pct_string + self.prog_bar[pct_place + len(pct_string):])\n",
      "\n",
      "    def __str__(self):\n",
      "        return str(self.prog_bar)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "p = ProgressBar(1000)\n",
      "for i in range(1001):\n",
      "    p.animate(i)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": []
    }
   ],
   "metadata": {}
  }
 ]
}