Thebe

Get started

In order to use Thebe, you must take the following steps on a page:

Load the thebe javascript bundle

The Thebe Javascript is most-easily obtained from a CDN. You can load the javascript library from a CDN by including this on a page:

<script src="https://unpkg.com/thebe@latest/lib/index.js"></script>

Alternatively, you can download the bundle and include it along with your site.

Configure Thebe in your page’s HTML

Thebe looks for a specific HTML block for its configuration. This happens when Thebe is “bootstrapped” (i.e., launched).

The configuration block has the following structure:

<script type="text/x-thebe-config">
   {
       a: collection
       of: key
       val: pairs
   }
</script>

See Configure Thebe for information about how and what to configure with Thebe.

Bootstrap Thebe on the page

If the Thebe Javascript bundle is loaded, and the configuration file is present, you may bootstrap (i.e., launch) Thebe by calling the following Javascript function:

thebelab.bootstrap()

This will take one or more of the following actions:

  • Re render the code cells to make them live cells. (the rendering can handle cells that contain a mixture of inputs and ouputs distinguished by prompts)

  • (optional) Request a notebook server from Binder

  • (optional) Request a Jupyter kernel from a notebook server.

Calling the bootstrap function is generally accomplished by connecting it to the “click” event of a button on the page.

Tip

If bootstrap: true is in the Thebe configuration, this will be triggered automatically upon page load.

Configure Thebe

You control Thebe’s behavior with a configuration block that is placed somewhere in a page’s HTML. The block has the following structure:

<script type="text/x-thebe-config">
   {
       a: collection
       of: key
       val: pairs
   }
</script>

For example, the following configuration tells Thebe to use a BinderHub for its sessions, as well as the repository to use with Binder:

<script type="text/x-thebe-config">
{
    requestKernel: true,
    binderOptions: {
        repo: "binder-examples/requirements",
        ref: "master",
    },
}
</script>

When Thebe is launched on a page, this configuration is used to control its behavior.

See the sections below for things that you can control with Thebe configuration.

Configure the kernel that will be launched

To configure the kernel that Thebe requests when it launches, use the following section in the Thebe configuration:

kernelOptions: {
  kernelName: "python3",
},

When Thebe is launched, it will request a kernel of this name for the page. Note that currently there can be only one kernel per page.

Note

You must ensure that the value of kernelName exists in the environment that Thebe tries to launch. Some short-hands for certain languages (like python) may also work.

Configure the working directory of the launched kernel

In addition to choosing the kernel, you may also choose the path where the kernel is launched. This will be relative to the root of the launched Jupyter server (e.g., if using a BinderHub, this will be relative to the root of the repository).

To configure the path of the working directory, use the following configuration:

kernelOptions: {
  kernelName: "python3",
  path: "path/to/directory"
}

Customize CodeMirror

CodeMirror is the tool used to convert your code cells into editable cells. It has a number of configuration options, such as theming and syntax highlighting. You can edit all of these attributes in a cell with the following thebe configuration:

// Additional options to pass to CodeMirror instances
codeMirrorConfig: {},

You can use any of the available CodeMirror configurations. For example, the following configuration changes the CodeMirror theme:

codeMirrorConfig: {
    theme: "abcdef"
}

The below code cell demonstrates this theme:

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.ion()
fig, ax = plt.subplots()
ax.scatter(*np.random.randn(2, 100), c=np.random.randn(100))
ax.set(title="Wow, an interactive plot!")

The above code should be styled according to the CodeMirror abcdef theme.

Mark a code cell as read-only

If you would like a code cell to be runnable by Thebe, but not editable by the user, you may mark it as “read-only” with the following syntax:

<pre data-executable data-readonly>print("I cannot be modified")</pre>

Users will not be able to modify the code once Thebe is activated, though they can still press the “run” button to see the outputs.

To set all cells as read-only by default, use the following thebe configuration:

codeMirrorConfig: {
    readOnly: true
}

This uses codeMirror to mark all cells as read-only. If you are using this setting and would like to manually mark individual cells as editable, you can override the codeMirror configuration for a cell using data-readonly="false". For example:

<pre data-executable data-readonly="false">print("I still can be modified")</pre>
<pre data-executable>print("Due to codeMirrorConfig, I cannot be modified")</pre>

Security Considerations

