Google Colab(以下Colab)を使っていると、画像表示は比較的簡単なのに、標準出力や標準エラーでのメッセージ表示は少し前時代的に感じていました🤔前回の記事ではtqdmライブラリを使ってプログレスバーの表示にチャレンジしましたが、他の部分もっと見栄えを良くする方法についても検索していました。
また、ColabではGPU処理のセッションが切断されないようにするためにprint()文を多用していますが、これが多すぎると表示エリアを何度もスクロールして確認する必要があり、少々不便です。
参照
uepon.hatenadiary.com uepon.hatenadiary.com
そこで何か良い方法はないかと探していたところ、IPython(Interactive Python)に行き当たりました。
参考:からあげさんのブログ
ColabのIPython(Interactive Python)環境は、Jupyter NotebookをベースとしたPythonの対話型実行環境です。ColabではIPythonの機能を全て活用できますが、特にIPython.displayモジュールの機能が非常に便利に感じたので、詳しく調べてみることにしました。
ColabのIPython.displayについて
IPython.displayは、Colabを含む**Jupyter Notebook環境で使用できる表示機能のモジュールです。このモジュールを使用すると、テキストのみならずHTML、画像、音声、ビデオなどの様々な種類のデータを豊かな形式で表示できます。
簡単な使用例
以下は簡単な使用例になります。output部分にHTMLの表示と画像が表示でき、これだけでも割と使えそうな雰囲気ですね。
from IPython.display import display, HTML, Image # HTMLを表示 display(HTML('<h1>これはHTMLです</h1>')) # 画像を表示 display(Image('image.png')) # Colabのcontentディレクトリに画像を格納すること

Pythonの変数の値をHTML内への表示
処理はPython、表示はHTMLを使用するとなるとその連携方法も気になります。
連携した表示を行うのであれば、f文字列(フォーマット文字列)を使用するのが便利です。IPython.displayモジュールに与える引数とすれば解決できます。
HTML内でのPython変数の表示例
from IPython.display import display, HTML # 変数の定義 name = "田中太郎" age = 30 scores = [85, 92, 78] # f文字列でHTMLに変数を埋め込む html_content = f""" <div style="background-color: #f0f0f0; padding: 15px; border-radius: 10px;"> <h2>ユーザー情報</h2> <p>名前: <b>{name}</b></p> <p>年齢: <b>{age}歳</b></p> <p>スコア: <b>{scores}</b></p> <p>平均点: <b>{sum(scores)/len(scores):.1f}点</b></p> </div> """ # 表示 display(HTML(html_content))

IPython.displayモジュールの主要なクラス
IPython.displayモジュールには機能別に以下のようなクラスが存在します。この中で使用するのはやはりHTMLやImageでしょうか。もし、Colabのノートブックを共有して自習をしてもらうのであれば、Videoを使用してYoutube動画を表示するのも効果があると思います。また、JSONの整形に関しても便利そうです。
IPython.displayのクラス抜粋
HTML- HTMLコードを表示Image- 画像ファイルやURL、バイトデータから画像を表示Audio- 音声ファイルを再生可能な形で表示Video- ビデオファイルを再生可能な形で表示Javascript- JavaScriptコードを実行Markdown- MarkdownテキストをレンダリングJSON- JSONデータを整形して表示Latex- LaTeX数式をレンダリングSVG- SVGのレンダリングIFrame- IFrameによる外部コンテンツの埋め込み
IPython.displayクラスの例
pandasのデータフレームの表示
pandasで使用するデータフレームをカラー付きで表示することも可能です。 以下の箇所でpandasのデータフレームにスタイルを適用し、
df.style.background_gradient(cmap='viridis')の処理
- .styleアクセサを使ってスタイリングオブジェクトに変換
- .background_gradient(cmap='viridis')で数値に基づいた背景色のグラデーションを適用
- 'viridis'はMatplotlibのカラーマップで、数値の大小を色の変化で表現(この場合は小さい値から大きい値にかけて、青から黄緑、黄色へと変化)
その後、その色設定をIPython.displayでレンダリングしています。
import pandas as pd from IPython.display import display, HTML df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}) styled_df = df.style.background_gradient(cmap='viridis') display(styled_df)

