PyScript Examples: Python for JavaScript Developers

Serverless Python scripts to run natively in your Web Browser

Ivan Campos
Sopmac Labs
Published in
12 min readFeb 16, 2023

--

PyScript Code Cookbook Contents

  1. OpenAI API for completions from GPT-3 & chats from GPT-3.5-turbo
  2. BeautifulSoup for web scraping
  3. Matplotlib for data visualization
  4. Pandas for dataframes (spreadsheets or tables)
  5. Numpy for manipulation of arrays

What is PyScript?

PyScript lets developers run Python code in a web browser — making it useful for web developers and data scientists.

Simply add these two lines inside the head of an HTML document to set up PyScript:

<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>

Once your setup is complete, we just need to add code to the HTML body.

Each of our cookbook items will present:

  • The primary objective of the example
  • A detailed description of the code
  • Working code (HTML elements and PyScript) for the HTML body
  • Sample web browser output

Feel free to explore cookbook entries in any order.

Artificial Intelligence

XMLHttpRequest and json

Objective: To use the OpenAI API to generate text based on a prompt and display it on a web page.

Note: While there is an official openai package for Python, only those packages listed in the following link are currently supported by PyScript: https://pyodide.org/en/stable/usage/packages-in-pyodide.html

Code Explanation for OpenAI API

  1. Imports: The code starts by importing the required modules, including json for encoding and decoding JSON data, localStorage and document from the JavaScript environment, and XMLHttpRequest for making HTTP requests.
  2. Bearer token: The code sets the bearer variable to a string that includes the OpenAI API authorization token, which is stored in the browser's local storage using the localStorage module.
  3. Prompt: The code sets the prompt variable to the string "list three colors" and displays it in a div with the ID prompt.
  4. Engine: The code sets the engine variable to "text-ada-001", which is the OpenAI API model to use for generating the text completion.
  5. XHR request: The code creates a new XMLHttpRequest object and opens a POST request to the OpenAI API completion endpoint. The request includes the required headers, including the "Content-Type" header set to "application/json" and the "Authorization" header set to the bearer token.
  6. Request data: The code creates a JSON object that includes the request data, including the prompt, the model to use, and various other parameters, and sends it with the XHR request.
  7. Response handling: The code uses the json.loads method to parse the JSON response from the API, and extracts the text of the first completion from the response.
  8. Completion display: The code displays the completion text in a div with the ID completion.
<body>
<div id="prompt"></div>
<div id="completion"></div>
<py-script>
import json
from js import localStorage, document, console, XMLHttpRequest

# !! set localStorage.setItem("openAI", "sk-YOUR_KEY") !!
bearer = "Bearer " + localStorage.getItem("openAI")

promptDiv = document.getElementById("prompt")
prompt = "list three colors"
promptDiv.innerHTML = "<h3>Prompt: </h3>\"" + prompt + "\"<hr/>"

# for best results (at a cost of $.02 per 1k tokens), use text-davinci-003
# for quickest and cheapest results ($.0004 per 1k tokens), use text-ada-001
engine = "text-ada-001"

xhr = XMLHttpRequest.new()
xhr.open("POST", "https://api.openai.com/v1/completions", False)
xhr.setRequestHeader("Content-Type", "application/json")
xhr.setRequestHeader("Authorization", bearer)

data = json.dumps({
"model": engine,
"prompt": prompt,
"max_tokens": 100,
"temperature": 0,
"top_p": 1,
"frequency_penalty": 1.2,
"presence_penalty": 0
})

xhr.send(data)

json_response = json.loads(xhr.response)
completion_text = json_response["choices"][0]["text"]
# console.log("Colors: " + completion_text)

completionDiv = document.getElementById("completion")
completionDiv.innerHTML = "<h3>OpenAI (" + engine + ") Response: </h3>\"" + completion_text.strip() + "\""
</py-script>
</body>

🆕 Example using GPT-3.5-turbo (July 2023)

<body>
<div id="prompt"></div>
<div id="completion"></div>
<py-script>
import json
from js import localStorage, document, console, XMLHttpRequest

# !! set localStorage.setItem("openAI", "sk-YOUR_KEY") !!
bearer = "Bearer " + localStorage.getItem("openAI")

promptDiv = document.getElementById("prompt")
prompt = "list three colors"
promptDiv.innerHTML = "<h3>Prompt: </h3>\"" + prompt + "\"<hr/>"

