Introduction

Jupyter is one of the most useful things I’ve come across for working with Python for science/engineering purposes. The support for rich output and rapid iteration of code lets me tweak algorithms and simulations and view the results in real time, providing an alternative to tools such as MATLAB but without the price or problems that come with being locked into a proprietary system.

My one problem with Jupyter notebooks is that they’re not as portable or extensible as plain text files. If I come up with an idea to modify my code but I’m not near a computer with Jupyter set up, it’s not easy to make the change quickly. If my notebook was stored in plain text, I could use any computer with a text editor (pretty much any computer ever) and make the change in minutes. Plain text is also a format that will never become obsolete, if Jupyter changes their format or becomes unmaintained 10 years from now and I need to revisit an old simulation, I’ll have to figure out how to convert it to a format that I can use with the tools available to me. Additionally, plain text allows me the freedom to export my documents into any file format I want, even customized formats to fit my specific needs.

Enter org-mode and Babel. org-mode is one of the most powerful software tools I’ve seen and covers everything from “keeping notes, maintaining TODO lists, planning projects, and authoring documents,” and Babel extends it to offer literate programming in a style similar to Jupyter notebooks.

Using the emacs-jupyter package it’s possible to combine the best features of org-mode, Babel, and Jupyter notebooks all into one system.

Prerequisites

Before following this guide I’d recommend that you’re fairly comfortable with, or at least not terrified by:

  • The command line, whether it be cmd.exe on Windows or bash on a proper operating system.
  • Some type of experience with programming languages, or just the ability to edit config files.
  • Git
  • Emacs experience helps, but shouldn’t be strictly necessary for this, since I’m starting from basically zero with Emacs and managed to figure it out without too much pain.

Note: I’m writing this on a computer running macOS 10.14.5, so the following procedure may be different depending on your operating system. You should be able to follow along pretty easily if you’re running GNU/Linux, but if you’re on Windows you’ll most likely have to modify my instructions for your system.

Setup

Install Emacs

First off, you’ll need to have Emacs installed on your system. Go to https://www.gnu.org/s/emacs/ and follow the instructions provided there.

Install Spacemacs

Spacemacs is a pre-configured setup that makes using Emacs quite a bit simpler for someone either starting from scratch or coming from Vim.

~ git clone https://github.com/syl20bnr/spacemacs ~/.emacs.d

Since the master branch of Spacemacs is currently way out of date, switch over to the develop branch to get the latest version. It should be relatively stable, at least it has been for me so far. If version .300 of Spacemacs has been release since this article was written, ignore this step and stick with the master branch.

~ cd ~/.emacs.d
~ git checkout develop

Configure Spacemacs

After installing Spacemacs, start up Emacs. You’ll be prompted with some basic setup questions, I just kept with the defaults and so far haven’t had to change anything. Spacemacs will then download and install the default packages, this may take a couple minutes depending on your Internet, so sit tight.

Next, set up the org-mode layer in Spacemacs. Press SPC f e d (the space bar followed the f, e, and d keys) and find the lines in the file shown below.

dotspacemacs-configuration-layers
'(
  ;; ----------------------------------------------------------------
  ;; Example of useful layers you may want to use right away.
  ;; Uncomment some layer names and press <SPC f e R> (Vim style) or
  ;; <M-m f e R> (Emacs style) to install them.
  ;; ----------------------------------------------------------------
  helm
  ;; auto-completion
  ;; better-defaults
  emacs-lisp
  ;; git
  ;; markdown
  ;; org
  ;; (shell :variables
  ;;        shell-default-height 30
  ;;        shell-default-position 'bottom)
  ;; spell-checking
  ;; syntax-checking
  ;; version-control
)

Uncomment the line with org by removing the double semicolon and add another line with the text python. The section should now look like this:

;; List of configuration layers to load.
dotspacemacs-configuration-layers
'(
  ;; ----------------------------------------------------------------
  ;; Example of useful layers you may want to use right away.
  ;; Uncomment some layer names and press `SPC f e R' (Vim style) or
  ;; `M-m f e R' (Emacs style) to install them.
  ;; ----------------------------------------------------------------
  ;; auto-completion
  ;; better-defaults
  emacs-lisp
  ;; git
  helm
  ;; markdown
  org
  ;; (shell :variables
  ;;        shell-default-height 30
  ;;        shell-default-position 'bottom)
  ;; spell-checking
  ;; syntax-checking
  ;; version-control
  python
  )

This enables the org-mode and Python layers in Spacemacs.

Now, in the same file, find the section below:

;; List of additional packages that will be installed without being
;; wrapped in a layer. If you need some configuration for these
;; packages, then consider creating a layer. You can also put the
;; configuration in `dotspacemacs/user-config'.
;; To use a local version of a package, use the `:location' property:
;; '(your-package :location "~/path/to/your-package/")
;; Also include the dependencies as they will not be resolved automatically.
dotspacemacs-additional-packages '()

and add jupyter to the dotspacemacs-additional-packages '() line so it looks like the text below:

;; List of additional packages that will be installed without being
;; wrapped in a layer. If you need some configuration for these
;; packages, then consider creating a layer. You can also put the
;; configuration in `dotspacemacs/user-config'.
;; To use a local version of a package, use the `:location' property:
;; '(your-package :location "~/path/to/your-package/")
;; Also include the dependencies as they will not be resolved automatically.
dotspacemacs-additional-packages '(jupyter)

This tells Spacemacs that we’ll be using the jupyter package for Emacs.

Now find the user-config section and modify it to look like this:

(defun dotspacemacs/user-config ()
  "Configuration for user code:
This function is called at the very end of Spacemacs startup, after layer
configuration.
Put your configuration code here, except for variables that should be set
before packages are loaded."
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((emacs-lisp . t)
     (python . t)
     (jupyter . t)))
  )

This tells org-babel that we’ll be using emacs-lisp and python in our source blocks.

Now press SPC f e R (the space bar followed the f key, the e key, and Shift + the R key) to reload the configuration file.

At this point, it may be worth it to go over the Spacemacs documentation and follow along with some of the tutorials there to get a handle on how it all works and get comfortable with using it to create and edit org-mode files.

Usage

Now we should be all set to use org-mode like a Jupyter notebook! Open a new .org file in Emacs and enter the following to test it out (make sure you have numpy and matplotlib installed first):

#+begin_src jupyter-python :session notebook :async yes
import numpy as np
import matplotlib.pyplot as plt

plt.figure(facecolor='white')

x = np.array(range(100)) - 50
y = 5*x**2 + 5

plt.plot(x, y)
plt.show()
#+end_src

Now press SPC m b e y and wait for the #+RESULTS: section to show up and press SPC m T i to show the plot inline. You should see an image like this:

Example matplotlib plot.

Final Words

Congratulations! You’ve setup Emacs, org-mode, Babel, and Jupyter to make a plain text alternative to Jupyter Notebooks. Happy Coding!

If you’d like to learn more about Spacemacs, org-mode, Babel, or emacs-jupyter please check out the links below.

Finally, without the hard work of all the people who make all of these amazing tools available for free, it would have been impossible for me to make this post or do any of the work I do, so if you can support any of them in any way (even if it’s by spreading the word), please do!