【最新のPyScript】HTMLにPython処理記述！ブラウザ表示をJavaScriptみたいに埋め込めるらしいので試してみた

先日PyConで取り扱っていたバックエンドで使うPythonをクライアントサイドで！使い勝手はJavaScriptとか書くかのように処理を書けるという**PyScript**です。
まだアルファ版ということで足りないところはあるようですが、話題となっているとのこと。

:point_down: サンプル: HTMLにPythonで処理書いてる。※少し時間かかるようです。

https://pyscript.net/examples/todo.html

https://pyscript.net/examples/matplotlib.html

HTMLにPythonの処理を埋め込んで書けるということで

- pandasとかscikit-learn、グラフなんかを書ける
- Pythonは書けるけどJS自信ない...

という人にも良いかもしれませんし、今後機能が充実したらもっと期待できそう。
![スクリーンショット 2022-05-13 2.16.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/b5c7bed9-0d4a-7ea5-09a7-95492d485fd8.png)

# PyScriptとは？

https://pyscript.net/

- インストール？そんなの入らない。jQueryとか使うみたいにCDN情報をコピーするだけ
- notebookみたいなものではない。
- HTMLファイルにJavaScriptで処理書くというののPython版が近い
- 2022/05現在アルファ版なので注意
- なんで動くのか？
    - ブラウザ上で動くバイナリコードのフォーマットWebAssembly使ってる
    - 詳しくないけど、JavaScriptを補完する目的で開発されたものらしい。

> https://qiita.com/ShuntaShirai/items/3ac92412720789576f22


# サクッと試す
使い方は簡単。HTMLファイルのヘッダーに以下を書けば準備完了。

```sample1.html
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
```

- 外部繋げませんとかCDN嫌いとかいう人は公式サイトからダウンロードして`pyscript.css`, `pyscript.js`指定してやればOK
- `alpha`と入っているのでアルファ版でなくなったら変わると思う
- chrome推奨

```sample1.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
    <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
    <title>Document</title>
</head>
<body>
    <py-script>
for i in range(5):
    print('Pythonで出力！')
    </py-script>
</body>
</html>
```

![スクリーンショット 2022-05-12 23.30.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/6f4294e5-7711-f580-1713-15be6c594644.png)

確かにpythonの記述で出力ができています。もちろんPythonなのでインデント重要。

# 標準ライブラリ使ってみる
当然標準ライブラリは使用できます。

```sample1.html
    <py-script>
from datetime import datetime
for i in range(5):
    print(f'【{datetime.now()}】: Pythonで出力！')
    
    </py-script>
```

![スクリーンショット 2022-05-12 23.36.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/e235a7b3-066a-0cdc-bb7f-8760925b2ae2.png)


# idに指定した箇所に処理を適用させる
`<py-script>`って囲んだところにしか表示をかけないならあまり使い道ないですので`id="xxxxx"`で指定した箇所にPython処理を埋め込みます。

```sample2.html
    <div id ="python_var" style="background-color: red;"></div>
    <py-script>
from datetime import datetime

var1 = '埋め込んだ値。背景赤'
pyscript.write('python_var', var1)
print(f'【{datetime.now()}】: Pythonで出力！')

    </py-script>
```

![スクリーンショット 2022-05-12 23.49.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/53dd10b9-9f53-f0f7-f7ac-73f3b6c95e68.png)

`pyscript.write(埋め込み先id名, 値)`を使って埋め込む先のid名を指定してpythonの値を表示させました。

## output使って埋め込む方法
pyscript.writeを使わなくても`output="xxxxx"`で埋め込む方法もある。

```sample2.html
    <div id ="python_var" style="background-color: red;"></div>
    <py-script output="python_var">
var1 = '埋め込んだ値。背景赤'
var1
    </py-script>
```
こんな感じで表示される。
![スクリーンショット 2022-05-13 1.23.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/e8eb59d1-1178-44b9-aadc-2a96e40f15b8.png)

