Google ColaboratoryのPythonでHTMLおよびJavaScriptを動かす

Google ColaboratoryのPythonでHTMLとJSを動かす ツール

今回は、Google Colaboratoryを使ってPythonプログラミング上でHTMLやJavaScriptを動かすことを試してみました。
Jupyter Notebook上の1セル内で、PythonとHTMLおよびJavaScriptが共存できて、Pythonから引数をJavaScriptに渡して関数を実行させることができたんです。
そして、JavaScriptからPythonへデータを返すということもできました。

スポンサーリンク

これができれば、Jupyter Notebook上でESP32やM5Cameraからのデータをリアルタイムで表示させることができるし、Webと連携して機械学習させることができると思われます。

本当は、前回記事で述べたように今回はGoogle ColaboratoryにM5Cameraからの画像をリアルタイム表示させる方法を紹介する予定だったのですが、まず、その前段階を説明する必要がありました。

では、自分が知り得た情報で説明したいと思います。

なお、私はGoogle ColaboratoryやJupyter Notebookは使い始めたばかりで、PythonもJavaScriptも独学の素人です。
何か間違いがありましたら、コメント投稿等でご連絡いただけると助かります。

    【目次】

  1. (事前準備)Google Colaboratory を使えるようにしておく
  2. IPythonでHTMLを表示させる
  3. IPythonで<style>~</style>で囲ったCSSも表示できた
  4. IPythonでJavaScript込みのHTMLでも問題無く動いた
  5. PythonとJavaScript相互に値を受け渡して動かしてみる実験(eval_js使用)
  6. まとめ

(事前準備)Google Colaboratory を使えるようにしておく

以下の記事を参照して、Google Colaboratoryを使える状態にしておきます。

ディープラーニングのお勉強~その8。Google ColaboratoryでPythonプログラミングして機械学習してみた~

IPythonでHTMLを表示させる

今回、IPythonというツールを初めて使ってみました。IPythonは正直よく知らないのですが、Pythonを更に強化したツールらしいです。
これを使えば、Pythonプログラミング上でHTMLやJavaScriptを動かすことができます。

まず、簡単なHTMLを表示させてみます。
以下のコードです。

import IPython
from IPython.display import display, HTML

htm = HTML('''\
<div>
  <b>Hello World!</b>
  <p>こんちは!</p>
</div>
''')

display(htm)

【実行結果】

HTMLテキストだけの表示

Jupyter NotebookのIPythonでHTMLを動かす

実行させると、こんな感じですぐ下に簡単なHTMLテキストは問題無く表示されました。

HTMLコードを改行付きで記述したい場合、三連引用符(トリプルクォーテーション)「’’’」でHTMLを囲えば良いわけです。

IPythonで<style>~</style>で囲ったCSSも表示できた

では、今度はWeb表示では欠かせないCSSをHTMLに入れ込んでも大丈夫なのかテストしてみます。
こんな感じです。

import IPython
from IPython.display import display, HTML

htm = HTML('''
<style>
  .color1{ color: green; }
  .color2{ color: #fff; background-color: #f00; }
</style>
<div>
  <div class='color1'>Hello World!</div>
  <b class='color2'>こんちは!</b>
</div>
''')

display(htm)

【実行結果】

CSS込みのHTML表示

IPythonでCSS込みのHTML表示

このように、<style>~</style>で囲ったCSSも問題無く動きました。

IPythonでJavaScript込みのHTMLでも問題無く動いた

では、HTMLにJavaScriptを埋め込んで、IPythonで動くかどうか試してみます。
Canvas要素もよく使うので試してみます。
こんな感じです。

import IPython
from IPython.display import display, HTML

htm = HTML('''
<style>
  .box{border: 1px solid}
</style>
<p>Canvas 画像水平反転</p>
<div>
  <img id='img' class='box' src='https://xxxxxxxx/xxxxx.jpg'>
  <canvas id='canvas' class='box'></canvas>
</div>
<div>
  <button id='btn_start' onclick='onButton()'>Flip Image ON</button>
</div>
<script type='text/javascript'>
  const img = document.getElementById('img');
  img.width = 160;
  img.height = 120;
  //オリジン画像の幅、高さを取得
  const origin_img_w = img.naturalWidth,
        origin_img_h = img.naturalHeight;

  const canvas_w = 200, canvas_h = 80;
  const canvas = document.getElementById('canvas');
  ctx = canvas.getContext('2d');
  canvas.width = canvas_w;
  canvas.height = canvas_h;

  function onButton(){
    //画像左右反転
    ctx.translate(canvas.width, 0);
    ctx.scale(-1, 1);
    ctx.drawImage(img, 0, 0, origin_img_w, origin_img_h, 0, 0, canvas_w, canvas_h);
  }
</script>
''')

display(htm)

【実行結果】

JavaScript込みのHTML表示

IPythonでJavaScript込みのHTML表示