インタラクティブなウィジェット
Colab上にUIのような機能をつけることも可能です。以下のコードではスライダーバーのUIを追加しています。
from IPython.display import display import ipywidgets as widgets slider = widgets.IntSlider(min=0, max=100) display(slider) # 後続のセルにてスライダーの現在の値を取得 current_value = slider.value print(f"現在のスライダー値: {current_value}")

プログレスバーの表示
tqdmライブラリを使用することで簡単にプログレスバーを使用できますが。 ループ処理以外でプログレスバーを表示するなんてことも可能です。 シンプルな表示なので使い所が限られますが、ダッシュボードの一部で使用できるかもしれません。
from IPython.display import display import ipywidgets as widgets from time import sleep progress = widgets.FloatProgress(value=0.0, min=0.0, max=1.0) display(progress) for i in range(10): progress.value = (i + 1) / 10 sleep(0.5)

複数の出力を一度に表示
IPython.displayのdisplay()に複数のデータを与えることで、表示にも反映することができます。
from IPython.display import display, HTML, Image display(HTML('<h2>複数の出力</h2>'), Image('image1.jpg'), Image('image2.jpg'))

JavaScriptを含むHTMLの表示
Javascriptを含むような処理を持つHTMLの表示を行うことも可能です。以下はセションの継続をHTML側でできないかと考えたコードになります。一応、こちらでもセッションの継続はできていました。
参考 セッション継続
from IPython.display import display, HTML display(HTML(""" <div style="padding: 10px; border: 1px solid #ddd; border-radius: 5px; background-color: #f8f9fa;"> <div> <span style="font-weight: bold;">ステータス:</span> <span id="status" style="color: green;">セッション継続処理実行中</span> </div> <div> <span style="font-weight: bold;">最終処理時刻:</span> <span id="lastUpdate"></span> </div> </div> <script> let counter = 0; function updateOutput() { const lastUpdate = document.getElementById('lastUpdate'); const counterElement = document.getElementById('counter'); // 最終更新時刻を更新 lastUpdate.innerHTML = new Date().toLocaleString(); // カウンターをインクリメント counter++; counterElement.innerHTML = counter; // Colabの接続を維持 document.querySelector("colab-toolbar-button#connect")?.click(); } // 1分ごとに実行 setInterval(updateOutput, 60*1000); updateOutput(); // 初回実行 </script> """))

応用テクニック
更に使えそうな機能がないか探してみました。
1. clear_output() - 出力をクリアして更新する
一度表示したものをクリア(削除)し、改めて描画し直すものです。以下の例ではカウントの値が0-9ま表示されますが、一回毎にクリアされるのでループ最後の9のみの表示が行われた状態で終了します。
clear_output()の引数のwaitには以下の意味があります。
wait=Falseの場合 … 即座に出力をクリアし、次の表示を行います。これにより、前の出力が消えた後に新しい出力が表示されます。つまり、画面がチラつく可能性があります。wait=Trueの場合(デフォルト) … 新しい出力が準備できるまで待ってから、前の出力をクリアします。これにより、出力のチラつきを防止できます。
from IPython.display import clear_output, display import time for i in range(10): clear_output(wait=True) display(f"カウント: {i}") time.sleep(1)

2. display(Javascript()) - Pythonの中でJavaScriptを実行する
HTMLの中でJavascriptを動作させることができるのであれば、Javascriptの文字列も動作させることもできるかなと調べたところ、display(Javascript())で動作させることができました。
注意:Jupyter Notebookには同様の機能で、display_javascript()がありますが、Colabではサポートされていません。
from IPython.display import Javascript, display js_code = """ console.log('これはJavaScriptから実行されています'); """ display(Javascript(js_code))
実行結果はconsole.log()を使用しているため、デバッグコンソールで動作を確認することになります。

3. セルの出力を保存
セルの実行によって、PythonのMatplotlibライブラリを使ってグラフを作成し、その画像ファイルを保存した後、Colab上でダウンロードできるリンクを表示しています。
from IPython.display import display, FileLink import matplotlib.pyplot as plt plt.plot([1, 2, 3]) plt.savefig('my_plot.png') display(FileLink('my_plot.png'))

4.SVGのレンダリング
SVGのコードを使用すればSVGの画像を表示(レンダリング)も可能です。
from IPython.display import SVG svg_code = """ <svg width="100" height="100"> <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" /> </svg> """ display(SVG(svg_code))

