A simple PyScript-fueled Jupyter Notebook running entirely in your browser - no server needed!

Jupyter right in your browser!

Working example

Below is a working example of a Python interpreter running right in your browser, importing some libraries and plotting a pretty graph with matplotlib!

Just go ahead, copy and paste the code from below in the blue input box and press SHIFT + ENTER on your keyboard or click on the play button just like in Jupyter. The first execution takes a few seconds but the following are actually quite fast!

#1 Plot a graph with matplotlib in PyScript

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import numpy as np
import matplotlib.pyplot as plt

print("<h1>Plot something with matplotlib</h1>")

data = {'a': np.arange(50),
        'c': np.random.randint(0, 50, 50),
        'd': np.random.randn(50)}
data['b'] = data['a'] + 10 * np.random.randn(50)
data['d'] = np.abs(data['d']) * 100

plt.scatter('a', 'b', c='c', s='d', data=data)
plt.xlabel('entry a')
plt.ylabel('entry b')
plt

#2 Load a remote excel file as a pandas df in PyScript

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from pyodide.http import pyfetch
import asyncio
import pandas as pd 
import openpyxl
from io import BytesIO

response = await pyfetch(url="/downloads/test.xlsx", method="GET")
bytes_response = await response.bytes()
df = pd.read_excel(BytesIO(bytes_response))
df

#3 Load, manipulate and export excel file in PyScript

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from pyodide.http import pyfetch
import asyncio
import pandas as pd 
import openpyxl
from io import BytesIO
import base64
from js import document

def pandas_excel_export(df, filename):
	# save to virtual filesystem
	df.to_excel(filename + ".xlsx")

	# binary xlsx to base64 encoded downloadable string 
	data = open("test.xlsx", 'rb').read()
	base64_encoded = base64.b64encode(data).decode('UTF-8')
	octet_string = "data:application/octet-stream;base64,"
	download_string = octet_string + base64_encoded

	# create new helper DOM element, click (download) and remove 
	element = document.createElement('a')
	element.setAttribute("href",download_string)
	element.setAttribute("download",filename + ".xlsx")
	element.click()
	element.remove()

# import 
response = await pyfetch("/downloads/test.xlsx", method="GET")
bytes_response = await response.bytes()

# read from bytes
df = pd.read_excel(BytesIO(bytes_response))

# manipulate
df["d"] = df["a"] + df["b"]

# export
pandas_excel_export(df,"test")

Insert the code from above right here:

- matplotlib - numpy - pandas - openpyxl

Output
Errors and Warnings

A prettier version

The code from above is borrowed from PyScript’s example site. Find the slightly modified basic version I used in this blog post here or the more sophisticated version here.

How does PyScript work?

PyScript is a fantastic project based on recent web technologies like Pyodide and WebAssembly. In a nutshell, it relies on modern browsers’ capability to run C/C++ code by compiling it to .wasm format.

Everything you need to add to your HTML file is the following line.

1
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>

It loads all the neccessary components via CDN and gets your interpreter ready.

If you need additional libraries include them with the ‘py-env’ tag. Not all libraries are supported yet but the very common ones like numpy, matplotlib or pandas are supported and work out-of-the-box!

1
2
3
4
5
6
  <py-env>
    - matplotlib
    - numpy
    - pandas
    - openpyxl
  </py-env>

So put altogether, to get the above examples running, I embedded this code on this HTML page.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
  <py-env>
    - matplotlib
    - numpy
    - pandas
    - openpyxl
  </py-env>


  <div>
    <div>
      <py-repl std-out="output" std-err="errors"></py-repl>
    </div><hr>
    <div>
      <b>Output</b><hr>
      <div id="output"></div>
    </div>
    <div>
      <b>Errors and Warnings</b><hr>
      <div id="errors"></div>
    </div>
  </div>

Read my first blog post about PyScript to find out more.

Jupyter Notebooks and PyScript

Disclaimer: the above mini example is not affiliated with the official Jupyter project. It is simply an emulation of its REPL logic - Read-Eval-Print-Loop but great for simple examples, playing around with the code or for beginners struggling with the calssic overhead like failing installations, different OS or virtual environments.

Find out more about Pyscript and REPL here or see other examples here.

Endless possibilites with PyScript

PyScript’s community is actively developing more mature use cases like machine learning pipelines, geospatial processing and much more. They have already done an incredible job so far! Personally, I’m super excited about what’s coming next and that from now on I can finally share my working Jupyter Notebooks with the world without having to pay for a costly server or worry about Python’s dependency hell. If it runs in my browser it will run in yours as well! :)

Bonus: a Python interpreter in markdown

As you might know, I created this blog with Hugo and write all my blog posts in markdown. In most markdown engines the option to render HTML directly is either supported by default or can be activated.

So in my use case, Hugo + Markdown + PyScript is a perfect match for writing nice interactive geospatial data science blog posts!

Spread the word

The more people know about it, the faster the community will grow and push its development. So spread the word!