# for best results (at a cost of $.02 per 1k tokens), use text-davinci-003
# for quickest and cheapest results ($.0004 per 1k tokens), use text-ada-001
engine = "gpt-3.5-turbo"

xhr = XMLHttpRequest.new()
xhr.open("POST", "https://api.openai.com/v1/chat/completions", False)
xhr.setRequestHeader("Content-Type", "application/json")
xhr.setRequestHeader("Authorization", bearer)

data = json.dumps({
"model": engine,
"messages": [
{
"role": "system",
"content": "you are a helpful assistant."
},
{
"role": "user",
"content": prompt
}
],
"temperature": 1,
"max_tokens": 256,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0
})

xhr.send(data)

json_response = json.loads(xhr.response)
print(json_response)
completion_text = json_response["choices"][0]["message"]["content"]

completionDiv = document.getElementById("completion")
completionDiv.innerHTML = "<h3>OpenAI (" + engine + ") Response: </h3>\"" + completion_text.strip() + "\""
</py-script>
</body>

Sample Web Browser Output for AI

Web Scraping

beautifulsoup4

Objective: to use BeautifulSoup to scrape all the links from midjourney.com and displays the links in a div element.

This code specifies that the beautifulsoup4 package be imported for use in the PyScript code.

<py-config>
packages = ['beautifulsoup4']
</py-config>

Code Explanation for Web Scraping

  1. Imports: The code starts by importing the required modules, including BeautifulSoup from the bs4 library, and document and XMLHttpRequest from the JavaScript environment.
  2. URL and XHR request: The code sets the url variable to "https://midjourney.com", creates a new XMLHttpRequest object, and opens a GET request to the URL. The code then sends the request and retrieves the response.
  3. Parsing: The code uses the BeautifulSoup library to parse the HTML response from the request, and sets the result to the soup variable.
  4. Link extraction: The code uses the find_all method of the soup object to extract all the a tags (links) from the HTML.
  5. Link display: The code gets a reference to the div with the ID links, and sets its inner HTML to a string that includes a header and a line break. The code then loops through the links array, gets the href attribute of each link, and adds it to the inner HTML of the div, followed by a line break.
<body>
<div id="links"></div>
<py-script>
from bs4 import BeautifulSoup
from js import document, XMLHttpRequest

url = "https://midjourney.com"
req = XMLHttpRequest.new()
req.open("GET", url, False)
req.send(None)
soup = BeautifulSoup(req.response, "html.parser")

links = soup.find_all("a")

linkDiv = document.getElementById("links")
linkDiv.innerHTML = "<span>Links for " + url + "</span><br/><br/>"

for link in links:
full_url = link.get("href")
linkDiv.innerHTML += full_url + "<br/>"
</py-script>
</body>

Sample Web Browser Output for Web Scraping

Data Visualization

matplotlib and numpy

Objective: to create a 3D bar chart of a 2D histogram of randomly generated data and displays it in a div element.

This code specifies that the matplotlib and numpypackages be imported for use in the PyScript code.

<py-config>
packages = ['matplotlib', 'numpy']
</py-config>

Code Explanation for 3D-Histogram

  1. Imports: The code starts by importing the required libraries, including matplotlib.pyplot as plt and numpy as np.
  2. Plotting function: The code defines a plot function that generates a 3D bar graph using Matplotlib.
  3. Random data: The code uses numpy to generate random data for the x and y coordinates of 100 points.
  4. 2D histogram: The code uses the np.histogram2d function to generate a 2D histogram of the random data, with the bin edges defined by xedges and yedges.
  5. Bar positions: The code uses np.meshgrid to generate arrays for the anchor positions of the bars in the 3D graph. The xpos and ypos arrays are constructed from the bin edges, and the zpos array is set to 0.
  6. Bar dimensions: The code uses np.ones_like to generate arrays for the dimensions of the bars in the 3D graph. The dx and dy arrays are set to 0.5, and the dz array is set to the values of the 2D histogram.
  7. Bar graph: The code uses the ax.bar3d method to add a 3D bar graph to the plot. The bar positions, dimensions, and sorting are defined by the arrays generated in the previous steps.
  8. Display: The code uses the display function to display the figure in the div with the ID graph-area in the web page.
<body>
<div id="graph-area"></div>
<py-script>
import matplotlib.pyplot as plt
import numpy as np

def plot():
# Fixing random state for reproducibility
np.random.seed(19680801)

fig = plt.figure()
ax = fig.add_subplot(projection='3d')
x, y = np.random.rand(2, 100) * 4
hist, xedges, yedges = np.histogram2d(x, y, bins=4, range=[[0, 4], [0, 4]])