5. IFrameによる外部コンテンツの埋め込み
HTMLをIFrameの形で結果に埋め込むことも可能です。Youtubeの動画埋め込みもできるので、ノートブックを共有してカリキュラムのような形にもできるのが便利ですね。
from IPython.display import IFrame # YouTubeビデオの埋め込み youtube_embed = IFrame("https://www.youtube.com/embed/F50bCrlTbIs", width=560, height=315) display(youtube_embed) # Webページの埋め込み webpage_embed = IFrame("https://www.irasutoya.com/", width=560, height=315) display(webpage_embed)

6. プログレスバーとステータス表示の組合わせ
このコードでは、3つの処理(データ読み込み・モデル訓練・結果検証)の進捗をリアルタイムで表示しています。 各処理が異なるタイミングと速度で進行する様子を、プログレスバーを使って可視化しています。
from IPython.display import display import ipywidgets as widgets import time # 複数プロセスの進捗を表示 progress_bars = {} for process in ['データ読み込み', 'モデル訓練', '結果検証']: progress_bars[process] = widgets.FloatProgress( value=0, min=0, max=100, description=process, bar_style='info', orientation='horizontal' ) display(progress_bars[process]) # 進捗の更新シミュレーション for i in range(101): if i < 70: progress_bars['データ読み込み'].value = i if 30 <= i < 90: progress_bars['モデル訓練'].value = (i - 30) * 1.5 if i >= 60: progress_bars['結果検証'].value = (i - 60) * 2.5 time.sleep(0.05)

7. テーブル表示のHTMLによるカスタマイズ
Pythonで作成されたデータをHTMLに格納することで表示を見やすくできます。前述のPandasのデータフレームの機能ではなくHTML側のクラスや属性で表示が代えられるので、こちらのほうが可視化の自由度は上がります。
from IPython.display import HTML import pandas as pd df = pd.DataFrame({ '名前': ['田中', '佐藤', '鈴木'], '年齢': [25, 30, 28], '得点': [85, 92, 78] }) # HTMLでスタイリングされたテーブル html_table = """ <style> .styled-table { border-collapse: collapse; margin: 25px 0; font-size: 0.9em; font-family: sans-serif; min-width: 400px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.15); } .styled-table thead tr { background-color: #009879; color: #ffffff; text-align: left; } .styled-table th, .styled-table td { padding: 12px 15px; } .styled-table tbody tr { border-bottom: 1px solid #dddddd; } .styled-table tbody tr:nth-of-type(even) { background-color: #f3f3f3; } </style> """ # HTMLテーブルを生成 html_table += df.to_html(classes='styled-table', index=False) display(HTML(html_table))
8. 地理データの表示(foliumとの連携)
foliumは、Pythonで地図を生成・表示ができるライブラリで、Leaflet.jsをバックエンドにしているため、Colab上で動的なマップを表示できます。このライブラリを連携することで地図の表示も可能です。
from IPython.display import display import folium # 地図を作成 m = folium.Map(location=[35.6895, 139.6917], zoom_start=12) # マーカーを追加 folium.Marker( location=[35.6895, 139.6917], popup='東京', icon=folium.Icon(color='red', icon='info-sign') ).add_to(m) # 表示 display(m)

9. リアルタイムでのグラフ更新
グラフの変化の様子をアニメーション(ぱらぱら漫画といったほうがあっている)で表示することが出来ます。 ちらつきが多いので、動きの少ないグラフのほうが向いていると思います。
from IPython.display import clear_output import matplotlib.pyplot as plt import numpy as np import time plt.figure(figsize=(10, 6)) for i in range(50): # 平均値が徐々に変化する正規分布データを生成 data = np.random.normal(i/10, 1, 1000) # 出力をクリアして新しいプロットを表示 clear_output(wait=True) plt.hist(data, bins=30) plt.title(f'Real-Time Updating Histogram (Iteration {i+1})') plt.xlim(-5, 10) plt.ylim(0, 200) plt.grid(True) display(plt.gcf()) time.sleep(0.2) plt.clf()


おわりに
今回はColabでIPython.displayモジュールを使用した表示方法を実験してみました。これでprint()文による残念な出力😢から、HTMLやJavaScriptを活用した見やすい表示方法へと進化させることができます🤩
データの可視化や処理状況の確認がより楽になり、共有することで教材的に活用することも可能な点が可能性を感じます。