Chemical Engineering Logo

An Introduction to Jupyter Notebooks


Cells & Cell types

Jupyter notebooks are made up of cells. Each cell is an execution scope, which means that it will be executed as a single block of instructions. Cells know about variables defined in previous cells (above them) but not any cells below them.

There are a few different types of cells:

  • Markdown - used for text editing.
  • Code - used for python code. When you execute a cell, it will be rendered (Markdown) or run through Python (Code). In fact, this cell was a Markdown cell and is then rendered using Markdown formatting.

Edit Mode vs. Command Mode

  • In edit mode, keyboard commands will edit the contents of a cell.
    • A cell in edit mode has a green border.
    • To switch to command mode, hit Esc.
  • In command mode, keyboard commands will invoke shortcuts to take actions on a notebook.
    • A cell in command mode has a blue border.
    • To switch to edit mode, hit Enter

Getting Help

When in command mode, you can get a quick list of shortcut commands by typing h or going to Help->Keyboard Shortcuts.

Changing cell type

When in command mode:

  • M converts the cell to Markdown.
  • Y converts the cell to Code.

Executing Cells

  • ⇪↩︎ (shift-enter) will evaluate the current cell and advance to the next cell.
  • ⌃↩︎ (control-enter) will evaluate the current cell and keep focus there.

In a notebook, you can execute cells in any order, but typically you should execute them top-to-bottom. One of the nice things about cells is you can make many quick changes and re-evaluate a cell without needing to re-evaluate the entire notebook.

When in command mode, use the up/down arrows to move to cells above/below.

Some Markdown Tips

You will definitely want to learn a bit about Markdown. Fortunately, there is a link under Help ➟ Markdown that will point you to some helpful resources.