Thebe allows users to run arbitrary code both in Python and, potentially, in Javascript. This allows interactive figures, and custom outputs to be run in your documentation, which is the benefit that Thebe brings! ✨

Cross Site Scripting

However, this can also lead to Cross-Site Scripting (XSS) attacks, with the most likely case being an Self-XSS attack. This happens when someone executes code that they do not understand, or is malicious.

For example, the %%html and the %%javascript cell-magics in Jupyter can directly insert script tags into your page. They can potentially modify the DOM, make API calls on the users behalf, or run untrusted code.

We recommend that you run Thebe in a static environment (e.g. ReadTheDocs or similar) that has no access to user credentials such as cookies or API keys.

Event hooks in Thebe

When Thebe is launched (with thebelab.bootstrap), it will emit a series of events corresponding to the state of the launch process. You can plug into these events to control the behavior on your page.

To do so, use the status event within Thebe, like so:

   thebelab.on("status", function (evt, data) {
    console.log("Status changed:", data.status, data.message);
});

In the above code, the data object contains a collection of information about Thebe, and data.status will reflect the current state of Thebe. This will cycle between these states:

  • building

  • built

  • launching

  • ready

These events can be used to do things like running code once the Jupyter Kernels is ready, or manipulating the page DOM before launching Thebe to result in certain behavior (e.g. a “loading status” button).

Configuration Reference

Here is an example of all possible configuration options for Thebe. This is what you place in between the <script type="text/x-thebe-config"> HTML tags on your page.


{
  // Whether thebe should automatically trigger the bootstrap upon page load
  // if set to false, the page should contain some additional javascript
  // responsible for triggering the javascript when desired (e.g. connected to a button click).
  bootstrap: false,

  // arbitrary pre-render function called as part of bootstrap
  preRenderHook: false,

  // Whether to request the kernel immediately when thebe is bootstrapped
  // instead of on executing code for the first time
  requestKernel: false,

  // Whether thebe should look for predefined output of cells before execution
  // If this option is enabled and the next div after the cell has the attribute
  // data-output=true (default), then the content of this div is rendered as output
  predefinedOutput: false,

  // The selector for identifying whether an element should be treated as output
  outputSelector: '[data-output]',

  // Options for requesting a notebook server from mybinder.org
  binderOptions: {
    repo: "minrk/ligo-binder",

    // only repo is required, the rest below are defaults:
    ref: "master",
    binderUrl: "https://mybinder.org",
    // select repository source (optional). Supports Github(default), Gitlab, and Git
    repoProvider: "github",
    savedSession: {
      // if enabled, thebe will store and try to re-use
      // connections (with credentials!) to running servers
      enabled: true,
      maxAge: 86400, // the max age in seconds to consider re-using a session
      storagePrefix: "thebe-binder-",
    }
  },

  // Options for requesting a kernel from the notebook server
  kernelOptions: {
    name: "python3",
    kernelName: "python3",
    path: "."
    // notebook server configuration; not needed with binder
    // serverSettings: {
    //      "baseUrl": "http://127.0.0.1:8888",
    //      "token": "test-secret"
    //    }
  },

  // Selector for identifying which elements on the page should
  // be made interactive
  selector: "[data-executable]",

  // Optional prompt handling during the rendering phase
  // Either false or a dictionary as in the example below
  stripPrompts: false,
  // stripPrompts: {
  //      inPrompt: 'sage: ',
  //      continuationPrompt: '....: ',
  //      // only apply the prompt stripping to cells matching this selector (optional)
  //      selector: '.sage-input',
  //    },

  // URL from which to load mathjax
  // set to `false` to disable mathjax
  mathjaxUrl: "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js",

  // mathjax configuration string
  mathjaxConfig: "TeX-AMS_CHTML-full,Safe",

  // Additional options to pass to CodeMirror instances
  codeMirrorConfig: {},
}

Running cells when Thebe starts

Sometimes it is helpful to automatically run some cells when Thebe starts. For example, if you’d like to pre-define some variables or import a function that you’ll use later on. This lets you focus the code that users read on the ideas that you want to convey.

Thebe can be controlled via Javascript after it has been initialized. Below are two ways that you can configure your Javascript to run code under-the-hood.

Running cells when Thebe is initialized

A straightforward way to run code is to simply simulate a click on the buttons that are created when you launch Thebe. By selecting the Thebe button and calling the click() method, the code in that cell will be run (and outputs will show) once the Thebe kernel is ready.

