IPython and The Jupyter notebook#

Jupyter is the name for this notebook interface, and the document format.

../../_images/jupyter-logo.png

Notebooks can contain Markdown like this cell here, as well as mathematics rendered with mathjax:

\[ \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\ldots} } } } \]

nbviewer is a service that renders notebooks to HTML, for sharing and reading notebooks on the Internet.

This notebook on nbviewer.

You can also convert notebooks to HTML and other formats locally with jupyter nbconvert.

IPython: beyond plain Python#

When executing code in IPython, all valid Python syntax works as-is, but IPython provides a number of features designed to make the interactive experience more fluid and efficient.

First things first: running code, getting help#

In the notebook, to run a cell of code, hit Shift-Enter. This executes the cell and puts the cursor in the next cell below, or makes a new one if you are at the end. Alternately, you can use:

  • Alt-Enter (or option-Enter) to force the creation of a new cell unconditionally (useful when inserting new content in the middle of an existing notebook).

  • Control-Enter executes the cell and keeps the cursor in the same cell, useful for quick experimentation of snippets that you don’t need to keep permanently.

print("Hi")
Hi
import time

for i in range(5):
    print(i, end=" ")
    time.sleep(1)
0 1 2 3 4 
i
4

Getting help:

Typing object_name? will print all sorts of details about any object, including docstrings, function definition lines (for call arguments) and constructor details for classes.

import numpy as np

np.asarray?
Docstring:
asarray(a, dtype=None, order=None, *, like=None)

Convert the input to an array.

Parameters
----------
a : array_like
    Input data, in any form that can be converted to an array.  This
    includes lists, lists of tuples, tuples, tuples of tuples, tuples
    of lists and ndarrays.
dtype : data-type, optional
    By default, the data-type is inferred from the input data.
order : {'C', 'F', 'A', 'K'}, optional
    Memory layout.  'A' and 'K' depend on the order of input array a.
    'C' row-major (C-style),
    'F' column-major (Fortran-style) memory representation.
    'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise
    'K' (keep) preserve input order
    Defaults to 'C'.
like : array_like
    Reference object to allow the creation of arrays which are not
    NumPy arrays. If an array-like passed in as ``like`` supports
    the ``__array_function__`` protocol, the result will be defined
    by it. In this case, it ensures the creation of an array object
    compatible with that passed in via this argument.

    .. versionadded:: 1.20.0

Returns
-------
out : ndarray
    Array interpretation of `a`.  No copy is performed if the input
    is already an ndarray with matching dtype and order.  If `a` is a
    subclass of ndarray, a base class ndarray is returned.

See Also
--------
asanyarray : Similar function which passes through subclasses.
ascontiguousarray : Convert input to a contiguous array.
asfarray : Convert input to a floating point ndarray.
asfortranarray : Convert input to an ndarray with column-major
                 memory order.
asarray_chkfinite : Similar function which checks input for NaNs and Infs.
fromiter : Create an array from an iterator.
fromfunction : Construct an array by executing a function on grid
               positions.

Examples
--------
Convert a list into an array:

>>> a = [1, 2]
>>> np.asarray(a)
array([1, 2])

Existing arrays are not copied:

>>> a = np.array([1, 2])
>>> np.asarray(a) is a
True

If `dtype` is set, array is copied only if dtype does not match:

>>> a = np.array([1, 2], dtype=np.float32)
>>> np.asarray(a, dtype=np.float32) is a
True
>>> np.asarray(a, dtype=np.float64) is a
False

Contrary to `asanyarray`, ndarray subclasses are not passed through:

>>> issubclass(np.recarray, np.ndarray)
True
>>> a = np.array([(1.0, 2), (3.0, 4)], dtype='f4,i4').view(np.recarray)
>>> np.asarray(a) is a
False
>>> np.asanyarray(a) is a
True
Type:      builtin_function_or_method

use two question marks ?? to see the source code:

np.asarray??
Docstring:
asarray(a, dtype=None, order=None, *, like=None)

Convert the input to an array.

Parameters
----------
a : array_like
    Input data, in any form that can be converted to an array.  This
    includes lists, lists of tuples, tuples, tuples of tuples, tuples
    of lists and ndarrays.
dtype : data-type, optional
    By default, the data-type is inferred from the input data.
order : {'C', 'F', 'A', 'K'}, optional
    Memory layout.  'A' and 'K' depend on the order of input array a.
    'C' row-major (C-style),
    'F' column-major (Fortran-style) memory representation.
    'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise
    'K' (keep) preserve input order
    Defaults to 'C'.
like : array_like
    Reference object to allow the creation of arrays which are not
    NumPy arrays. If an array-like passed in as ``like`` supports
    the ``__array_function__`` protocol, the result will be defined
    by it. In this case, it ensures the creation of an array object
    compatible with that passed in via this argument.

    .. versionadded:: 1.20.0

Returns
-------
out : ndarray
    Array interpretation of `a`.  No copy is performed if the input
    is already an ndarray with matching dtype and order.  If `a` is a
    subclass of ndarray, a base class ndarray is returned.

