Tutuorial 0b: Introduction to JupyterLab

(c) 2018 Justin Bois. With the exception of pasted graphics, where the source is noted, this work is licensed under a Creative Commons Attribution License CC-BY 4.0. All code contained herein is licensed under an MIT license.

This document was prepared at Caltech with financial support from the Donna and Benjamin M. Rosen Bioengineering Center.

This tutorial was generated from a Jupyter notebook. You can download the notebook here.

The first thing we'll do, discussed later, is import all the modules we'll need. You should in general do this at the very beginning of each notebook, and in fact each .py file you write.

In [1]:
import itertools

# Our numerical workhorses
import numpy as np
import pandas as pd
import scipy.integrate

# Import Altair for high level plotting
import altair as alt

# Import Bokeh modules for interactive plotting
import bokeh.io
import bokeh.plotting

# Set up Bokeh for inline viewing
bokeh.io.output_notebook()
Loading BokehJS ...

In this tutorial, you will learn the basics on how to use JupyterLab. All of your homework will be submitted as Jupyter notebooks, so this is something you will need to master. It will be useful for you to go over Tutorial 0c to learn how to use $\LaTeX$ in your Jupyter notebooks. You should also look at Tutorial 0d, which gives an example homework problem an what we expect in terms of content and formatting in your homework.

You should, of course, read the official JupyterLab documentation as well.

What is Jupyter?

From the Project Jupyter website:

Project Jupyter is an open source project was born out of the IPython Project in 2014 as it evolved to support interactive data science and scientific computing across all programming languages.

So, Jupyter is an extension of IPython the pushes interactive computing further. It is language agnostic as its name suggests. The name "Jupyter" is a combination of Julia (a new language for scientific computing), Python (which you know and love), and R (the dominant tool for statistical computation). However, you can run over 40 different languages in a JupyterLab, not just Julia, Python, and R.

Central to Jupyter/JupyterLab are Jupyter notebooks. In fact, the document you are reading right now was generated from a Jupyter notebook. We will use Jupyter notebooks extensively in the course, along with .py files and the console.

Why Jupyter notebooks?

When writing code you will reuse, you should develop fully tested modules using .py files. You can always import those modules when you are using a Jupyter notebook (more on modules and importing them later in the bootcamp). So, a Jupyter notebook is not good for an application where you are building reusable code or scripts. However, Jupyter notebooks are very useful in the following applications.

  1. Exploring data/analysis. Jupyter notebooks are great for trying things out with code, or exploring a data set. This is an important part of the research process. The layout of Jupyter notebooks is great for organizing thoughts as you synthesize them.
  2. Developing image processing pipelines. This is really just a special case of (1), but it worth mentioning separately because Jupyter notebooks are especially useful when figuring out what steps are best for extracting useful data from images, which happens all-too-often in biology. Using the Jupyter notebook, you can write down what you hope to accomplish in each step of processing and then graphically show the results as images as you go through the analysis.
  3. Sharing your thinking in your analysis. Because you can combine nicely formatted text and executable code, Jupyter notebooks are great for sharing how you go about doing your calculations with collaborators and with readers of your publications. Famously, LIGO used a Jupyter notebook to explain the signal processing involved in their first discovery of a gravitational wave.
  4. Pedagogy. All of the content in this class, including this lesson, was developed using Jupyter notebooks!

Now that we know what Jupyter notebooks are and what the motivation is for using them, let's start!

Launching a Jupyter notebook

To launch a Jupyter notebook, click on the Notebook icon of the JupyterLab launcher. If you want to open an existing notebook, right click on it in the Files tab of the JupyterLab window and open it.

Cells

A Jupyter notebook consists of cells. The two main types of cells you will use are code cells and markdown cells, and we will go into their properties in depth momentarily. First, an overview.

A code cell contains actual code that you want to run. You can specify a cell as a code cell using the pulldown menu in the toolbar of your Jupyter notebook. Otherwise, you can can hit esc and then y (denoted "esc, y") while a cell is selected to specify that it is a code cell. Note that you will have to hit enter after doing this to start editing it.

