Edit this page on our live server and create a PR by running command !create-pr in the console panel

Using multiple kernels in one Jupyter notebook

  • Difficulty level: easy
  • Time need to lean: 10 minutes or less
  • Key points:
    • SoS starts and manages other jupyter kernels as subkernels
    • Each codecell belongs to either SoS or one of the subkernels
    • Subkernels can be selected from cell-level language-selection dropdown box, or SoS magics

SoS Notebook is an extension to Jupyter Notebook that allows the use of multiple kernels in one notebook. More importantly, it allows the exchange of data among subkernels so that you can, for example, preprocess data using Bash, analyze the processed data in Python, and plot the results in R. The SoS kernel is extended from the standard Python 3 kernel so you can use any Python statements in SoS. SoS Notebook is also a frontend to the SoS workflow engine but we will leave this topic to Using SoS Workflow Engine in SoS Notebook.

user_interface

Installation

The SoS website has detailed instructions on how to install and run SoS Notebook in its Running SoS section.

User Interfaces

SoS Notebook is based on Jupyter and consists of the sos kernel and frontend extensions to both the classic Jupyter and Jupyter Lab. More specifically, it adds a language selection dropdown box to each code cell and a console panel to classic Jupyter. The language selection dropdown boxes are used to display and switch kernels of each code cell, and the console panel is used to execute scratch cells and display various other information generated by SoS notebook.

The following is a screenshot of a sample SoS notebook. As you can see, the three code cells are in SoS, R and JavaScript respectively,

user_interface

The JupyterLab interface is similar but it uses the existing console windows of JupyterLab, which does not open automatically. To get a layout similar to what is shown below, you will need to manually open a console window (right click -> Open Console for Notebook), and move it to the side if you prefer.

user_interface

The SoS Notebook interface provides a number of ways to improve interactive data analysis under a Jupyter environment. For example, it allows the execution of current line (or selected text) from the current cell in the console panel so that you can step through the source code before executing the cell in its entirety. SoS also allows the displays of transient information, e.g. preview of variables in the console panel so that they do not mix with the main output. These features will be described in details in other tutorials.

Switch between kernels

The SoS kernel serves as the master kernel to other Jupyter kernels. These kernels are called subkernel and can be any Jupyter supported kernels that have been installed for Jupyter.

You can set the language of the cell to any kernel using the language drop down box to the top right corner of a code cell. For example, the following cell uses language R (kernel irkernel).

In [1]:
No description has been provided for this image

If you prefer setting the kernel explicitly in a cell, you can use magic %use. This magic starts the specified kernel and use it for the present cell.

In [2]:
32

When you create new code cell, it inherits the kernel from the code cell immediately before it. For example, the following cell uses kernel R when I insert a new code cell using the + icon on the toolbar.

In [3]:
  1. -2.17374047235647
  2. 0.822712271334

To switch back to the SoS kernel, you can use the dropdown box, or magic %use SoS.

In [4]:

Working with subkernels

SoS can interact with any Jupyter kernel through the use of SoS kernels. Basically, SoS can

  • List the kernel in the language dropdown box and use it to execute associated cells
  • Use %expand magic to prepare input before sending to the kernel
  • Use %capture magic to capture the output from the kernel
  • Use %render magic to render output from the kernel

without knowing what the kernel does.

For example, with the variable artist defined in SoS

In [5]:

You can use magic %expand to create a SPARQL query with variable artist, and capture the output to another variable html_table.

In [6]:
Return format: JSON
Display: table
Endpoint set to: http://dbpedia.org/sparql
person name
http://dbpedia.org/resource/Vincent_van_Gogh Vincent van Gogh
http://dbpedia.org/resource/Johanna_van_Gogh-Bonger Johanna van Gogh-Bonger
Total: 2, Shown: 2

Variable html_table now contains the resulting HTML table and you can parse it in Python (SoS) to extract the information.