img要素のsrcに自分の好きなサイトの画像URLを貼り付ければ、このように外部サイトから画像が取得できます。
そして、「Flip Image ON」ボタンを押すと、画像が水平反転されて横長に引き伸ばされて表示されると思います。
素晴らしいですね。
何でもできそうですね。

PythonとJavaScript相互に値を受け渡して動かしてみる実験(eval_js使用)

では、今回の最大の目的、PythonプログラミングからJavaScript関数を実行させてみます。
Pythonで計算させた値をJavaScript内の関数に渡して、HTMLのCanvas要素画像を動かす実験です。
そして、逆にJavaScriptで得た数値をPythonに返すこともやってみます。
以下のコードです。

import IPython
import time
from IPython.display import display, HTML
from google.colab.output import eval_js

def htm_source(xi = 0):
  htm2 = HTML('''
    <div>X座標 <span id='text'>0</span></div>
    <canvas id="canvas"></canvas>
    <script>
      const text = document.getElementById('text'),
            canvas = document.getElementById('canvas'),
            ctx = canvas.getContext('2d');
      ctx.fillStyle = '#0ff';
      var r = 0;

      function circle(x){
        if(x > 0){
           ctx.clearRect(x - 10, 0, 60, 60);
        }
        ctx.beginPath();
        ctx.arc(x + 30, 30, 30, r, 2 * Math.PI);  //中心(30, 30)の開始位置に半径30pxの円
        ctx.fill();
        text.innerHTML = x + 60;
        r += 0.5;
        return r; //eval_jsへの返り値になる
      }
      circle(0);
    </script>
  ''')
  display(htm2) # HTMLをセルに表示(※インデント必要)
###########################################
#ここからPythonでJavaScriptを動かす実行文
htm_source(0)
# 3秒待機
time.sleep(3)
r = 0
for i in range(10, 100, 10):
  # eval_jsで、HTML内のJavaScript関数に直接アクセス
  data = eval_js('circle({})'.format(i))
  print(data, end=', ')
  time.sleep(0.5)

【実行結果】

IPythonによるJavaScriptアニメ

IPythonとJavaScriptの値の相互受け渡しによるアニメ

やったぜ!
この動画はGIF動画の無限ループですが、実際の実行結果では1回しかアニメーションしません。
Pythonで計算した値をJavaScriptの関数に渡して、円を動かしています。
そして、下の欄では、JavaScriptから返ってきた値をPythonで表示させています。
まさに、PythonとJavaScriptとHTMLの融合ですね。
これ、すごいですよね。
さすがGoogleですね。
それに、Jupyter Notebookもスゴイし、なにより、ブラウザが凄いなと思いましたね。

ここでのポイントは、eval_jsという関数で、Pythonプログラミング上からJavaScript内の関数に直接アクセスして実行できることです。
formatで、JavaScript内の関数へ値を渡すことができます。
eval_jsについては、Google公式の以下のドキュメントを参考にしてください。
https://colab.research.google.com/notebooks/snippets/advanced_outputs.ipynb

個人的にいろいろ試してみたのですが、eval_jsで渡す引数は、残念ながら1つのみのようです。どなたか複数の引数の渡し方があれば教えてください。
因みに、eval_jsを複数回使えば、複数の引数を渡せないことは無いです。
また、返り値は、渡した先のJavaScript関数でreturnすれば、Python上に返って来ます。

ところで、個人的にハマった点というか、注意しなければならない点がありました。
Pythonの関数定義はdefですが、その適用範囲はインデント(字下げ)部分です。
上記のコードでいうと、6行~31行までです。
私はこのインデントをすっかり忘れて、31行のdisplay関数を先頭から記述してしまい、うまく動かなくてハマったことがありました。
私は長らくArduino IDEでC言語を使っていて、JavaScriptに関してはC言語と似ているのであまり問題にならなかったのですが、Pythonはかなり異なる部分が多く、戸惑いました。
今回のようにPythonとJavaScriptが共存している場合、ちょっとでも注意を怠ると単純ミスで動かなくなるので注意が必要ですね。

と、いうことで、とりあえず、ここまでできればPython初心者の私には十分です。
これで、Google Colaboratory上でESP32やM5Cameraからのデータを使った機械学習ができそうです。

まとめ

以上、Google ColaboratoryのPythonプログラミングでHTMLおよびJavaScriptを動かす方法でした。

Jupyter Notebookの1セル内にPythonとHTMLおよびJavaScriptが共存して実行できるというのは不思議な感じですね。
これができれば、Google ColaboratoryでESP32やM5StackおよびM5Cameraからのデータをやり取りし、機械学習ができそうです。

ということで、今回はここまでです。
次回はいよいよM5Cameraからの映像をJupyter Notebook上にリアルタイム表示させる方法を紹介したいと思います。

コメント

タイトルとURLをコピーしました