pythonの処理内容をoutputの名前と一致するところに入れているだけ。
`var1`だけ書きましたが`print(var1)`してもOK

# 外部ライブラリ使う場合
Pyodideの公式サイトに使用できるライブラリが記述されています。

pandas, numpy, scikit-learn, matplotlib , tqdmとかありました。
ローカルで使うちょっとしたツール作成なら現状でもできそう。

https://pyodide.org/en/stable/usage/packages-in-pyodide.html

matplotlib, pandasを使って棒グラフを表示させてみます。

```sample3.html

<head>
...
    <py-env>
        - pandas
        - matplotlib
    </py-env>
</head>
<body>
    <div id="bar"></div>
    <py-script>
import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame({
    'name': ['apple', 'orange', 'banana'],
    'store': ['store1', 'store1', 'store2'],
    'price': [100, 120, 200],
})
fig, ax = plt.subplots()
ax.bar(df['name'], df['price'])
pyscript.write('bar', fig)

    </py-script>
</body>
```

![スクリーンショット 2022-05-13 0.33.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/3b99c534-d571-426b-c0c1-b28fc923e48c.png)

なんかHTMLにちょこちょこ書くだけでかけると少し感動しますw

一応解説すると、

- `fig`がfigureつまり画像が入っている。
- `ax`がaxisつまり軸。`ax.bar(df['name'], df['price'])`でx軸にname, y軸にpriceの棒グラフ
- 画像のデータ`fig`をid="bar"のところに表示

試してないのでなんとも言えないですがディスク上のファイルから読み込むことも可能とのこと。
[.whl使った例](https://github.com/pyscript/pyscript/blob/main/pyscriptjs/examples/toga/freedom.html)


# htmlの中にPythonコード書くのが嫌なのでモジュールとしてインポート
htmlの中に書けるのは便利だけと、長くなってくるとシンタックスハイライトも効かないし書きにくいし、不便じゃね？
と思うのが当然なので自作のモジュールとしてimportしてスッキリさせることもできるとのこと。
コードは公式のサンプルを参照。

> https://github.com/pyscript/pyscript/blob/main/GETTING-STARTED.md#local-modules

```data.py
import numpy as np

def make_x_and_y(n):
    x = np.random.randn(n)
    y = np.random.randn(n)
    return x, y
```

同じディレクトリに`data.py`作成してimport。ランダムなデータを生成できるdata.pyを読み込む。

```.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
        - paths:
          - ./data.py
      </py-env>
    </head>

  <body>
    <h1>Let's plot random numbers</h1>
    <div id="plot"></div>
    <py-script output="plot">
import matplotlib.pyplot as plt
from data import make_x_and_y

x, y = make_x_and_y(n=1000)

fig, ax = plt.subplots()
ax.scatter(x, y)
fig
    </py-script>
  </body>
</html>
```

読み込み方は`paths:`を記述すること。そして、注意点としてモジュールで使っている`numpy`も`<py-env>`で読み込む必要あること。

# py-replで便利に対話形式で実行

```sample4.html
<body>
    <py-repl>
    </py-repl>
    <py-script>
def tax(n):
    return print(f'税込 {n*1.1}円')
    </py-script>
</body>
```
`<py-repl>`というのをpythonを入力できる画面が出せます。
notebookみたいですね。

![スクリーンショット 2022-05-13 2.09.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/5a055722-216b-bf50-de54-f3839e5bfb5d.png)

そして定義した関数を呼ぶことも可能です。ちょっとしたツールを作るのに最適な昨日かもしれません。


# 参考にして手を動かすといいかも
動かしながら体験してみるといいかも。

https://pyscript.net/examples/

作りたいのあったらコードもみながら作るといいかも

https://github.com/pyscript/pyscript/tree/main/pyscriptjs/examples

いい質問あったのでみてみるといいかも。

https://community.anaconda.cloud/c/tech-topics/pyscript/41

例えばcsvを自分のディスクから読み込めないなーと思ってたら答えあった。