Tutorials‎ > ‎

Combining Vim and IPython

There are many things to be said about the pros and cons of Matlab, but there is one thing I really love about it and that is the workflow. As a researcher working with large datasets (EEG data), one needs a computer as a tool to manipulate and visualize the data, often beyond the capabilities of a GUI. In a typical session, you have the command line on one side and an editor on the other. The command line is the lab bench where I fire commands to manipulate the data. If more than one line of code is necessary to do what I want, or it is something I'm likely to do again, I write it down in the editor, where piece by piece a script is forming. Being able to run arbitrary parts of the script, and not the entire thing from top to bottom, is crucial. Most of the time, the first thing in the script is to load a large datafile, something I do not wish to repeat every time I make a change to the script. Nor do I want to create hundreds of little scripts, each performing a little piece of a larger analysis. While I can select lines by mouse and run them, Matlab introduced a more convenient way in the form of cells. I can separate 'steps' in the script by %% marks, delimiting so called cells. Now I can execute each cell individually. I would have a 'loading EEG data' cell, a 'bandpass filter' cell, etc.

Though I love the Matlab editor, I'm even more in love with Vim. And although Matlab is a powerful beast, I like Python better. IPython offers a notebook environment that offers cell mode and much more. It is a great tool to share scripts with others. However, since it runs in a browser it is prone to being slow and the editor is clumsy at best. Recently I was able to recreate the workflow described above using Vim and IPython by enhancing the vim-ipython plugin written by Paul Ivanov. You can download my version at http://github.com/wmvanvliet/vim-ipython.git.

Installing the plugin

My recommended way of installing the plugin is to use Pathogen, which has installation instructions on their Github repository, and clone the repository in the bundles directory. If that sounds like gibberish, the easiest way to install the plugin is to download the ipy.vim script directly and place it in a directory '$VIMHOME/ftplugin/python', where the value of $VIMHOME depends on your OS:

Linux and UNIX derivatives: /home/username/.vim
OSX: /Users/username/.vim
Windows XP: C:\Documents and Settings\username\vimfiles
Windows 7+: C:\Users\username\vimfiles

Replace 'username' with your actual username and make sure your Vim is compiled with Python support.

How it works

Recently, IPython has been redesigned to spawn a kernel process, which runs the Python interpreter, and connect one (or more!) clients to this kernel. We are going to attach Vim as one of the clients. First, start IPython in 'qtconsole' mode:

ipython qtconsole --pylab

Then open Vim and issue the command:


It will find the running IPython kernel and connect to it. Once the connection is up and running, you can open a second window with <leader>s that shows the kernel output (empty for now). Create a script, for example:

## Do something
print 'Hello IPython, working hard or hardly working?'
a = [1,2,3]

## Do something else
print 'Doing something else now...'
plot(a, a)

Moving your cursor to one of the lines and pressing C-s will execute the current line, writing output to the top window if it's open. Making a visual selection and pressing C-s will execute the selected lines. Pressing F5 will execute the entire script. Note that the qtconsole window is attached to the same kernel, so typing 'print a' there should bring up [1,2,3]. Hovering the mouse over the 'a' variable in Vim will bring up a tooltip with [1,2,3] as well. This is all due to the excellent work of Paul Ivanov.

I made an addition of my own. Note that I start the two comments with ##, instead of the usual single #. This marks the beginning of a new cell (anagolous to the %% marks in Matlab). Moving the cursor inside a cell and pressing C-M-s will send the contents of the entire cell to IPython. Now my favorite workflow is restored! I've also included some folding expressions that define by default a fold for each cell. The command 'zM' will collapse all defined folds, so it should yield:

+-- 4 lines # Do something---------
+-- 3 lines # Do something else----

Now each step in my script is a cell, folded by default, and executed by moving the cursor over the fold and pressing C-M-s.