Here’s a code sample that selects all cells with a tag called thebelab-init and simulates a click on the button.

thebelab.events.on("request-kernel")(() => {
    // Find any cells with an initialization tag and ask Thebe to run them when ready
    var thebeInitCells = document.querySelectorAll('.thebelab-init');
    thebeInitCells.forEach((cell) => {
        console.log("Initializing Thebe with cell: " + cell.id);
        const initButton = cell.querySelector('.thebelab-run-button');
        initButton.click();
    });
});

Running custom code with Thebe

In addition, you can run your own custom code from the Thebe object with Javascript using the requestExecute method. Below is a code snippet that uses the same event trigger, but in this case runs some custom code against the kernel once it is ready.

thebelab.events.on("request-kernel")((kernel) => {
    // Find any cells with an initialization tag and ask Thebe to run them when ready
    kernel.requestExecute({code: "import numpy"})
});

In both of the cases above, you’ll likely need to customize the Javascript calls depending on how your code is structured and what behavior you’d like when users land on a page.

Contributing Guide

Thanks for your interest in contributing to thebe, your contributions are welcome and appreciated 🎉. This page contains some information to help you get started.

Note

thebe was recently called thebelab, so you may see mentions of thebelab scattered throughout the repository. Feel free to flag these and suggest we rename them to thebe.

Contributing guide

See the ExecutableBooks developer guidelines for conventions and practices around developing thebe. However, note that some practices, such as creating releases, may be different because thebe is primarily an Javascript (npm) package rather than a Python package.

Repository structure

thebe is primarily written in Javascript, and structured as an NPM package.

  • src/ contains the code and assets that make up thebe. This is what you’ll edit to make changes to the project.

  • examples/ provides a few HTML examples of how thebe can be used. It is mostly for documentation

Set up a development environment

In order to get Thebe running locally, you’ll need to have Node installed on your system.

Minimum requirements are:

  • nodejs v15.0 or greater

  • npm v6.0 or greater

  • yarn v1.22 or greater

You can install it in several ways, the most common being:

conda install -c conda-forge nodejs

Once installed, also install yarn which is what you will run in order to run Thebe locally.

npm install -g yarn

Next, clone the repository and install the required dependencies:

git clone https://github.com/executablebooks/thebe
cd thebe
yarn install

This will install all dependencies needed to run thebe (specified in package.json). By default, yarn install will also have created a production build in lib

If you are using npm v7 you may encounter Peer Dependency Errors see comments below to resolve these.

Note

Using yarn install will ensure that you install the latest tested dependencies, and will not make any unintentional local upgrades. yarn uses npm under the hood, please do not use npm install directly to install dependencies.

Peer Dependency Errors

Due to recent changes in npm as of v7 peer dependency issues are flagged as critical errors. However, many projects have not yet resolved these issues in their code base, this means that a project’s co-dependencies can prevent installation of a package. This is a know issue, to resolve this there are two options:

  1. Downgrade npm to v6

  npm install -g npm@6
  1. Set the legacy-peer-deps option in your local environment

  npm config set legacy-peer-deps true

Build and demo thebe locally

To use your local copy of thebe (e.g., if you make any changes to the src/ folder), you can run a local build and serve a sample web page. To do so, run:

yarn run build:watch

This will build thebe/ locally (including any changes you’ve made to the source code).

You can now demo the latest thebe/ changes by opening the file at development/binder.html. Open this file to see Thebe running.

The content of development/binder.html is a simple HTML page that demonstrates Thebe functionality. You can edit it to test out new features or configurations.

Running the yarn run develop command will start a watch on the source code, building with webpack and will serve it along with development/binder.html. As you change the code in src/, the javascript will automatically be re-built, but you’ll be required to refresh the page.

Using a local kernel

development/binder.html will connect to a public binder instance which can be slow.

For faster development and easy control over the python environment available to Jupyter is run yarn run develop:local instead.

This will serve the file from development/local.html which will attempt to connect to a local Jupyter kernel.

You will need to have Jupyter running with the expected authentication token for this to work. i.e.

jupyter notebook \
  --NotebookApp.token=thebe-test-secret \
  --NotebookApp.allow_origin='http://127.0.0.1:8080'

Committing changes

Thebe uses code autoformatting so you don’t need to worry about style lint, so whenever you are ready to commit changes run yarn run fmt to autoformat the javascript. You can put this script in .git/hooks/pre-commit:

#!/bin/sh
if [[ -f package.json ]]; then
    yarn run fmt
fi

to run auto-formatting prior to each commit.

Testing Thebe

You can test manually, interactively by running yarn run develop to open and serve development.html with the current build of thebe.

Running automated tests

There are two types of automated test environment in place in thebe both using the Jest testing library. These are:

  1. a standard javascript testing setup for unit / component level testing of the thebe library. These can be run using yarn run test or yarn run test:watch and test code is located in the test folder.

  2. e2e style tests using jest + puppeteer that can be run yarn run test:e2e or yarn run test:e2e:watch and test code is located in the e2e folder.

Alternately, you can push your changes to GitHub and let the tests run automatically via GitHub Actions.

TODO: get testing infrastructure to a point where we can reasonably request tests for new features.

Adding unit tests

Unit style tests work by loading the thebe library or part of it in javascript; mocking inputs and/or dependencies, executing a function and asserting on outputs of mocks. A good first example to look at is tests/bootstrap.spec.js. This test:

  • loads thebe js code import * as thebelab from "../src/thebelab";

  • manipulates the dom to prep the test (via built in JSDOM)

  • calls the thebe.bootstrap() function

  • checks for expected behaviour

If you are new to Jest check their getting started, mocking and expect assertion api docs.

Adding e2e Tests

e2e style tests are achieved using Puppeteer a headless chrome api that can be used to load a page complete with thebe scripts, allowing full execution as though it was in an end user browser and then assertion of end state.

Adding new e2e tests involves: (see e2e/readonly.test.js for an example)

  • creating a test html page that load and uses thebe, placing this in the e2e/fixtures/HTML folder

  • load the fixture page at the start of your test

beforeAll(async () => {
  await page.goto(
    `file:${path.join(__dirname, "/fixtures/HTML/readonly1.html")}`,
    { waitUntil: ["load", "domcontentloaded", "networkidle0"] }
  );
});
  • Assert on initial page state

  • Invoke UI actions to trigger behavior

  • assert on final state

Building docs locally

Thebe uses Sphinx and JupyterBook for building documentation. Thebe documentation is located in the /docs directory. You will need the development environment setup, see the above Set up a development environment to learn more. You will also need Python installed, and can install the requirements for the documentation using:

cd docs/
pip install -r doc-requirements.txt

Once you are in the documentation folder:

make html

Finally, run the following to view the built documentation locally:

make show

Releasing Thebe

To release thebe, follow the EBP guidelines to make sure the repo is ready for release.

Once prepared, bump the version with:

  1. Use yarn to update the thebe version in the package.json file and to create a git tag for the version using yarn version --new-version NEW_VERSION, e.g. yarn version --new-version 0.5.1

  2. Push the tag to github: git push --follow-tags

  3. Create a release for the new tag on github at https://github.com/executablebooks/thebe/releases/new; this will trigger a github action that uploads the latest version to unpkg.com/browse/thebe/.

Thebe architecture

Thebe consumes three principal APIs:

  1. jQuery for manipulating elements on the page

  2. JupyterLab for talking to a running Jupyter server to execute code and display outputs

  3. BinderHub for requesting kernels from a BinderHub instance, such as mybinder.org.

Manipulating the page

