どうもです、タドスケです。
PyScriptを触っていて、基本的な機能に関する使い方を色々と調べましたので、サンプル集として公開しておきます。
このページにあるサンプルは自由にお使いいただいて構いません。
※2022/08/23更新
matplotlibを使用したグラフの描画
このページの内容は、PyScript の alpha 版を使用しています。
2023/07/02 現在、まだ動くことを確認していますが、最新版(latest)では廃止されている可能性があります。
Hello world
PyScriptでHello worldを表示するサンプルです。
<!-- 必要最小限のPyScript動作 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<!-- pyscriptを使えるようにするために必要な2行 -->
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<div id="output"/>
<!-- ここ以下にpythonのコードを書く -->
<py-script>
output = Element('output')
output.write('Hello world!')
</py-script>
</body>
</html>
Element(Id名) で要素を取得し、write() で中身を書き換えています。
メインループ
定期的に実行されるメインループの実装例です。
<!-- 定期的に実行されるメインループを持つサンプル -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<!-- pyscriptを使えるようにするために必要な2行 -->
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<div id="output"/>
<!-- ここ以下にpythonのコードを書く -->
<py-script>
from datetime import datetime as dt
import asyncio
# 定数
_FPS = 1.0 / 30
# エレメント
_OUTPUT = Element('output')
# 呼び出す関数はasyncにする必要がある
async def main():
while True:
_OUTPUT.write(f'{dt.now()}')
await asyncio.sleep(_FPS)
pyscript_loader.close()
pyscript.run_until_complete(main())
</py-script>
</body>
</html>
呼び出す関数をasyncで定義するのと、pyscript.run_until_complete(main()) で関数を登録しているのがポイントです。
入力
マウス、キー入力を受け取るサンプルです。
<!-- キー入力を取得するサンプル -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<!-- pyscriptを使えるようにするために必要な2行 -->
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<div style="height:300px;border:solid;">
Key=<input id="key"/><br/>
MouseButton=<input id="mousebutton"/><br/>
MousePos=<input id="mousepos" value="()"/><br/>
</div>
<!-- ここ以下にpythonのコードを書く -->
<py-script>
from pyodide import create_proxy
# エレメント
el_key = Element('key')
el_mousebutton = Element('mousebutton')
el_mousepos = Element('mousepos')
# 呼び出す関数はasyncにする必要がある
async def on_keydown(event):
"""キーが押されたとき."""
el_key.element.value = event.key
async def on_keyup(event):
"""キーが離されたとき."""
el_key.element.value = ''
async def on_mousedown(event):
"""マウスボタンが押されたとき."""
el_mousebutton.element.value = event.button
async def on_mouseup(event):
"""マウスボタンが離されたとき."""
el_mousebutton.element.value = ''
async def on_mousemove(event):
"""マウスカーソルが移動したとき."""
el_mousepos.element.value = f'({event.x}, {event.y})'
panel = document.querySelector("body")
panel.addEventListener("keydown", create_proxy(on_keydown))
panel.addEventListener("keyup", create_proxy(on_keyup))
panel.addEventListener("mousedown", create_proxy(on_mousedown))
panel.addEventListener("mouseup", create_proxy(on_mouseup))
panel.addEventListener("mousemove", create_proxy(on_mousemove))
</py-script>
</body>
</html>
document.querySelector() 関数で取得した要素に対して addEventListener を呼んでイベントを登録しています。
登録する関数はそのままでは登録できず、create_proxy(func) と指定する必要があります。
イベント名などはJavaScriptのものがそのまま使えるようです。
自作モジュール
pythonコードが大きくなってくると、html内に直接書くのがしんどくなってきます。
py-scriptでは、外部にある自作モジュールを読み込んで実行させることができます。
今回は以下のモジュール(mymodule.py)を読み込みます。
def hello():
print('pyから表示')
if __name__ == '__main__':
hello()
やり方は以下の2つがあります。
- py-scriptタグにsrc属性をつける
- py-envタグ内で宣言して、py-script内でimport
py-scriptタグにsrc属性をつける
<!-- 必要最小限のPyScript動作 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<!-- pyscriptを使えるようにするために必要な2行 -->
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<py-script src="./mymodule.py"><!-- main扱いになる -->
print('htmlから表示') # srcを指定した場合、このコードは実行されない
</py-script>
</body>
</html>
まるっとそのままファイルを指定できるので簡単です。
ただしhtmlに書いた他のコードが実行されなくなってしまうようなので、html要素と連携するようなコードを書くのが難しくなるかもしれません。
py-envタグ内で宣言して、py-script内でimport
<!-- 必要最小限のPyScript動作 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<!-- pyscriptを使えるようにするために必要な2行 -->
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<!-- importするために、ここに書いておく必要がある -->
<!-- 自作モジュールを使う時は paths: 以降にモジュール名を書く -->
<py-env>
- paths:
- ./mymodule.py
</py-env>
</head>
<body>
<py-script>
import mymodule # importなのでmain扱いにならない
print('htmlから表示')
mymodule.hello() # モジュール内の関数を呼び出せる
</py-script>
</body>
</html>
importしたモジュール内の関数をhtml内から呼び出すことができます。
htmlに依存しないコードをモジュール内に書いておいて、依存部分だけhtml側に書くようにするのが良さそうです。
ローカルストレージによるセーブ機能
ローカルストレージ機能を利用して、ブラウザ上にセーブデータを保存するサンプルです。
ページをリロードする度に数字が増えます。
※ローカルストレージ機能をOFFにしている場合は動きません
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<!-- pyscriptを使えるようにするために必要な2行 -->
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<input id="output" style="width:300px"/>
<py-script>
from js import localStorage, document
# localStorage.removeItem('count') # 値をリセットしたい場合はコメントアウトを外す
# 読み込み
count = localStorage.getItem('count')
if count is None:
count = 0 # 値が無ければ初期値を設定
else:
count = int(count) + 1 # 値があれば加算
# 保存
localStorage.setItem('count', count)
output = document.querySelector('#output')
output.value = f'{count} 回目のご来店ありがとうございます。'
</py-script>
</body>
</html>
from js import localStorage でlocalStorageを使えるようにします。
後はJavaScriptのlocalStorageの使い方を参考に、getItem, setItemでデータを読み書きできます。
注意点として、localStorageで扱えるのは文字列型のみなので、数値型を保存するにはint-str関数による変換が必要です。
Canvasを利用した描画
canvasを取ってきて描画するサンプルです。
<!-- canvasを利用した描画サンプル -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<canvas id="output" width="300px" height="200px"/>
<py-script>
import math
from js import document, Element, CanvasRenderingContext2D, Image
canvas: Element = document.querySelector('#output')
ctx: CanvasRenderingContext2D = canvas.getContext('2d')
def draw_rect():
"""四角の描画."""
ctx.fillStyle = "rgb(0, 0, 0)"
ctx.fillRect(0, 0, 300, 200)
def draw_arc():
"""円の描画."""
center_x = 50 # 中心X
center_y = 50 # 中心Y
radius = 20 # 半径
angle_start = 0 * math.pi / 180 # 開始角度
angle_end = 360 * math.pi / 180 # 終了角度
anticlockwise = False # 反時計回りにするか
ctx.fillStyle = "rgb(0, 255, 255)"
ctx.arc( center_x, center_y, radius, angle_start, angle_end, anticlockwise ) ;
ctx.fill()
def draw_text():
"""テキストの描画."""
ctx.font = "15px bold sans-serif"
ctx.fillStyle = "rgb(255, 255, 255)"
ctx.fillText(f"canvasに描いています", 5, 20)
def draw_image():
"""画像の描画."""
x = 100
y = 60
w = 50
h = 50
image = Image.new() # pythonではnew Image()とできないので、特殊な書き方になる
image.src = 'image.png'
image.onload = lambda e: ctx.drawImage(image, x, y, w, h) # 読み込み待ちをしないと表示されない
draw_rect()
draw_arc()
draw_text()
draw_image()
</py-script>
</body>
</html>
getContext(‘2d’) で取ってきたcontextに対して、JavaScriptと同じ形式の関数が呼べます。
画像だけはちょっと特殊で、以下の対応が必要です。
- imageインスタンスはImage.new() で生成する(JavaScriptとは違う書き方)
- image.onloadに読み込み完了後のメソッドを登録し、その中でdrawImageを呼ぶ
matplotlibを利用したグラフの描画
matplotlibを使用してグラフを描画するサンプルです。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<py-env>
- matplotlib
</py-env>
</head>
<body>
<div id="output"></div>
<py-script>
import matplotlib.pyplot as plt
x = [i for i in range(100)]
y = [i**2 for i in range(100)]
fig = plt.figure()
plt.plot(x, y)
pyscript.write('output', fig)
</py-script>
</body>
</html>
matplotlibを単体で使う際にはshow()関数を使うのですが、PyScriptの場合はウィンドウを生成することができないので、代わりにpyscript.writeでdivタグに貼り付けています。
貼り付けるためにグラフの描画領域(fig)を明示的に取得しています。
(showで表示するだけならこの行は省略可能)
コメント
コメント一覧 (1件)
[…] 【PyScript】サンプル集(alpha 版) どうもです、タドスケです。 […]