See Also
--------
asanyarray : Similar function which passes through subclasses.
ascontiguousarray : Convert input to a contiguous array.
asfarray : Convert input to a floating point ndarray.
asfortranarray : Convert input to an ndarray with column-major
                 memory order.
asarray_chkfinite : Similar function which checks input for NaNs and Infs.
fromiter : Create an array from an iterator.
fromfunction : Construct an array by executing a function on grid
               positions.

Examples
--------
Convert a list into an array:

>>> a = [1, 2]
>>> np.asarray(a)
array([1, 2])

Existing arrays are not copied:

>>> a = np.array([1, 2])
>>> np.asarray(a) is a
True

If `dtype` is set, array is copied only if dtype does not match:

>>> a = np.array([1, 2], dtype=np.float32)
>>> np.asarray(a, dtype=np.float32) is a
True
>>> np.asarray(a, dtype=np.float64) is a
False

Contrary to `asanyarray`, ndarray subclasses are not passed through:

>>> issubclass(np.recarray, np.ndarray)
True
>>> a = np.array([(1.0, 2), (3.0, 4)], dtype='f4,i4').view(np.recarray)
>>> np.asarray(a) is a
False
>>> np.asanyarray(a) is a
True
Type:      builtin_function_or_method

Tab completion#

Tab completion, especially for attributes, is a convenient way to explore the structure of any object you’re dealing with. Type object_name.<TAB> to view the object’s attributes. Besides Python objects and keywords, tab completion also works on file and directory names.

from PIL import Image
Image.

Accessing the underlying operating system#

We can use cat to view the contents of a file:

!cat hw.py
#!/usr/bin/env python3

from math import sin
import sys

x = float(sys.argv[1])
sin_x = sin(x)

print(f"Hello, sin({x:g}) = {sin_x:.3f}")
import os

print(os.getcwd())
/Users/minrk/dev/simula/in3110/site/lectures/02-python
import subprocess

p = subprocess.run(["ls", "-l"], capture_output=True, check=True)
print(p.stdout.decode())
total 1080
-rw-r--r--  1 minrk  staff      21 Sep  2  2020 UiO.txt
-rwxr-xr-x  1 minrk  staff     490 Sep  2  2020 car.py
-rw-r--r--  1 minrk  staff   12814 Aug 22 12:04 exercises.ipynb
drwxr-xr-x  6 minrk  staff     192 Aug 22 12:04 figs
-rwxr-xr-x  1 minrk  staff     139 Sep  1 11:10 hw.py
-rw-r--r--  1 minrk  staff  406877 Sep 22 09:28 ipython.ipynb
-rw-r--r--  1 minrk  staff   22868 Aug 22 12:04 jupyter-logo.png
-rw-r--r--  1 minrk  staff     740 Aug 22 12:04 myNumber_test.py
-rwxr-xr-x  1 minrk  staff     823 Aug 22 12:04 point.py
-rwxr-xr-x  1 minrk  staff     670 Sep  2  2020 point2d.py
-rwxr-xr-x  1 minrk  staff     856 Sep  2  2020 point3d.py
-rwxr-xr-x  1 minrk  staff    1488 Sep  2  2020 pointnd.py
-rw-r--r--  1 minrk  staff   15011 Sep  1 11:10 python_summary-classes.ipynb
-rw-r--r--  1 minrk  staff   49134 Sep  1 11:10 python_summary.ipynb
-rwxr-xr-x  1 minrk  staff     658 Aug 22 12:04 shape.py
!pwd
/Users/minrk/dev/simula/in3110/site/lectures/02-python
!ls -la
total 1080
drwxr-xr-x  18 minrk  staff     576 Sep 22 09:28 .
drwxr-xr-x  22 minrk  staff     704 Sep 13 10:23 ..
drwxr-xr-x  11 minrk  staff     352 Sep 21 12:44 .ipynb_checkpoints
-rw-r--r--   1 minrk  staff      21 Sep  2  2020 UiO.txt
-rwxr-xr-x   1 minrk  staff     490 Sep  2  2020 car.py
-rw-r--r--   1 minrk  staff   12814 Aug 22 12:04 exercises.ipynb
drwxr-xr-x   6 minrk  staff     192 Aug 22 12:04 figs
-rwxr-xr-x   1 minrk  staff     139 Sep  1 11:10 hw.py
-rw-r--r--   1 minrk  staff  406877 Sep 22 09:28 ipython.ipynb
-rw-r--r--   1 minrk  staff   22868 Aug 22 12:04 jupyter-logo.png
-rw-r--r--   1 minrk  staff     740 Aug 22 12:04 myNumber_test.py
-rwxr-xr-x   1 minrk  staff     823 Aug 22 12:04 point.py
-rwxr-xr-x   1 minrk  staff     670 Sep  2  2020 point2d.py
-rwxr-xr-x   1 minrk  staff     856 Sep  2  2020 point3d.py
-rwxr-xr-x   1 minrk  staff    1488 Sep  2  2020 pointnd.py
-rw-r--r--   1 minrk  staff   15011 Sep  1 11:10 python_summary-classes.ipynb
-rw-r--r--   1 minrk  staff   49134 Sep  1 11:10 python_summary.ipynb
-rwxr-xr-x   1 minrk  staff     658 Aug 22 12:04 shape.py
files = !ls
print("My current directory's files:")
print(files)
My current directory's files:
['UiO.txt', 'car.py', 'exercises.ipynb', 'figs', 'hw.py', 'ipython.ipynb', 'jupyter-logo.png', 'myNumber_test.py', 'point.py', 'point2d.py', 'point3d.py', 'pointnd.py', 'python_summary-classes.ipynb', 'python_summary.ipynb', 'shape.py']
for f in files:
    print(f)