# Construct arrays for the anchor positions of the 16 bars.
xpos, ypos = np.meshgrid(xedges[:-1] + 0.25, yedges[:-1] + 0.25, indexing="ij")
xpos = xpos.ravel()
ypos = ypos.ravel()
zpos = 0

# Construct arrays with the dimensions for the 16 bars.
dx = dy = 0.5 * np.ones_like(zpos)
dz = hist.ravel()

ax.bar3d(xpos, ypos, zpos, dx, dy, dz, zsort='average')
display(fig, target="graph-area", append=False)

plot()
</py-script>
</body>

Sample Web Browser Output for 3D-Histogram

Barcode

matplotlib and numpy

Objective: to generate a binary image plot of a 1-dimensional numpy array using matplotlib and displaying it in a div.

This code specifies that the matplotlib and numpypackages be imported for use in the PyScript code.

<py-config>
packages = ['matplotlib', 'numpy']
</py-config>

Code Explanation for Barcode

  1. Imports: The code starts by importing the required libraries, including matplotlib.pyplot as plt and numpy as np.
  2. Data: The code defines a binary array code of 100 elements.
  3. Plotting parameters: The code sets the pixel_per_bar variable to 4, and the dpi variable to 100. These parameters determine the size and resolution of the bar graph.
  4. Plotting function: The code defines a plot function that generates a bar graph representation of the binary array using Matplotlib.
  5. Figure: The code creates a new figure with the size determined by the pixel_per_bar and dpi variables, and sets the DPI to 100.
  6. Axes: The code adds a new set of axes to the figure, spanning the whole figure, and sets the axis off.
  7. Bar graph: The code uses the ax.imshow method to display the binary array as a bar graph, using the binary color map, auto aspect ratio, and nearest interpolation.
  8. Display: The code uses the display function to display the figure in the div with the ID graph-area in the web page.
<body>
<div id="graph-area"></div>
<py-script>
import matplotlib.pyplot as plt
import numpy as np

code = np.array([
1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1,
0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0,
1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1,
1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1])

pixel_per_bar = 4
dpi = 100

def plot():
fig = plt.figure(figsize=(len(code) * pixel_per_bar / dpi, 2), dpi=dpi)
ax = fig.add_axes([0, 0, 1, 1]) # span the whole figure
ax.set_axis_off()
ax.imshow(code.reshape(1, -1), cmap='binary', aspect='auto',
interpolation='nearest')
display(fig, target="graph-area", append=False)

plot()
</py-script>
</body>

Sample Web Browser Output for Barcode

Pie Chart

matplotlib

Objective: to generate a pie chart that displays the relative proportions of four data values and displays them in a div element.

This code specifies that the matplotlib package be imported for use in the PyScript code.

<py-config>
packages = ['matplotlib']
</py-config>

Code Explanation for Pie Chart

  1. Imports: The code starts by importing the required library, matplotlib.pyplot, as plt.
  2. Data: The code defines two variables, labels and sizes, which contain the labels and values of the data, respectively.
  3. Plotting function: The code defines a plot function that generates a pie chart representation of the data using Matplotlib.
  4. Subplots: The code creates a new figure and a set of axes using the plt.subplots function.
  5. Pie chart: The code uses the ax.pie method to display the data as a pie chart, with the given labels and autopct values, as well as the distances for the percentages and labels.
  6. Display: The code uses the display function to display the figure in the div with the ID graph-area in the web page.
<body>
<div id="graph-area"></div>
<py-script>
import matplotlib.pyplot as plt

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]

def plot():
fig, ax = plt.subplots()
ax.pie(sizes, labels=labels, autopct='%1.1f%%', pctdistance=1.25, labeldistance=.6)
display(fig, target="graph-area", append=False)

plot()
</py-script>
</body>

Sample Web Browser Output for Pie Chart

DataFrames

pandas and numpy

Objective: to create two pandas dataframes, pivot one of them, and display both dataframes in div elements.

This code specifies that the pandas and numpy packages be imported for use in the PyScript code.

<py-config>
packages = ['pandas', 'numpy']
</py-config>