The first thing Thebe does is find elements on the page that should be made executable. It does this with jQuery, finding (by default) elements that look like <div data-executable="true">..., with a query such as the $("[data-executable]) (this is the default, but can be customized). Once it has found these elements, Cell objects are created (more on Cells in the JupyterLab API), which then replace the elements that were found.

JupyterLab APIs

The main thing Thebe does is execute code and display output. This is done with JupyterLab APIs. A Cell is an element wrapping a code input area and associated OutputArea for displaying the outputs that result from execution.

Main APIs used:

  • OutputArea for rendering outputs on the page

  • Session for starting kernels

  • Kernel for sending/receiving messages to/from a connected kernel

  • WidgetManager for working with interactive widgets

Configuration

Configuration is handled by adding a script tag with type=”text/x-thebe-config”. This should specify a javascript object.

More information in the README (TODO: move it here?)

<script type="text/x-thebe-config">
  {
    binderOptions: {
      repo: "minrk/ligo-binder",
      ref: "master",
    }
  }
</script>

thebe API

The thebe JavaScript API

Note

This document is a work in progress. We need to add jsdoc-style docstrings to our exported functions.

bootstrap(options)

Do it all in one go. 1. load options 2. run hooks 3. render cells 4. request a Kernel 5. hook everything up

Arguments
  • options (Object) – Object containing thebe options. Same structure as x-thebe-options.

Returns

Promise – Promise for connected Kernel object

Thebe turns your static HTML pages into interactive ones, powered by a kernel. It is the evolution of the original Thebe project with javascript APIs provided by JupyterLab.

For example, see the following code cell:

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.ion()
fig, ax = plt.subplots()
ax.scatter(*np.random.randn(2, 100), c=np.random.randn(100))
ax.set(title="Wow, an interactive plot!")

It is static for now. You can activate Thebe by pressing the button below. This will ask mybinder.org for a Python kernel, and turn the code cell into an interactive one with outputs!

Try clicking the button. The cell will be come active!

You can press “run” in order to run the contents of the cell and display the result (be patient, it will take a few moments for Binder to start the kernel).

Getting Started

To get started, check out Get started.

Examples

For more examples showing how to configure, use, and activate Thebe, see the list below. We recommend browsing the raw HTML of each one in order to see how Thebe is used.

A minimal example

This page illustrates a minimal setup to get Thebe running, using mybinder as a kernel (i.e. computation backend) provider. This guide will go step-by-step in loading Thebe and activating it so that your code cells become active.

Loading and configuring Thebe

In order to use Thebe, we must first set its configuration. This must be done before Thebe is loaded from a CDN or a local script.

Here’s a sample configuration for Thebe

<!-- Configure and load Thebe !-->
<script type="text/x-thebe-config">
  {
    requestKernel: true,
    binderOptions: {
      repo: "binder-examples/requirements",
    },
  }
</script>

In this case, requestKernel: true asks Thebe to request a kernel immediately upon being loaded, and binderOptions provides the repository that Binder will use to give us a Kernel.

Next, we’ll load Thebe from a CDN:

<script src="https://unpkg.com/thebe@latest/lib/index.js"></script>

Adding a button to activate Thebe

There are many ways you can activate Thebe. In this case, we’ll add a button to our page, and configure it to bootstrap Thebe once it is clicked. We’ll do this with a little bit of Javascript.

Placing the button and adding the JavaScript to enable Thebe was done with the code below:

<button id="activateButton"  style="width: 150px; height: 75px; font-size: 1.5em;">Activate</button>
<script>
var bootstrapThebe = function() {
    thebelab.bootstrap();
}

document.querySelector("#activateButton").addEventListener('click', bootstrapThebe)
</script>

Adding code cells

Finally, we’ll add code cells that Thebe can activate. By default, Thebe will look for any HTML elements with data-executable="true". We’ll also add a data-language="python" attribute to enable syntax highlighting with CodeMirror.

print("Hello!")

Here’s the code that created the cell above:

<pre data-executable="true" data-language="python">print("Hello!")</pre>

Press the Thebe button above to activate this cell, then press the “Run” button, or “Shift-Enter” to execute this cell.

Note

When Thebe is activated in this example, it must first ask Binder for a kernel. This may take several seconds.

Now let’s try another cell that generates a Matplotlib plot. Because we’ve configured Thebe to use Binder with an environment that has Numpy and Matplotlib, this works as expected. Try modifying the cell contents and re-running!

This is another cell, with plotting. Shift-Enter again!

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10)
plt.plot(x, np.sin(x))
plt.plot(x, np.cos(x))

Here’s the HTML for the cell above:

<pre data-executable="true" data-language="python">
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10)
plt.plot(x, np.sin(x))
plt.plot(x, np.cos(x))
</pre>

And here’s an example where the contents cannot be modified once instantiated:

print("My contents cannot be changed!")

For more examples, check out Examples.

Bqplot Example

Thebe can display output from bqplot Jupyter widgets, a 2D plotting library. This example is repurposed from the bqplot documentation and is licensed under the Apache License 2.0 License. Note that this example does not fix the pan/zoom feature on plots.

Setup

Be sure to load require.min.js and Font Awesome 4 before any of your thebe activation code, it is required for the bqplot widget and navigation icons to work:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" integrity="sha512-5A8nwdMOWrSz20fDsjczgUidUBR8liPYU+WymTZP1lmY9G6Oc7HlZv156XqnsgNUzTyMefFTcsFH/tnJE/+xBg==" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>