Among some of the things you can do:

  • Create sections (#), subsections (##), subsubsections (###)
  • Create quote blocks for text using a >

    My famous quote

  • Display code (that won't be executed) enclosed in a single tick ` for in-line code fragments or in a section of triple ticks ``` for separate displayed fragments:

    def display_hello(): 
      print('hello there!')
  • Insert LaTeX equations by enclosing them in \$ for inline equations: $\alpha=\frac{\beta}{\gamma}$ and \$\$ for displayed equations: $$\vec{q}=-\lambda\nabla T$$

Note that not all LaTeX functionality is supported, however. More on LaTeX below.

  • Insert images:
    For example, to insert picture.png from the img directory adjacent to your notebook: ![Image](img/picture.png)
  • Insert hyperlinks:
    [displayed link text](


Tables are formed using | to separate columns and --- to indicate header rows. For example,

 Fruit  | Vegetable
Banana  | Pea
Kiwi    | Carrot


Fruit Vegetable
Banana Pea
Kiwi Carrot

You can also alter the cell alignment in a table:

Right-aligned Centered Left-aligned
Use a trailing : for right-aligned. Use leading and trailing : for centered Use leading : for left-aligned
Republican Sane Democrat

If you want to display data from Python in tabular format, you may want to use the pandas library.

You can link to any section heading as follows:

  [link text to display](#heading-text)

For example, here is a link to the executing cells section above.

The heading text is case sensitive, and spaces should be replaced with dashes.

HTML in a notebook

In addition to Markdown, you can use any HTML commands in a notebook (at least in markdown mode).

LaTeX in a notebook

LaTeX is a powerful typesetting language in its own right, but a subset of LaTeX is supported in Jupyter. If you are learning LaTeX, here is a cheat sheet that you may find useful. Built-in to Jupyter notebooks you will find support for inline equations by encapsulating them in single $ and for displayed equations by encapsulating them in double $$

Some Common LaTeX Usage

LaTeX Displayed
\int_{\alpha}^{\beta} f(x) dx $\int_{\alpha}^{\beta} f(x) dx$
\frac{a}{b} $\frac{a}{b}$
\left( \frac{\partial f}{\partial x} \right) $\left( \frac{\partial f}{\partial x}\right)$
\vec{x} $\vec{x}$
\overline{abc} $\overline{abc}$
\int_a^b \underbrace{ \frac{1-x}{e^x}}_\mathrm{integrand} dx $\int_a^b \underbrace{ \frac{1-x}{\exp(x^2)}}_\mathrm{integrand} dx$
\mathsf{abcde} $\mathsf{abcde}$
\mathrm{abcde} $\mathrm{abcde}$
\boldsymbol{\alpha} $\boldsymbol{\alpha}$

LaTeX Macros

LaTeX macros can be used to create shortcuts to simplify frequently used, complex expressions. Put them at the top of your notebook in a markdown cell and they will be available in any later markdown cell. Here are some examples: $\def\del#1#2{\frac{\partial#1}{\partial#2}}$ $\def\d#1#2{\frac{\mathrm{d}#1}{\mathrm{d}#2}}$ $\newcommand{\Ls}{\mathcal{L}_\sigma}$ $\def\D#1#2{\frac{\mathrm{D}#1}{\mathrm{D}#2}}$

Macro definition Example Usage Example Output
$\def\del#1#2{\frac{\partial#1}{\partial#2}}$ $\del{f}{x}$ $\del{f}{x}$
$\def\d#1#2{\frac{\mathrm{d}#1}{\mathrm{d}#2}}$ $\d{f}{x}$ $\d{f}{x}$
$\def\D#1#2{\frac{\mathrm{D}#1}{\mathrm{D}#2}}$ $\D{f}{x}$ $\D{f}{x}$
$\newcommand{\Ls}{\mathcal{L}_\sigma}$ $\Ls$ $\Ls$

LaTeX extensions

If you install the nbextensions package then you get support for a few additional LaTeX features, including:

  • The equation environment for numbered equations:
    a = b + c \label{eq:my special equation}
    To disable numbering, put \nonumber after the equation. That is basically equivalent to putting the equation within double $$:
    $$ a = b + c $$
  • The align environment for aligned (and numbered) equations:
    a &\rightarrow b + c \\
    c + d &\rightarrow e \\
    This produces equations aligned at the & symbol. These equations are also numbered and can be labeled.
  • To cross-reference an equation, use the \ref{} command and supply the label you created:
    \ref{eq:my special equation}

Debugging a notebook

There are a few techniques to use in debugging a notebook:

  1. Add print() statements in to see what your code is doing.
  2. Use the %who or whos cell magics. This will tell you what variables are currently defined.
  3. Activate the variable inspector plugin from the nbextensions package. This will give you a floating window containing a list of variables currently defined. It is very handy!
  4. Sometimes it is helpful to restart the kernel (press the ⟳ button). This will clear all variables defined in the notebook and give you a clean slate.
  5. Add the %%debug cell magic to the beginning of a code cell. This will produce a terminal prompt at the bottom of the cell that allows you to enter python commands (like print, etc.) without needing to rerun the whole cell.

Python in a Jupyter Notebook

One of the great things about Jupyter is the ability to intersperse documentation (Markdown) with code that runs interactively and generates results.

We'll next consider a few useful things that you will need to know to get started in Python

Defining Functions

In python, a function is defined using the def keyword. For example, we could create a function add

In [1]:
def add( x1, x2 ):
  return x1+x2;

The colon at the end of the first line, which indicates that the body of the function (indented) comes next.

To use this, we can call our add function:

In [2]:
add( 5, 6 )
In [3]:
x = 3.14; y = 10;
z = add( x, y );

Using Python Libraries

Python has a vast number of libraries to simplify many tasks. Among those that you will probably use regularly:

  • matplotlib provides very powerful (but sometimes challenging to use) plotting capabilities. A quick way to get started on a plot is to look at the matplotlib gallery to obtain code to generate a plot like the one you want to create.
  • NumPy provides really powerful array handling capabilities like those in Matlab to allow you to create and manipulate arrays of data. It also has some algorithms that operate on the data. If you are a matlab user, here is a great guide showing you the equivalent numpy/python commands
  • SciPy has a large number of algorithms such as interpolation, quadrature, optimization, ODE solvers, linear algebra tools, etc. There is some duplication between NumPy and SciPy.
  • pandas provides a lot of data analysis tools.
  • SymPy provides support for symbolic mathematics within Python.

The first step in using a library is to tell Python that you want it. This is done using the import command:

In [4]:
# import the numpy library and alias it to np. numpy provides linspace like matlab. 
# It also provides constants like pi and functions like sin, cos, etc.
import numpy as np
x = np.linspace( 0, 2*np.pi )  # create an array spaced from 0 to 2*pi.
y = np.sin(x)
z = y**2


Python has vast plotting capabilities that can be a bit overwhelming. Frequently, we simply want to plot basic 1D functions, which is accomplished through matplotlib's pyplot package:

In [5]:
# note that this cell uses results defined in the cell above (x and z)
import matplotlib.pyplot as plt
plt.plot( x, np.sin(x), 'k', label='SIN' )  # label is what the legend will show.
plt.plot( x, np.cos(x), 'r', label='COS' )
plt.plot( x, np.tan(x), 'g' )               # no label = no legend entry
plt.plot( x, z, label="sin^2" )
plt.title('sin, cos and tan')               # title for the plot
plt.xlabel('x')                             # x-axis label
plt.ylabel('f(x)')                          # y-axis label
plt.legend()                                # show the legend
plt.grid()                                  # show the grid on the plot
plt.ylim(-1,1)                              # set the y-axis range                                  # render the plot
<Figure size 640x480 with 1 Axes>

There are many options on plotting in Python. The matplotlib gallery or examples are great places to get template code to produce the kind of plot you are looking for.

Getting help on python commands

You can get help on a Python command by typing it in a command cell and following it by ? then evaluating the cell:

In [6]:
import numpy as np

Interactive Notebooks: Widgets

Widgets are a set of simple tools that enable powerful interactivity in a notebook.

There are a few building blocks necessary:

  1. Create the widget(s). There are numerous widgets available including sliders, text boxes, drop-downs, radio buttons, etc.
  2. Create a function to call when the widget is modified.
  3. Use the interact function

A Simple Example

In [7]:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams

from ipywidgets import interact
import ipywidgets as widgets

# Create the function that we will call.  It can take multiple arguments if necessary.
def plot_it(f,w):
    t = np.linspace(0,2,500)
    if w=='sin':
        plt.plot( t, np.sin(np.pi*f*t) )
    elif w=='cos':
        plt.plot( t, np.cos(np.pi*f*t) )
    elif w=='tan':
        plt.plot( t, np.tan(np.pi*f*t) )

# create our widgets.
fwidget = widgets.IntSlider(min=0,
which = widgets.Dropdown(options=['sin','cos','tan'],

# hook up the widget with the function
interact( plot_it, f=fwidget, w=which )
<function __main__.plot_it(f, w)>

There are many other things that you can do with widgets. See the documentation for more information.

Magics in Jupyter Notebooks

There are a few useful tricks that can be used within a Jupyter notebook but that ordinary Python doesn't understand. Let's go through a few.


%lsmagic in a command cell will display the avilable line and cell magics:

In [8]:
Available line magics:
%alias  %alias_magic  %autocall  %automagic  %autosave  %bookmark  %cat  %cd  %clear  %colors  %config  %connect_info  %cp  %debug  %dhist  %dirs  %doctest_mode  %ed  %edit  %env  %gui  %hist  %history  %killbgscripts  %ldir  %less  %lf  %lk  %ll  %load  %load_ext  %loadpy  %logoff  %logon  %logstart  %logstate  %logstop  %ls  %lsmagic  %lx  %macro  %magic  %man  %matplotlib  %mkdir  %more  %mv  %notebook  %page  %pastebin  %pdb  %pdef  %pdoc  %pfile  %pinfo  %pinfo2  %popd  %pprint  %precision  %profile  %prun  %psearch  %psource  %pushd  %pwd  %pycat  %pylab  %qtconsole  %quickref  %recall  %rehashx  %reload_ext  %rep  %rerun  %reset  %reset_selective  %rm  %rmdir  %run  %save  %sc  %set_env  %store  %sx  %system  %tb  %time  %timeit  %unalias  %unload_ext  %who  %who_ls  %whos  %xdel  %xmode

Available cell magics:
%%!  %%HTML  %%SVG  %%bash  %%capture  %%debug  %%file  %%html  %%javascript  %%js  %%latex  %%markdown  %%perl  %%prun  %%pypy  %%python  %%python2  %%python3  %%ruby  %%script  %%sh  %%svg  %%sx  %%system  %%time  %%timeit  %%writefile

Automagic is ON, % prefix IS NOT needed for line magics.

A line magic has a single % prefix and applies to the given line of code only. A cell magic has a double %% prefix and applies to the whole cell below where it is found.


The timeit magic is very useful when you want to time a section of code. For example:

In [9]:
import numpy as np
A = np.random.rand(50,50) # a large matrix
%timeit np.linalg.det(A)  # calculate the determinant
28.8 µs ± 2.07 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

As you can see from the output, timeit runs the cell/line several times to get a decent average time, and also reports the variability in the runtime.

who and whos

The who and whos magics provide information about the variables defined in the notebook similar to their Matlab counterparts:

In [10]:
Variable   Type                Data/Info
A          ndarray             50x50: 2500 elems, type `float64`, 20000 bytes
add        function            <function add at 0x108778c80>
fwidget    IntSlider           IntSlider(value=1, descri<...>tion='Frequency:', max=8)
interact   _InteractFactory    <ipywidgets.widgets.inter<...>ry object at 0x108771128>
np         module              <module 'numpy' from '/an<...>kages/numpy/'>
plot_it    function            <function plot_it at 0x116403ae8>
plt        module              <module 'matplotlib.pyplo<...>es/matplotlib/'>
rcParams   RcParams            _internal.classic_mode: F<...>: 0.6\nytick.right: False
which      Dropdown            Dropdown(description='Fun<...>os', 'tan'), value='sin')
widgets    module              <module 'ipywidgets' from<...>/ipywidgets/'>
x          ndarray             50: 50 elems, type `float64`, 400 bytes
y          ndarray             50: 50 elems, type `float64`, 400 bytes
z          ndarray             50: 50 elems, type `float64`, 400 bytes