PyScript Examples: Python for JavaScript Developers
Serverless Python scripts to run natively in your Web Browser
PyScript Code Cookbook Contents
- OpenAI API for completions from GPT-3 & chats from GPT-3.5-turbo
- BeautifulSoup for web scraping
- Matplotlib for data visualization
- Pandas for dataframes (spreadsheets or tables)
- 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
- Imports: The code starts by importing the required modules, including
json
for encoding and decoding JSON data,localStorage
anddocument
from the JavaScript environment, andXMLHttpRequest
for making HTTP requests. - 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 thelocalStorage
module. - Prompt: The code sets the
prompt
variable to the string "list three colors" and displays it in adiv
with the IDprompt
. - Engine: The code sets the
engine
variable to "text-ada-001", which is the OpenAI API model to use for generating the text completion. - 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 thebearer
token. - 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.
- 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. - Completion display: The code displays the completion text in a
div
with the IDcompletion
.
<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
- Imports: The code starts by importing the required modules, including
BeautifulSoup
from thebs4
library, anddocument
andXMLHttpRequest
from the JavaScript environment. - URL and XHR request: The code sets the
url
variable to "https://midjourney.com", creates a newXMLHttpRequest
object, and opens a GET request to the URL. The code then sends the request and retrieves the response. - Parsing: The code uses the
BeautifulSoup
library to parse the HTML response from the request, and sets the result to thesoup
variable. - Link extraction: The code uses the
find_all
method of thesoup
object to extract all thea
tags (links) from the HTML. - Link display: The code gets a reference to the
div
with the IDlinks
, and sets its inner HTML to a string that includes a header and a line break. The code then loops through thelinks
array, gets thehref
attribute of each link, and adds it to the inner HTML of thediv
, 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 numpy
packages be imported for use in the PyScript code.
<py-config>
packages = ['matplotlib', 'numpy']
</py-config>
Code Explanation for 3D-Histogram
- Imports: The code starts by importing the required libraries, including
matplotlib.pyplot
asplt
andnumpy
asnp
. - Plotting function: The code defines a
plot
function that generates a 3D bar graph using Matplotlib. - Random data: The code uses
numpy
to generate random data for the x and y coordinates of 100 points. - 2D histogram: The code uses the
np.histogram2d
function to generate a 2D histogram of the random data, with the bin edges defined byxedges
andyedges
. - Bar positions: The code uses
np.meshgrid
to generate arrays for the anchor positions of the bars in the 3D graph. Thexpos
andypos
arrays are constructed from the bin edges, and thezpos
array is set to 0. - Bar dimensions: The code uses
np.ones_like
to generate arrays for the dimensions of the bars in the 3D graph. Thedx
anddy
arrays are set to 0.5, and thedz
array is set to the values of the 2D histogram. - 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. - Display: The code uses the
display
function to display the figure in thediv
with the IDgraph-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 numpy
packages be imported for use in the PyScript code.
<py-config>
packages = ['matplotlib', 'numpy']
</py-config>
Code Explanation for Barcode
- Imports: The code starts by importing the required libraries, including
matplotlib.pyplot
asplt
andnumpy
asnp
. - Data: The code defines a binary array
code
of 100 elements. - Plotting parameters: The code sets the
pixel_per_bar
variable to 4, and thedpi
variable to 100. These parameters determine the size and resolution of the bar graph. - Plotting function: The code defines a
plot
function that generates a bar graph representation of the binary array using Matplotlib. - Figure: The code creates a new figure with the size determined by the
pixel_per_bar
anddpi
variables, and sets the DPI to 100. - Axes: The code adds a new set of axes to the figure, spanning the whole figure, and sets the axis off.
- Bar graph: The code uses the
ax.imshow
method to display the binary array as a bar graph, using thebinary
color map, auto aspect ratio, and nearest interpolation. - Display: The code uses the
display
function to display the figure in thediv
with the IDgraph-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
- Imports: The code starts by importing the required library,
matplotlib.pyplot
, asplt
. - Data: The code defines two variables,
labels
andsizes
, which contain the labels and values of the data, respectively. - Plotting function: The code defines a
plot
function that generates a pie chart representation of the data using Matplotlib. - Subplots: The code creates a new figure and a set of axes using the
plt.subplots
function. - 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. - Display: The code uses the
display
function to display the figure in thediv
with the IDgraph-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
- Imports: The code starts by importing the required libraries,
pandas
aspd
,numpy
asnp
, andjs
to access the JavaScript API. - First DataFrame: The code creates a new dataframe
df
with 3 columns, "AAA", "BBB", and "CCC", and 4 rows of data. - Displaying the first DataFrame: The code uses the
document.getElementById
method to access thediv
element with the ID "df-table". The code sets theinnerHTML
property of the element to display the string "DataFrame" followed by a line break. The code then uses thedisplay
function to display thedf
dataframe in the "df-table"div
, with theappend
argument set to "True" so that the dataframe is appended to the existing contents of thediv
. - Second DataFrame: The code creates a new dataframe
df2
with 3 columns, "Province", "City", and "Sales", and 7 rows of data. - Pivot Table: The code uses the
pd.pivot_table
method to create a pivot table representation of thedf2
dataframe, with "Province" as the index, "City" as the columns, "Sales" as the values, using the sum of the values, and including the margins. - Displaying the pivot table: The code uses the
document.getElementById
method to access thediv
element with the ID "df2-table". The code sets theinnerHTML
property of the element to display the string "Pivot Raw" followed by a line break. The code then uses thedisplay
function to display the rawdf2
dataframe in the "df2-table"div
, with theappend
argument set to "True" so that the dataframe is appended to the existing contents of thediv
. The code then appends another line break and the string "Pivoted" to theinnerHTML
property of the "df2-table"div
and displays the pivot table representation of thedf2
dataframe in the "df2-table"div
using thedisplay
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
- This code generates a random 4x3 array using the
np.random.rand
function from the NumPy library, and stores the result in the variablerandom
. It then displays the contents ofrandom
as a string in adiv
element with theid
"array-area". - The code also creates a 3x2 array and finds its shape using the
shape
attribute and stores the result in the variableshape
. The shape is then displayed in the samediv
element. - Finally, the code creates a 2x3 array and finds its transpose using the
T
attribute and stores the result in the variabletransposedArray
. The original and transposed arrays are displayed in the samediv
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.