初めに〜PyScriptとは〜
最近、PyScriptというものが少しホットな話題になっているようです。
これまでHTMLの中に書くことができるのはJavaScriptだけだったのですが、PyScriptを用いるとPythonコードをHTMLの中に書いて、実行することができます。
例えば入力されたデータを用いてグラフを描画するといったことは、これまでJavaScriptでしかできませんでしたが、これからはPythonを使うことでも可能になるのです!
2022年4月末にAnacondaから発表されたPyScriptですが、当記事執筆時点(2022年6月)で公開されているのはアルファ版(パイロット版) です。
まだまだ機能が足りないところもありますが、今後の開発が期待されます。
本記事執筆時点(2022年6月)で、PyScriptはアルファ版です。本番環境での使用はお控えください。
公式も「本番環境での使用は推奨しません」と発表しています。
開発環境
この記事では以下の環境で開発を行っています。
- MacOS Monterey version 12.4
- ブラウザ:Safari version 15.5
(エディタはCotEditorを使うことが多いです。同士いますか...)
基本的な使い方
head
タグに<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
を書いてやれば使えるようになります。
PyScriptのページからローカルにダウンロードして読み込んでも良いでしょう。
PyScript用のcssも準備されています。
そちらは<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css"/>
から読み込めます。
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css"/>
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
</html>
コードは<py-script>
タグで囲んだ部分に書きます。
インデントをちゃんと書かないとエラーになるのはいつものpythonと同じですので注意が必要です。
...
<body>
<py-script>
print("Hello, world!")
</py-script>
</body>
...
Loading runtime...というちょっとかっこいい画面
左上にちゃんとHello, World!
。
f-string
もちゃんと使うことができます。ただし、<h1>
タグなどで装飾するのはできないようです。
...
<py-script>
My_name = "Rj.Chiba"
print("Hello, " + My_name)
print(f"Hello, {My_name}")
print("<h1>hogehoge</h1>")
</py-script>
<h1>
<py-script>
print("hogehoge")
</py-script>
</h1>
...
これはPyScriptで表示している文字がdiv
タグの中に書かれているため。
この場合は、表示させたい場所にp
タグなどをあらかじめ作っておいて、そのid
を<py-script output=[id]>
と渡してあげる。
...
<body>
<p id="title" style="font-size:20px;" align="center"></p>
<py-script output="title">
print("Hello, World!")
</py-script>
</body>
...
なお、pyscript.write(id名,渡す値)
としても同じ結果が得られます。
でもoutput=[id]
は必要なんですよね...
<body>
<p id="title" style="font-size:20px;" align="center"></p>
<py-script output="title">
pyscript.write("title","Hello Rj.Chiba!")
</py-script>
</body>
対話的にスクリプトを実行することもできます。
そのために使うのが<py-repl>
タグ。これを書いておくだけでスクリプトを入力し、実行することができます。
...
<body>
<py-repl>
</py-repl>
</body>
...
実行してほしいスクリプトを最初から書いておくこともできます。
...
<body>
<py-repl>
print(1+1)
print(1+2)
</py-repl>
</body>
...
標準ライブラリも使いたい
pythonの良いところはやはりライブラリが充実している点。
PyScriptでは標準ライブラリを使用することができます。
まずはPythonのバージョンを表示させてみましょう。
普段pythonを使っている時と同様に、platform
をimportして、platform.python_version()
をprintします。
<body>
<p id="title" style="font-size:20px;" align="center"></p>
<py-script output="title">
import platform
print(f"Python Version: {platform.python_version()}")
</py-script>
</body>
外部ライブラリも使いたい!
データなどを扱っている人で、numpy
やpandas
、scikit-learn
あたりを使いたい人も多いのではないでしょうか。ここではそれらの外部ライブラリを読み込んで、データを出力してみたいと思います。
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css"/>
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<py-env>
- numpy
- matplotlib
</py-env>
</head>
<body>
<div id="canvas" align="center"></div>
<py-script output="canvas">
import numpy as np
from matplotlib import pyplot as plt
fig = plt.figure()
x = np.linspace(0,10,1000)
y = np.sin(x)+np.cos(x*1.1)
plt.plot(x,y,c="r",lw=1,label=r"$y=\sin x+\cos(1.1x)$")
plt.grid()
plt.legend()
plt
</py-script>
</body>
</html>
外部ライブラリを読み込むためには、head
タグ内にpy-env
タグを作って、その中でインポートしたいライブラリを宣言します。
ここではnumpy
とmatplotlib
を読み込んでいます。
...
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css"/>
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<py-env>
- numpy
- matplotlib
</py-env>
</head>
...
グラフを表示させる方法は、普段のpythonコードとほとんど変わりません。
...
<div id="canvas" align="center"></div>
<py-script output="canvas">
# ライブラリをインポート
import numpy as np
from matplotlib import pyplot as plt
fig = plt.figure()
# データを作る
x = np.linspace(0,10,1000)
y = np.sin(x)+np.cos(x*1.1)
# プロット
plt.plot(x,y,c="r",lw=1,label=r"$y=\sin x+\cos(1.1x)$")
plt.grid()
plt.legend()
plt #いつもと違うところ!
</py-script>
...
唯一違う点は最終行のplt
です。
普段グラフを表示させるときはplt.show()
などを用いますが、PyScriptでそれをすると、なにも表示されません。
パッケージごとに他にもローカルルールがあるかもしれません。
今のところ困ること
先日、東北大学のオープンキャンパス用にwebページを作っていて、PyScriptでアニメーションを表示させようとしたところ詰まりました。
from matplotlib import animation
...
ani = animation.ArtistAnimation(fig, img, interval=50)
...
PythonError:
Traceback (most recent call last):
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 429, in eval_code .run(globals, locals)
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 300, in run coroutine = eval(self.code, globals, locals)
File "", line 6, in File "/lib/python3.10/site-packages/matplotlib/animation.py", line 1457, in __init__ super().__init__(fig, *args, **kwargs)
File "/lib/python3.10/site-packages/matplotlib/animation.py", line 1397, in __init__ event_source = fig.canvas.new_timer(interval=self._interval)
File "/lib/python3.10/site-packages/matplotlib/backends/browser_backend.py", line 468, in new_timer return TimerWasm(*args, **kwargs)
File "/lib/python3.10/site-packages/matplotlib/backend_bases.py", line 1097, in __init__ self.interval = 1000 if interval is None else interval
File "/lib/python3.10/site-packages/matplotlib/backend_bases.py", line 1139, in interval self._timer_set_interval()
File "/lib/python3.10/site-packages/matplotlib/backends/browser_backend.py", line 562, in _timer_set_interval if self._timer is not None:
AttributeError: 'TimerWasm' object has no attribute '_timer'
単純にTimerWasmには_timerなんてattributeはないよ! というエラー。
この問題の根本にあるのは、ブラウザ上で非同期処理ができないということらしい(How to fix matplotlib animation issue: 'TimerWasm' object has no attribute '_timer')。
まだアルファ版なので仕方ない部分なんですかね...
自作ライブラリも使いたい!
まだまだ不満な点は多いですが、PyScriptでは自作のライブラリを読み込んで使うこともできます。
例として次のようなhello.py
を準備してみましょう。
def greeting(name);
print(f"Hello, I am {name}!")
def call():
print("Who are you?")
これを読み込むためには、<py-env>
タグを次のように書きます。
...
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css"/>
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<py-env>
- paths:
- hello.py
</py-env>
</head>
...
あとは外部ライブラリを読み込んだ時と同じことをすればOK。
...
<py-script>
from hello import *
name = "Qiiiiiiita"
greeting(name)
call()
</py-script>
...
しかし...
うまくいかない!ModuleNotFoundError
が出てしまいます。
pathの通っているディレクトリにhello.py
を置いても、簡易サーバーを立ち上げてもダメでした。
PythonError:
Traceback (most recent call last):
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 429, in eval_code .run(globals, locals)
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 300, in run coroutine = eval(self.code, globals, locals)
File "", line 4, in ModuleNotFoundError: No module named 'hello'
他にもimportがうまくいかないという記事がありましたが、
一方でうまくいっている雰囲気の記事もあります(HTML内にPythonコードを書いて実行できるPyScriptで遊んでみた!)。
方法は合っている気がするのだけど。
最後に。
PyScriptのポテンシャルを感じることはできましたが、
アルファ版ということもあって、本番環境では使えないですね!(そりゃそう)
更なる開発に期待しています。
でもコードなども公開されているので、ぜひご参考に。
PyScript demo
それでは!