4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

最近話題のPyScriptを使ってみる

Last updated at Posted at 2022-06-29

初めに〜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"/>から読み込めます。

index.html
<!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と同じですので注意が必要です。

index.html
...
 <body>
 <py-script>
print("Hello, world!")
 </py-script>
 </body>
...

Loading runtime...というちょっとかっこいい画面
スクリーンショット 2022-06-29 14.08.15.png
左上にちゃんとHello, World!
スクリーンショット 2022-06-29 14.09.27.png

f-stringもちゃんと使うことができます。ただし、<h1>タグなどで装飾するのはできないようです。

index.html
...
  <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>
...

スクリーンショット 2022-06-29 15.07.22.png
これはPyScriptで表示している文字がdivタグの中に書かれているため。

この場合は、表示させたい場所にpタグなどをあらかじめ作っておいて、そのid<py-script output=[id]>と渡してあげる。

index.html
...
<body>
 <p id="title" style="font-size:20px;" align="center"></p>
 <py-script output="title">
print("Hello, World!")
 </py-script>
</body>
...

スクリーンショット 2022-06-29 15.17.05.png

なお、pyscript.write(id名,渡す値)としても同じ結果が得られます。
でもoutput=[id]は必要なんですよね...

index.html
<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>タグ。これを書いておくだけでスクリプトを入力し、実行することができます。

index.html
...
<body>
  <py-repl>
  </py-repl>
</body>
...

なにも書かないと、もちろん対話シェルしか表示されない。
スクリーンショット 2022-06-29 16.02.46.png

実行してほしいスクリプトを最初から書いておくこともできます。

index.html
...
<body>
  <py-repl>
print(1+1)
print(1+2)
  </py-repl>
</body>
...

スクリーンショット 2022-06-29 16.05.43.png

標準ライブラリも使いたい

pythonの良いところはやはりライブラリが充実している点。
PyScriptでは標準ライブラリを使用することができます。
まずはPythonのバージョンを表示させてみましょう。

普段pythonを使っている時と同様に、platformをimportして、platform.python_version()をprintします。

index.html
<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>

スクリーンショット 2022-06-29 15.27.25.png
python 3.10が入っているんですね。

外部ライブラリも使いたい!

データなどを扱っている人で、numpypandasscikit-learnあたりを使いたい人も多いのではないでしょうか。ここではそれらの外部ライブラリを読み込んで、データを出力してみたいと思います。

index.html
<!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>

スクリーンショット 2022-06-29 15.34.52.png

外部ライブラリを読み込むためには、headタグ内にpy-envタグを作って、その中でインポートしたいライブラリを宣言します。
ここではnumpymatplotlibを読み込んでいます。

...
<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)
...

このコードを実行させようとしたところ、次のようなエラーが。
スクリーンショット 2022-06-29 15.48.20.png

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を準備してみましょう。

hello.py
def greeting(name);
 print(f"Hello, I am {name}!")

def call():
 print("Who are you?")

これを読み込むためには、<py-env>タグを次のように書きます。

index.html
...
<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。

index.html
...
 <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

それでは!

4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?