UiO.txt
car.py
exercises.ipynb
figs
hw.py
ipython.ipynb
jupyter-logo.png
myNumber_test.py
point.py
point2d.py
point3d.py
pointnd.py
python_summary-classes.ipynb
python_summary.ipynb
shape.py

Beyond Python: magic functions#

The IPython ‘magic’ functions are a set of commands, invoked by prepending one or two % signs to their name, that live in a namespace separate from your normal Python variables and provide a more command-like interface. They take flags with -- and arguments without quotes, parentheses or commas. The motivation behind this system is two-fold:

  • To provide a namespace for controlling IPython itself and exposing other system-oriented functionality.

  • To expose a calling mode that requires minimal verbosity and typing while working interactively. Thus the inspiration taken from the classic Unix shell style for commands.

Line vs cell magics:

%timeit list(range(10000))
2.47 ms ± 15.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
list(range(10))
list(range(100))
2.58 µs ± 23.7 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

Line magics can be used even inside code blocks:

for size in [10, 1000, 100_000, 1_000_000]:
    print(f"size: {size:10}", end=" ")
    %timeit list(range(size))
size:         10 1.07 µs ± 10.2 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
size:       1000 198 µs ± 2.67 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
size:     100000 26.8 ms ± 233 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
size:    1000000 267 ms ± 1.81 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit time.sleep(1) 
1 s ± 731 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit?
Docstring:
Time execution of a Python statement or expression

Usage, in line mode:
  %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
or in cell mode:
  %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
  code
  code...

Time execution of a Python statement or expression using the timeit
module.  This function can be used both as a line and cell magic:

- In line mode you can time a single-line statement (though multiple
  ones can be chained with using semicolons).

- In cell mode, the statement in the first line is used as setup code
  (executed but not timed) and the body of the cell is timed.  The cell
  body has access to any variables created in the setup code.

Options:
-n<N>: execute the given statement <N> times in a loop. If <N> is not
provided, <N> is determined so as to get sufficient accuracy.

-r<R>: number of repeats <R>, each consisting of <N> loops, and take the
best result.
Default: 7

-t: use time.time to measure the time, which is the default on Unix.
This function measures wall time.

-c: use time.clock to measure the time, which is the default on
Windows and measures wall time. On Unix, resource.getrusage is used
instead and returns the CPU user time.

-p<P>: use a precision of <P> digits to display the timing result.
Default: 3

-q: Quiet, do not print result.

-o: return a TimeitResult that can be stored in a variable to inspect
    the result in more details.

.. versionchanged:: 7.3
    User variables are no longer expanded,
    the magic line is always left unmodified.

Examples
--------
::

  In [1]: %timeit pass
  8.26 ns ± 0.12 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

  In [2]: u = None

  In [3]: %timeit u is None
  29.9 ns ± 0.643 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

  In [4]: %timeit -r 4 u == None

  In [5]: import time

  In [6]: %timeit -n1 time.sleep(2)

The times reported by %timeit will be slightly higher than those
reported by the timeit.py script when variables are accessed. This is
due to the fact that %timeit executes the statement in the namespace
of the shell, compared with timeit.py, which uses a single setup
statement to import function or create variables. Generally, the bias
does not matter as long as results from timeit.py are not mixed with
those from %timeit.
File:      ~/conda/lib/python3.10/site-packages/IPython/core/magics/execution.py

We can use a magic to write a file.

%%writefile test.txt
This is a test file!
It can contain anything I want...

And more...
Writing test.txt
!cat test.txt
This is a test file!
It can contain anything I want...

And more...

Let’s see what other magics are currently defined in the system:

%lsmagic
Available line magics:
%alias  %alias_magic  %autoawait  %autocall  %automagic  %autosave  %bookmark  %cat  %cd  %clear  %colors  %conda  %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  %pip  %popd  %pprint  %precision  %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.

Plotting in the notebook#

This magic configures matplotlib to render its figures inline:

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 300)
y = np.sin(x**2)
plt.plot(x, y)
plt.title("A little chirp");
../../_images/6f04f99f0c0d080f62b28dad0a6d7887da4566796915a562b08629675e01e3f7.png