If you want to execute the code in a code cell, hit "shift + enter." Note that code cells are executed in the order you shift-enter them. That is to say, the ordering of the cells for which you hit "Shift + Enter" is the order in which the code is executed. If you did not explicitly execute a cell early in the document, its results are not known to the Python interpreter. This is a very important point and is often a source of confusion and frustration for students.

Markdown cells contain text. The text is written in markdown, a lightweight markup language. You can read about its syntax here. Note that you can also insert HTML into markdown cells, and this will be rendered properly. As you are typing the contents of these cells, the results appear as text. Hitting "Shift + Enter" renders the text in the formatting you specify.

You can specify a cell as being a markdown cell in the Jupyter toolbar, or by hitting "esc, m" in the cell. Again, you have to hit enter after using the quick keys to bring the cell into edit mode.

In general, when you want to add a new cell, you can click the + icon on the notebook toolbar. The shortcut to insert a cell below is "esc, b" and to insert a cell above is "esc, a." Alternatively, you can execute a cell and automatically add a new one below it by hitting "alt + enter."

Code cells

Below is an example of a code cell printing hello, world. Notice that the output of the print statement appears in the same cell, though separate from the code block.

In [2]:
# Say hello to the world.
print('hello, world.')
hello, world.

If you evaluate a Python expression that returns a value, that value is displayed as output of the code cell. This only happens, however, for the last line of the code cell.

In [3]:
# Would show 9 if this were the last line, but it is not, so shows nothing
4 + 5

# I hope we see 11.
5 + 6
Out[3]:
11

Note, however, if the last line does not return a value, such as if we assigned a variable, there is no visible output from the code cell.

In [4]:
# Variable assignment, so no visible output.
a = 5 + 6
In [5]:
# However, now if we ask for a, its value will be displayed
a
Out[5]:
11

Display of graphics

We will be using Altair and Bokeh almost exclusively during the course. To make sure the Bokeh plots get shown in the notebook, you should execute

bokeh.io.output_notebook()

in your notebook. In this notebook, it is executed in the first code cell. Altair plots are natively rendered in notebooks using JupyterLab (but not using classic Jupyter notebooks; see here). You will see an example of rendering a plot in a Jupyter notebook using Altair below. For now, let's generate a plot of a pretty curve using Bokeh.

In [6]:
# Generate data to plot
x = np.linspace(0, 2 * np.pi, 200)
y = np.exp(np.sin(np.sin(x)))

# Make plot
p = bokeh.plotting.figure(plot_height=200,
                          plot_width=400,
                          x_axis_label='x',
                          y_axis_label='y')
p.line(x, y, line_width=2)

# Show the plot
bokeh.io.show(p)

We have a nice, interactive plot of a graceful curve!

We will talk a lot more about display of graphics in our lessons on plotting and exploratory data analysis.

Proper formatting of cells

Generally, it is a good idea to keep cells simple. You can define one function, or maybe two or three closely related functions, in a single cell, and that's about it. When you define a function, you should make sure it is properly commented with descriptive doc strings. Below is an example of how I might generate a plot of the Lorenz attractor (which I choose just because it is fun) with code cells and markdown cells with discussion of what I am doing. (The doc string in this function is nice, but longer than that is necessary for submitted homework in class. At least something akin to the first line of the doc string must appear in function definitions in your submitted notebooks.)

Between cells, you should explain with text what you are doing. Let's look at an example for plotting a Lorenz attractor.

We will use scipy.integrate.odeint() to numerically integrate the Lorenz attractor. We therefore first define a function that returns the right hand side of the system of ODEs that define the Lorentz attractor.