Configure thebe and load it:

<script type="text/x-thebe-config">
  {
    requestKernel: true,
    binderOptions: {
      repo: "bqplot/bqplot",
      ref: "0.12.18",
      binderUrl: "https://mybinder.org",
      repoProvider: "github",
    },
  }
</script>
<script src="https://unpkg.com/thebe@latest/lib/index.js"></script>

Create a button to activate thebe:

<button id="activateButton" style="width: 120px; height: 40px; font-size: 1.5em;">
  Activate
</button>
<script>
var bootstrapThebe = function() {
    thebelab.bootstrap();
}
document.querySelector("#activateButton").addEventListener('click', bootstrapThebe)
</script>

Now add code cells between these HTML tags:

<pre data-executable="true" data-language="python"></pre>

Example

Press the “Activate” button below to connect to a Jupyter server:

Here we will display a basic 2D plot:

import numpy as np
from bqplot import pyplot as plt

size = 100
np.random.seed(0)
x_data = np.arange(size)
y_data = np.cumsum(np.random.randn(size)  * 100.0)

plt.figure(title='My First Plot')
plt.plot(x_data, y_data)
plt.show()

Ipyleaflet Example

Thebe can display output from ipyleaflet Jupyter widgets. This example is repurposed from the ipyleaflet documentation and is licensed under the MIT License (MIT).

Setup

Be sure to load require.min.js before any of your thebe activation code, it is required for Jupyter widgets to work:

<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>

Configure thebe and load it:

<script type="text/x-thebe-config">
  {
    requestKernel: true,
    binderOptions: {
      repo: "jupyter-widgets/ipyleaflet",
      ref: "0.13.3",
      binderUrl: "https://mybinder.org",
      repoProvider: "github",
    },
  }
</script>
<script src="https://unpkg.com/thebe@latest/lib/index.js"></script>

Create a button to activate thebe:

<button id="activateButton" style="width: 120px; height: 40px; font-size: 1.5em;">
  Activate
</button>
<script>
var bootstrapThebe = function() {
    thebelab.bootstrap();
}
document.querySelector("#activateButton").addEventListener('click', bootstrapThebe)
</script>

Now add code cells between these HTML tags:

<pre data-executable="true" data-language="python"></pre>

Example

Press the “Activate” button below to connect to a Jupyter server:

Here we will display a basic leaflet map:

from ipyleaflet import Map, Heatmap
from random import uniform
import time

def create_random_data(length):
    "Return a list of some random lat/lon/value triples."
    return [[uniform(-80, 80),
         uniform(-180, 180),
         uniform(0, 1000)] for i in range(length)]

m = Map(center=[0, 0], zoom=2)
m

Now we add a heatmap:

heat = Heatmap(locations=create_random_data(1000), radius=20, blur=10)
m.add_layer(heat)

Finally, we add some animation to our heatmap:

for i in range(100):
    heat.locations = create_random_data(1000)
    time.sleep(0.1)

Ipympl Example

Thebe can display output from ipympl, which enables interactivity with matplotlib.

Setup

Be sure to load require.js and Font Awesome 4 before any of your thebe activation code so that the matplotlib widgets can function.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" integrity="sha512-5A8nwdMOWrSz20fDsjczgUidUBR8liPYU+WymTZP1lmY9G6Oc7HlZv156XqnsgNUzTyMefFTcsFH/tnJE/+xBg==" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>

Configure thebe and load it:

<script type="text/x-thebe-config">
  {
    requestKernel: true,
    binderOptions: {
      repo: "matplotlib/ipympl",
      ref: "0.6.1",
      repoProvider: "github",
    },
  }
</script>
<script src="https://unpkg.com/thebe@latest/lib/index.js"></script>

Create a button to activate thebe:

<button id="activateButton" style="width: 120px; height: 40px; font-size: 1.5em;">
  Activate
</button>
<script>
var bootstrapThebe = function() {
    thebelab.bootstrap();
}
document.querySelector("#activateButton").addEventListener('click', bootstrapThebe)
</script>

Now add between these HTML tags:

<pre data-executable="true" data-language="python">
%matplotlib widget

</pre>

Examples

Using ipympl, you can display a variety of interactive plots.

Press the “Activate” button below to connect to a Jupyter server:

2D plot
%matplotlib widget

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
fig.canvas.layout.width = '7in'
fig.canvas.layout.height= '5in'
ax.plot([1,2,3], [4,5,3])
3D plot
%matplotlib widget

