Putting a web front-end on a Jupyter notebook

Let’s say you’re a data scientist, and you’ve been asked to solve a problem. Of course, what you really want is to build an interactive tool, so your colleagues can solve the problem themselves!

In this tutorial, we take a machine-learning model in a Jupyter notebook, and turn it into a web application using the Anvil Uplink:

Note: This guide includes screenshots of the Classic Editor. Since we created this guide, we've released the new Anvil Editor, which is more powerful and easier to use.

All the code in this guide will work, but the Anvil Editor will look a little different to the screenshots you see here!


Want to know more?

Read about the Uplink in the Anvil reference docs.


Topics Covered


How the connection is made | 0:21 - 0:45


We use the Anvil Uplink to connect a Jupyter Notebook to Anvil. It’s a library you can pip install on your computer or wherever your Notebook is running.

It allows you to:

  • call functions in your Jupyter Notebook from your Anvil app
  • call functions in your Anvil app from your Juypter Notebook
  • store data in your Anvil app from your Jupyter Notebook
  • use the Anvil server library inside your Jupyter Notebook

It works for any Python process - this happens to be a Jupyter Notebook, but it could be an ordinary Python script, a Flask app, even the Python REPL!


Running on-site | 0:45 - 1:02


Doing this 100% on-site in your own private network is supported. You get your own private version of the Anvil server (it’s three Docker containers) and the system runs as before, but all within your network.

Read this article for more information.


Plan of action | 1:02 - 1:10


We’re going to:

  1. Set up a Jupyter Notebook
  2. Connect it to an Anvil app
  3. Build a user interface to our model

Setting up the Jupyter Notebook | 1:10 - 1:22


We start with a pre-existing Jupyter Notebook containing a classification model that distinguishes between cats and dogs. You give it an image and it scores it as ‘cat’ or ‘dog’.

Our thanks to Uysim Ty for sharing it on Kaggle.


Making the connection | 1:22 - 1:54


We enable the Anvil Uplink and connect the notebook.

First, we enable the Uplink in the Anvil IDE.

A modal from the IDE showing a randomised key you can use to connect to your Anvil app from any Python process.

Then we pip install the Uplink library on the machine the Jupyter Notebook is running on:

pip install anvil-uplink

By adding the following lines, we connect the Jupyter Notebook to our Anvil app:

import anvil.server

anvil.server.connect('PKXOZYCZKFLQ75KUKBRTS5DO-7NSHFRCVF76FAGQL')

Now our Jupyter Notebook can do anything we can do in an Anvil Server Module - call Anvil server functions, store data in Data Tables, and define server functions to be called from other parts of the app.


Loading an image into the Notebook | 1:54 - 3:14


We load the image into the Jupyter Notebook by making an anvil.server.callable function in the Jupyter Notebook:

import anvil.media

@anvil.server.callable
def classify_image(file):
    with anvil.media.TempFile(file) as filename:
        img = load_img(filename)

This function can be called from the client-side code (and server-side code) of our Anvil app.

We’re passing the image in as an Anvil Media object, which we then write to a temporary file.

The load_img function loads the file into Pillow, a Python imaging library.

Then we can do a bit of post-processing of the image to get it into a format that the model likes:

    # Inside the classify_image function

    img = img.resize((128, 128), resample=PIL.Image.BICUBIC)
    arr = img_to_array(img)
    arr = np.expand_dims(arr, axis=0)
    arr /= 255

Then we can just pass it into our model and return the result:

    # Inside the classify_image function

    score = model.predict(arr)
    return ('dog' if score < 0.5 else 'cat', float(score))

Building a User Interface | 3:14 - 3:45


We drag-and-drop components to create a User Interface. It consists of a FileLoader to upload the images, an Image to display them, and a Label to display the classification.

The Anvil Editor design view showing the app with some components dropped into it.

Making the User Interface call the Jupyter Notebook | 3:45 - 4:32


Now to write some Python code that runs in the browser so the app responds when an image is loaded in.

We define an event handler that triggers when the FileLoader gets a new file:

  def file_loader_1_change(self, file, **event_args):
    """This method is called when a new file is loaded into this FileLoader."""
    result, score = anvil.server.call('classify_image', file)
    
    self.result_lbl.text = "%s (%0.2f)" % (result, score)
    self.image_1.source = file

The first line calls the classify_image function in the Jupyter Notebook, passing in the image file.

Then we display the result (cat or dog) and the score (0 to 1; completely dog or completely cat).

We also put the image file into the Image component so that the user can see their cat or dog (or other cat-or-dog-like image) and decide if they agree with the result.


It works! Now to publish it | 4:32 - 5:10


We give it a quick test by uploading an image of a cat - yes, it works, that’s a cat.

An app containing an Upload Photo button, an image of a cat, and the text 'cat (0.96)'

It’s already published at a private URL. By click a button and entering our chosen domain name, we made it public at https://cat-or-dog.anvil.app.


Try it for yourself

Build this app for yourself - Sign up and follow along, or try more tutorials to learn more about Anvil.

The Jupyter Notebook is available on Kaggle - our thanks to Uysim Ty, its creator.


Next up

If you’d like to learn the basics of Anvil, start with the Hello, World! tutorial.

If you’d like to learn more about the Uplink, you can read the reference docs.