In [7]:
Out[7]:
[<a href="http://dbpedia.org/resource/Vincent_van_Gogh" target="_other">http://dbpedia.org/resource/Vincent_van_Gogh</a>,
 <a href="http://dbpedia.org/resource/Johanna_van_Gogh-Bonger" target="_other">http://dbpedia.org/resource/Johanna_van_Gogh-Bonger</a>]

The %render magic also captures the output from subkernels. However, instead of saving the output to a SoS variable (and process later), this magic renders the output in specified format (defult to Markdown).

For example, the usual output of the following R script would be

In [8]:
5 random numbers
* 0.611514953744196
* -0.854535016318753
* 1.48766450043063
* -0.42451630385367
* 0.502684364155923

and you can use the %render magic to treat the text output as Markdown and be rendered in HTML

In [9]:

5 random numbers

  • -0.401287570710614
  • -1.57496175496738
  • -1.75766877068975
  • 0.970604999334162
  • -1.0811157602911

Variable exchange among subkernels

For an increasing number of kernels, SoS provides language modules to facilitate more powerful ways to work with them. The most important of which are magics to exchange variables between live kernels. Several magics can be used but the easiest and most widely used one is %get, which gets specified variables from one kernel to the present kernel.

For example, the R kernel has a mtcars dataframe and we would like to have a look at the data in Python. Then, in a SoS kernel, you can use the following magic to get the variable from R.

In [10]:
Out[10]:
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6.0 160.0 110.0 3.90 2.620 16.46 0.0 1.0 4.0 4.0
Mazda RX4 Wag 21.0 6.0 160.0 110.0 3.90 2.875 17.02 0.0 1.0 4.0 4.0
Datsun 710 22.8 4.0 108.0 93.0 3.85 2.320 18.61 1.0 1.0 4.0 1.0
Hornet 4 Drive 21.4 6.0 258.0 110.0 3.08 3.215 19.44 1.0 0.0 3.0 1.0
Hornet Sportabout 18.7 8.0 360.0 175.0 3.15 3.440 17.02 0.0 0.0 3.0 2.0
Valiant 18.1 6.0 225.0 105.0 2.76 3.460 20.22 1.0 0.0 3.0 1.0
Duster 360 14.3 8.0 360.0 245.0 3.21 3.570 15.84 0.0 0.0 3.0 4.0
Merc 240D 24.4 4.0 146.7 62.0 3.69 3.190 20.00 1.0 0.0 4.0 2.0
Merc 230 22.8 4.0 140.8 95.0 3.92 3.150 22.90 1.0 0.0 4.0 2.0
Merc 280 19.2 6.0 167.6 123.0 3.92 3.440 18.30 1.0 0.0 4.0 4.0
Merc 280C 17.8 6.0 167.6 123.0 3.92 3.440 18.90 1.0 0.0 4.0 4.0
Merc 450SE 16.4 8.0 275.8 180.0 3.07 4.070 17.40 0.0 0.0 3.0 3.0
Merc 450SL 17.3 8.0 275.8 180.0 3.07 3.730 17.60 0.0 0.0 3.0 3.0
Merc 450SLC 15.2 8.0 275.8 180.0 3.07 3.780 18.00 0.0 0.0 3.0 3.0
Cadillac Fleetwood 10.4 8.0 472.0 205.0 2.93 5.250 17.98 0.0 0.0 3.0 4.0
Lincoln Continental 10.4 8.0 460.0 215.0 3.00 5.424 17.82 0.0 0.0 3.0 4.0
Chrysler Imperial 14.7 8.0 440.0 230.0 3.23 5.345 17.42 0.0 0.0 3.0 4.0
Fiat 128 32.4 4.0 78.7 66.0 4.08 2.200 19.47 1.0 1.0 4.0 1.0
Honda Civic 30.4 4.0 75.7 52.0 4.93 1.615 18.52 1.0 1.0 4.0 2.0
Toyota Corolla 33.9 4.0 71.1 65.0 4.22 1.835 19.90 1.0 1.0 4.0 1.0
Toyota Corona 21.5 4.0 120.1 97.0 3.70 2.465 20.01 1.0 0.0 3.0 1.0
Dodge Challenger 15.5 8.0 318.0 150.0 2.76 3.520 16.87 0.0 0.0 3.0 2.0
AMC Javelin 15.2 8.0 304.0 150.0 3.15 3.435 17.30 0.0 0.0 3.0 2.0
Camaro Z28 13.3 8.0 350.0 245.0 3.73 3.840 15.41 0.0 0.0 3.0 4.0
Pontiac Firebird 19.2 8.0 400.0 175.0 3.08 3.845 17.05 0.0 0.0 3.0 2.0
Fiat X1-9 27.3 4.0 79.0 66.0 4.08 1.935 18.90 1.0 1.0 4.0 1.0
Porsche 914-2 26.0 4.0 120.3 91.0 4.43 2.140 16.70 0.0 1.0 5.0 2.0
Lotus Europa 30.4 4.0 95.1 113.0 3.77 1.513 16.90 1.0 1.0 5.0 2.0
Ford Pantera L 15.8 8.0 351.0 264.0 4.22 3.170 14.50 0.0 1.0 5.0 4.0
Ferrari Dino 19.7 6.0 145.0 175.0 3.62 2.770 15.50 0.0 1.0 5.0 6.0
Maserati Bora 15.0 8.0 301.0 335.0 3.54 3.570 14.60 0.0 1.0 5.0 8.0
Volvo 142E 21.4 4.0 121.0 109.0 4.11 2.780 18.60 1.0 1.0 4.0 2.0

Note that transfer is not a correct word for what has just happened because SoS creates an independent variable with the same name, almost the same content in a similar type in the destimation kernel. What this means is that

  1. The original variable is untouched.
  2. A new variable in the destination kernel is created. It will have the same name as the original variable unless the original name is not allowed in the destination kernel (e.g. a R variable my.var will be transferred as my_var in Python).
  3. The new variable will be in a similar type, in this case Python pandas.DataFrame for a R data.frame. This type will vary from language to language.
  4. There is no gurantee of lossless data transfer because not all information could be converted between two data types in two langauges. For example, as of writing Julia's data frame type does not row label so row labels will be missing from transferred dataframes.

The %get magic uses option --from to specify the source kernel, which can be ignored if the source kernel is SoS. For example, the %get data magic executed in a R cell would get variable data from the SoS kernel.

In [11]:
In [12]:
  1. 0
  2. 1
  3. 4
  4. 9
  5. 16

A less popular magic is %put, which works identical to %get but goes another direction. That is to say,

In [13]:
In [14]:
Out[14]:
array([ 1,  2,  5, 10, 17])

Another magic that can be used to exchange variables between subkernels is %with. This magic accepts options --in (-i) and --out (-o) to pass specified input variables to the kernel, and return specified output variables from the kernel after the completion of the evaluation.

For example, if you have

In [15]:

you can pass the input and output variables to magic %with

In [16]:

and obtain the result in the SoS kernel

In [17]:
Out[17]:
[0.291055252881525, -0.333775589436228, -1.45014194132963]