from mpl_toolkits.mplot3d import axes3d

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)
plt.show()
 

Plotly Example

Thebe can display output from plotly.py.

Setup

Be sure to load require.js before any of your thebe activation code so that the Jupyter widgets can function:

<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>

Configure thebe and load it:

<script type="text/x-thebe-config">
  {
    requestKernel: true,
    binderOptions: {
      repo: "plotly/plotly.py",
      ref: "doc-prod",
      binderUrl: "https://mybinder.org",
      repoProvider: "github",
    },
  }
</script>
<script src="https://unpkg.com/thebe@latest/lib/index.js"></script>

Create a button to activate thebe:

<button id="activateButton" style="width: 120px; height: 40px; font-size: 1.5em;">
  Activate
</button>
<script>
var bootstrapThebe = function() {
    thebelab.bootstrap();
}
document.querySelector("#activateButton").addEventListener('click', bootstrapThebe)
</script>

Now add code cells between these HTML tags:

<pre data-executable="true" data-language="python"></pre>

Example

Press the “Activate” button below to connect to a Jupyter server:

Here is a distribution plot example from https://plotly.com/python/distplot/ (MIT License):

import plotly.express as px
df = px.data.tips()
fig = px.histogram(df, x="total_bill", y="tip", color="sex", marginal="rug",
                   hover_data=df.columns)
fig.show()

IPyCytoscape Example

Thebe can display output from ipycytoscape, which could visualize graphs using Cytoscape.js.

Setup

Be sure to load require.js before any of your thebe activation code so that the Cytoscape visualizations can function:

<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>

Configure thebe and load it:

<script type="text/x-thebe-config">
  {
    requestKernel: true,
    binderOptions: {
      repo: "QuantStack/ipycytoscape",
      ref: "1.2.0",
      repoProvider: "github",
    },
  }
</script>
<script src="https://unpkg.com/thebe@latest/lib/index.js"></script>

Create a button to activate thebe:

<button id="activateButton" style="width: 120px; height: 40px; font-size: 1.5em;">
  Activate
</button>
<script>
var bootstrapThebe = function() {
    thebelab.bootstrap();
}
document.querySelector("#activateButton").addEventListener('click', bootstrapThebe)
</script>

Now add code cells between these HTML tags:

<pre data-executable="true" data-language="python"></pre>

Example

Using Cytoscape, you can display a graph with several nodes. This example is from the ipycytoscape repository and is licensed under the BSD 3-Clause License.

.._example: https://github.com/QuantStack/ipycytoscape/blob/master/examples/Text%20on%20node.ipynb

Press the “Activate” button below to connect to a Jupyter server:

import ipycytoscape
data = {
  'nodes': [
      { 'data': { 'id': 'desktop', 'name': 'Cytoscape', 'href': 'http://cytoscape.org' } },
      { 'data': { 'id': 'a', 'name': 'Grid', 'href': 'http://cytoscape.org' } },
      { 'data': { 'id': 'b', 'name': 'Cola', 'href': 'http://cytoscape.org' } },
      { 'data': { 'id': 'c', 'name': 'Popper', 'href': 'http://cytoscape.org' } },
      { 'data': { 'id': 'js', 'name': 'Cytoscape.js', 'href': 'http://js.cytoscape.org' } }
  ],
  'edges': [
      {'data': { 'source': 'desktop', 'target': 'js' }},
      {'data': { 'source': 'a', 'target': 'b' }},
      {'data': { 'source': 'a', 'target': 'c' }},
      {'data': { 'source': 'b', 'target': 'c' }},
      {'data': { 'source': 'js', 'target': 'b' }}
  ]
}
cytoscapeobj = ipycytoscape.CytoscapeWidget()
cytoscapeobj.graph.add_graph_from_json(data)
cytoscapeobj.set_style([{
  'selector': 'node',
  'css': {
      'content': 'data(name)',
      'text-valign': 'center',
      'color': 'white',
      'text-outline-width': 2,
      'text-outline-color': 'green',
      'background-color': 'green'
  }
  },
  {
  'selector': ':selected',
  'css': {
      'background-color': 'black',
      'line-color': 'black',
      'target-arrow-color': 'black',
      'source-arrow-color': 'black',
      'text-outline-color': 'black'
  }}
  ])
