Google Colabの表示をパワーアップ!初学者のためのIPython.display活用ガイド

Google Colab(以下Colab)を使っていると、画像表示は比較的簡単なのに、標準出力標準エラーでのメッセージ表示は少し前時代的に感じていました🤔前回の記事ではtqdmライブラリを使ってプログレスバーの表示にチャレンジしましたが、他の部分もっと見栄えを良くする方法についても検索していました。

また、ColabではGPU処理のセッションが切断されないようにするためにprint()文を多用していますが、これが多すぎると表示エリアを何度もスクロールして確認する必要があり、少々不便です。

参照

uepon.hatenadiary.com uepon.hatenadiary.com

そこで何か良い方法はないかと探していたところ、IPython(Interactive Python)に行き当たりました。

参考:からあげさんのブログ

karaage.hatenadiary.jp

ColabIPython(Interactive Python)環境は、Jupyter NotebookをベースとしたPythonの対話型実行環境です。ColabではIPythonの機能を全て活用できますが、特にIPython.displayモジュールの機能が非常に便利に感じたので、詳しく調べてみることにしました。

ColabIPython.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モジュールには機能別に以下のようなクラスが存在します。この中で使用するのはやはりHTMLImageでしょうか。もし、Colabのノートブックを共有して自習をしてもらうのであれば、Videoを使用してYoutube動画を表示するのも効果があると思います。また、JSONの整形に関しても便利そうです。

IPython.displayのクラス抜粋

  1. HTML - HTMLコードを表示
  2. Image - 画像ファイルやURL、バイトデータから画像を表示
  3. Audio - 音声ファイルを再生可能な形で表示
  4. Video - ビデオファイルを再生可能な形で表示
  5. Javascript - JavaScriptコードを実行
  6. Markdown - Markdownテキストをレンダリング
  7. JSON - JSONデータを整形して表示
  8. Latex - LaTeX数式をレンダリング
  9. SVG - SVGレンダリング
  10. 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.displaydisplay()に複数のデータを与えることで、表示にも反映することができます。

from IPython.display import display, HTML, Image

display(HTML('<h2>複数の出力</h2>'), 
        Image('image1.jpg'), 
        Image('image2.jpg'))

JavaScriptを含むHTMLの表示

Javascriptを含むような処理を持つHTMLの表示を行うことも可能です。以下はセションの継続をHTML側でできないかと考えたコードになります。一応、こちらでもセッションの継続はできていました。

参考 セッション継続

uepon.hatenadiary.com

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. セルの出力を保存

セルの実行によって、PythonMatplotlibライブラリを使ってグラフを作成し、その画像ファイルを保存した後、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()

おわりに

今回はColabIPython.displayモジュールを使用した表示方法を実験してみました。これでprint()文による残念な出力😢から、HTMLやJavaScriptを活用した見やすい表示方法へと進化させることができます🤩

データの可視化や処理状況の確認がより楽になり、共有することで教材的に活用することも可能な点が可能性を感じます。