Code Explanation for working with DataFrames

  1. Imports: The code starts by importing the required libraries, pandas as pd, numpy as np, and js to access the JavaScript API.
  2. First DataFrame: The code creates a new dataframe df with 3 columns, "AAA", "BBB", and "CCC", and 4 rows of data.
  3. Displaying the first DataFrame: The code uses the document.getElementById method to access the div element with the ID "df-table". The code sets the innerHTML property of the element to display the string "DataFrame" followed by a line break. The code then uses the display function to display the df dataframe in the "df-table" div, with the append argument set to "True" so that the dataframe is appended to the existing contents of the div.
  4. Second DataFrame: The code creates a new dataframe df2 with 3 columns, "Province", "City", and "Sales", and 7 rows of data.
  5. Pivot Table: The code uses the pd.pivot_table method to create a pivot table representation of the df2 dataframe, with "Province" as the index, "City" as the columns, "Sales" as the values, using the sum of the values, and including the margins.
  6. Displaying the pivot table: The code uses the document.getElementById method to access the div element with the ID "df2-table". The code sets the innerHTML property of the element to display the string "Pivot Raw" followed by a line break. The code then uses the display function to display the raw df2 dataframe in the "df2-table" div, with the append argument set to "True" so that the dataframe is appended to the existing contents of the div. The code then appends another line break and the string "Pivoted" to the innerHTML property of the "df2-table" div and displays the pivot table representation of the df2 dataframe in the "df2-table" div using the display function.
<body>
<div id="df-table"></div>
<hr/>
<div id="df2-table"></div>
<py-script>
import pandas as pd
import numpy as np
from js import document

df = pd.DataFrame(
{"AAA": [4, 5, 6, 7], "BBB": [10, 20, 30, 40], "CCC": [100, 50, -30, -50]}
)

TableDF = document.getElementById("df-table")
TableDF.innerHTML = "DataFrame<br/>"

display(df, target="df-table", append="True")


df2 = pd.DataFrame(
data={
"Province": ["ON", "QC", "BC", "AL", "AL", "MN", "ON"],
"City": [
"Toronto",
"Montreal",
"Vancouver",
"Calgary",
"Edmonton",
"Winnipeg",
"Windsor",
],
"Sales": [13, 6, 16, 8, 4, 3, 1],
}
)

pivot = pd.pivot_table(
df2,
values=["Sales"],
index=["Province"],
columns=["City"],
aggfunc=np.sum,
margins=True,
)

pivot.stack("City")

TableDF2 = document.getElementById("df2-table")
TableDF2.innerHTML = "Pivot Raw<br/>"

display(df2, target="df2-table", append="True")
TableDF2.innerHTML += "<br/>Pivoted"
display(pivot, target="df2-table", append="True")

</py-script>
</body>

Sample Web Browser Output for DataFrames

Arrays

numpy

Objective: to generate random 4x3 arrays using numpy and display their values, shapes, and transposed values in a div element.

This code specifies that the numpy package be imported for use in the PyScript code.

<py-config>
packages = ['numpy']
</py-config>

Code Explanation for working with Arrays

  1. This code generates a random 4x3 array using the np.random.rand function from the NumPy library, and stores the result in the variable random. It then displays the contents of random as a string in a div element with the id "array-area".
  2. The code also creates a 3x2 array and finds its shape using the shape attribute and stores the result in the variable shape. The shape is then displayed in the same div element.
  3. Finally, the code creates a 2x3 array and finds its transpose using the T attribute and stores the result in the variable transposedArray. The original and transposed arrays are displayed in the same div element.
<body>
<div id="array-area"></div>
<py-script>
import numpy as np
from js import document, XMLHttpRequest

divArray = document.getElementById("array-area")

random = np.random.rand(4,3)
divArray.innerHTML = "Random (4,3) Array: " + str(random.tolist()) + "<hr/>"

array = np.array([[1,2],[3,4],[5,6]])
shape = array.shape
divArray.innerHTML += "Shape of " + str(array.tolist()) + " is " + str(shape) + "<hr/>"

arrayToTranspose = np.array([['s','t','u'],['x','y','z']])
transposedArray = arrayToTranspose.T
divArray.innerHTML += str(arrayToTranspose.tolist()) + " transposed is " + str(transposedArray.tolist())

</py-script>
</body>

Sample Web Browser Output for Arrays

GitHub Repo

All of the code reviewed above is available within the following repository: https://github.com/IvanCampos/pyScript

To get the code working, just open an example’s HTML file with your web browser.

No deployment scripts, servers, cloud configs, command line instructions, etc…

Just like vanilla JavaScript, you simply have Python running natively inside your web browser.

--

--

Ivan Campos
Sopmac Labs

Exploring the potential of AI to revolutionize the way we live and work. Join me in discovering the future of tech