cytoscapeobj

Pythreejs Example

Thebe can display output from pythreejs. The examples are taken from the pythreejs documentation and are licensed under the BSD 3-Clause License.

Setup

Be sure to load require.js before any of your thebe activation code so that the Jupyter widgets can function:

<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>

Configure thebe and load it:

<script type="text/x-thebe-config">
  {
    requestKernel: true,
    binderOptions: {
      repo: "jupyter-widgets/pythreejs",
      ref: "2.2.1",
      binderUrl: "https://mybinder.org",
      repoProvider: "github",
    },
  }
</script>
<script src="https://unpkg.com/thebe@latest/lib/index.js"></script>

Create a button to activate thebe:

<button id="activateButton" style="width: 120px; height: 40px; font-size: 1.5em;">
  Activate
</button>
<script>
var bootstrapThebe = function() {
    thebelab.bootstrap();
}
document.querySelector("#activateButton").addEventListener('click', bootstrapThebe)
</script>

Now add code cells between these HTML tags:

<pre data-executable="true" data-language="python"></pre>

Examples

Press the “Activate” button below to connect to a Jupyter server:

Primitive shapes can be displayed:

from pythreejs import BoxGeometry
BoxGeometry(
    width=5,
    height=10,
    depth=15,
    widthSegments=5,
    heightSegments=10,
    depthSegments=15)

More complex shapes can be constructed and viewed:

from IPython.display import display
from pythreejs import (ParametricGeometry, Mesh, PerspectiveCamera, Scene,
                       MeshLambertMaterial, DirectionalLight, AmbientLight,
                       Renderer, OrbitControls, PerspectiveCamera)

f = """
function f(origu, origv, out) {
    // scale u and v to the ranges I want: [0, 2*pi]
    var u = 2*Math.PI*origu;
    var v = 2*Math.PI*origv;

    var x = Math.sin(u);
    var y = Math.cos(v);
    var z = Math.cos(u+v);

    out.set(x,y,z);
}
"""
surf_g = ParametricGeometry(func=f, slices=16, stacks=16)

surf = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='green', side='FrontSide'))
surf2 = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='yellow', side='BackSide'))
c = PerspectiveCamera(position=[5, 5, 3], up=[0, 0, 1],
                      children=[DirectionalLight(color='white',
                                                 position=[3, 5, 1],
                                                 intensity=0.6)])
scene = Scene(children=[surf, surf2, c, AmbientLight(intensity=0.5)])
renderer = Renderer(camera=c, scene=scene, controls=[OrbitControls(controlling=c)], width=400, height=400)
display(renderer)

Matplotlib + Ipywidgets Interact Example

Thebe can display interactive plots using matplotlib and ipywidget’s interact.

Setup

Be sure to load require.min.js and Font Awesome 4 before any of your thebe activation code, it is required for the widget and its icons to work:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" integrity="sha512-5A8nwdMOWrSz20fDsjczgUidUBR8liPYU+WymTZP1lmY9G6Oc7HlZv156XqnsgNUzTyMefFTcsFH/tnJE/+xBg==" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>

Configure thebe and load it:

<script type="text/x-thebe-config">
  {
    requestKernel: true,
    binderOptions: {
      repo: "matplotlib/ipympl",
      ref: "0.6.1",
      repoProvider: "github",
    },
  }
</script>
<script src="https://unpkg.com/thebe@latest/lib/index.js"></script>

Create a button to activate thebe:

<button id="activateButton" style="width: 120px; height: 40px; font-size: 1.5em;">
  Activate
</button>
<script>
var bootstrapThebe = function() {
    thebelab.bootstrap();
}
document.querySelector("#activateButton").addEventListener('click', bootstrapThebe)
</script>

Now add code cells between these HTML tags:

<pre data-executable="true" data-language="python"></pre>

Example

Press the “Activate” button below to connect to a Jupyter server:

Here is a simple interactive sine plot example:

%matplotlib widget
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0,10)

def sine_func(x, w, amp):
    return amp*np.sin(w*x)

@widgets.interact(w=(0, 4, 0.25), amp=(0, 4, .1))
def update(w = 1, amp = 1):
    plt.clf()
    plt.ylim(-4, 4)
    plt.plot(x, sine_func(x, w, amp))

Acknowledgements

thebe was originally developed as a part of OpenDreamKit - Horizon 2020 European Research Infrastructure project (676541).