In [7]:
def lorenz_attractor(r, t, p):
    """
    Compute the right hand side of system of ODEs for Lorenz attractor.
    
    Parameters
    ----------
    r : array_like, shape (3,)
        (x, y, z) position of trajectory.
    t : dummy_argument
        Dummy argument, necessary to pass function into 
        scipy.integrate.odeint
    p : array_like, shape (3,)
        Parameters (s, k, b) for the attractor.
        
    Returns
    -------
    output : ndarray, shape (3,)
        Time derivatives of Lorenz attractor.
        
    Notes
    -----
    .. Returns the right hand side of the system of ODEs describing
       the Lorenz attractor.
        x' = s * (y - x)
        y' = x * (k - z) - y
        z' = x * y - b * z
    """
    # Unpack variables and parameters
    x, y, z = r
    s, p, b = p
    
    return np.array([s * (y - x), 
                     x * (p - z) - y, 
                     x * y - b * z])

With this function in hand, we just have to pick our initial conditions and time points and run the numerical integration.

In [8]:
# Parameters to use
p = np.array([10.0, 28.0, 8.0 / 3.0])

# Initial condition
r0 = np.array([0.1, 0.0, 0.0])

# Time points to sample
t = np.linspace(0.0, 30.0, 4000)

# Use scipy.integrate.odeint to integrate Lorentz attractor
r = scipy.integrate.odeint(lorenz_attractor, r0, t, args=(p,))

# Unpack results into x, y, z.
x, y, z = r.transpose()

Now, we'll construct a plot of the trajectory using Altair. We will cover the mechanics of how this is done in the first weeks of the course.

In [9]:
# Make a DataFrame of data
df = pd.DataFrame(dict(t=t, x=x, y=y, z=z))

charts = [
    alt.Chart(df,
            height=200,
            width=250
        ).mark_line(
            strokeWidth=1
        ).encode(
            x=x_col,
            y=y_col,
            order='t'
        )
    for x_col, y_col in itertools.combinations(('x', 'y', 'z'), 2)]

alt.vconcat(*charts)
Out[9]:

And we have three nice plots with projections onto the x-y, x-z, and y-z planes.

Best practices for code cells

Here is a summary of some general rules for composing and formatting your code cells.

  1. Keep the width of code in cells below 80 characters.
  2. Keep your code cells short. If you find yourself having one massive code cell, break it up.
  3. Always properly comment your code. Provide complete doc strings for any functions you define.
  4. Do all of your imports in the first code cell at the top of the notebook. With the exception of "from ... import ..." imports, import one module per line.
  5. For submitting assignments, always display your graphics in the notebook.

Markdown cells

Markdown cells contain text. The text is written in markdown, a lightweight markup language. The list of syntactical constructions at this link are pretty much all you need to know for standard markdown. Note that you can also insert HTML into markdown cells, and this will be rendered properly. As you are typing the contents of these cells, the results appear as text. Hitting "shift + enter" renders the text in the formatting you specify.

You can specify a cell as being a markdown cell in the Jupyter tool bar, or by hitting "esc, m" in the cell. Again, you have to hit enter after using the quick keys to bring the cell into edit mode.

In addition to HTML, some $\LaTeX$ expressions may be inserted into markdown cells. $\LaTeX$ (pronounced "lay-tech") is a document markup language that uses the $\TeX$ typesetting software. It is particularly well-suited for beautiful typesetting of mathematical expressions. In Jupyter notebooks, the $\LaTeX$ mathematical input is rendered using software called MathJax. This is usually run off of a remote server, so if you are not connected to the internet, your equations may not be rendered. You will use $\LaTeX$ extensively in preparation of your assignments. There are plenty of resources on the internet for getting started with $\LaTeX$, but you will only need a tiny subset of its functionality in your assignments, and Tutorial 0c, plus cheat sheets you may find by Google (such as this one) are useful.

Computing environment

You should always conclude (or begin, but I'll use the convention of concluding for this class) your notebooks with some information about the versions of the software you used in the analysis. This helps reproducibility. Using Watermark helps with that.

In [10]:
%load_ext watermark
In [11]:
%watermark -v -p numpy,scipy,pandas,bokeh,altair,jupyterlab
CPython 3.7.0
IPython 6.5.0

numpy 1.15.1
scipy 1.1.0
pandas 0.23.4
bokeh 0.13.0
altair 2.2.2
jupyterlab 0.34.9