Matplotlib を使って簡単なメニューを作成する

PythonPythonBeginner
今すぐ練習

This tutorial is from open-source community. Access the source code

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

この実験では、Matplotlibを使って簡単なメニューを作成する方法を学びます。メニューには項目のリストが含まれ、各項目はユーザーによって選択できます。選択された項目は、何らかのアクションを実行するコールバック関数をトリガーします。

VMのヒント

VMの起動が完了したら、左上隅をクリックしてノートブックタブに切り替え、Jupyter Notebookを使って練習しましょう。

時々、Jupyter Notebookが読み込み終了するまで数秒待つ必要がある場合があります。Jupyter Notebookの制限により、操作の検証を自動化することはできません。

学習中に問題に遭遇した場合は、Labbyにお問い合わせください。セッション後にフィードバックを提供してください。そうすれば、迅速に問題を解決します。

ライブラリのインポート

始めるには、必要なライブラリをインポートする必要があります。この場合、matplotlib.pyplotmatplotlib.artistmatplotlib.patches、およびmatplotlib.transformsからIdentityTransformをインポートする必要があります。

import matplotlib.pyplot as plt
import matplotlib.artist as artist
import matplotlib.patches as patches
from matplotlib.transforms import IdentityTransform

ItemPropertiesクラスを定義する

次に、各メニュー項目のプロパティを設定するために使用されるItemPropertiesクラスを定義します。このクラスを使用することで、各項目のフォントサイズ、ラベル色、背景色、およびアルファ値を設定できます。

class ItemProperties:
    def __init__(self, fontsize=14, labelcolor='black', bgcolor='yellow',
                 alpha=1.0):
        self.fontsize = fontsize
        self.labelcolor = labelcolor
        self.bgcolor = bgcolor
        self.alpha = alpha

次に、メニュー内の各項目を作成するために使用されるMenuItemクラスを定義します。このクラスには、グラフ、ラベル文字列、プロパティ、ホバー時のプロパティ、および選択時のコールバック関数をパラメータとして渡します。MenuItemクラスはartist.Artistクラスから継承されています。

class MenuItem(artist.Artist):
    padx = 5
    pady = 5

    def __init__(self, fig, labelstr, props=None, hoverprops=None,
                 on_select=None):
        super().__init__()

        self.set_figure(fig)
        self.labelstr = labelstr

        self.props = props if props is not None else ItemProperties()
        self.hoverprops = (
            hoverprops if hoverprops is not None else ItemProperties())
        if self.props.fontsize!= self.hoverprops.fontsize:
            raise NotImplementedError(
               'support for different font sizes not implemented')

        self.on_select = on_select

        ## IdentityTransform()に変換を設定することで、
        ## 座標を直接ピクセル単位で指定できます。
        self.label = fig.text(0, 0, labelstr, transform=IdentityTransform(),
                              size=props.fontsize)
        self.text_bbox = self.label.get_window_extent(
            fig.canvas.get_renderer())

        self.rect = patches.Rectangle((0, 0), 1, 1)  ## 後で更新されます。

        self.set_hover_props(False)

        fig.canvas.mpl_connect('button_release_event', self.check_select)

    def check_select(self, event):
        over, _ = self.rect.contains(event)
        if not over:
            return
        if self.on_select is not None:
            self.on_select(self)

    def set_extent(self, x, y, w, h, depth):
        self.rect.set(x=x, y=y, width=w, height=h)
        self.label.set(position=(x + self.padx, y + depth + self.pady/2))
        self.hover = False

    def draw(self, renderer):
        self.rect.draw(renderer)
        self.label.draw(renderer)

    def set_hover_props(self, b):
        props = self.hoverprops if b else self.props
        self.label.set(color=props.labelcolor)
        self.rect.set(facecolor=props.bgcolor, alpha=props.alpha)

    def set_hover(self, event):
        """
        イベントのホバー状態を更新し、変更されたかどうかを返します。
        """
        b, _ = self.rect.contains(event)
        changed = (b!= self.hover)
        if changed:
            self.set_hover_props(b)
        self.hover = b
        return changed

また、メニューを作成するために使用されるMenuクラスを定義する必要があります。このクラスには、グラフとメニュー項目のリストをパラメータとして渡します。

class Menu:
    def __init__(self, fig, menuitems):
        self.figure = fig

        self.menuitems = menuitems

        maxw = max(item.text_bbox.width for item in menuitems)
        maxh = max(item.text_bbox.height for item in menuitems)
        depth = max(-item.text_bbox.y0 for item in menuitems)

        x0 = 100
        y0 = 400

        width = maxw + 2*MenuItem.padx
        height = maxh + MenuItem.pady

        for item in menuitems:
            left = x0
            bottom = y0 - maxh - MenuItem.pady

            item.set_extent(left, bottom, width, height, depth)

            fig.artists.append(item)
            y0 -= maxh + MenuItem.pady

        fig.canvas.mpl_connect('motion_notify_event', self.on_move)

    def on_move(self, event):
        if any(item.set_hover(event) for item in self.menuitems):
            self.figure.canvas.draw()

メニューを作成する

これで、メニューを作成できます。新しいグラフを作成し、左マージンを調整します。次に、メニュー項目のリストを作成してメニューに追加します。また、各項目に対してコールバック関数を定義し、選択された項目を表示します。

fig = plt.figure()
fig.subplots_adjust(left=0.3)
props = ItemProperties(labelcolor='black', bgcolor='yellow',
                       fontsize=15, alpha=0.2)
hoverprops = ItemProperties(labelcolor='white', bgcolor='blue',
                            fontsize=15, alpha=0.2)

menuitems = []
for label in ('open', 'close','save','save as', 'quit'):
    def on_select(item):
        print('you selected %s' % item.labelstr)
    item = MenuItem(fig, label, props=props, hoverprops=hoverprops,
                    on_select=on_select)
    menuitems.append(item)

menu = Menu(fig, menuitems)
plt.show()

まとめ

おめでとうございます!Matplotlibを使って簡単なメニューを成功裏に作成しました。MenuItemクラスとMenuクラスを作成する方法、および各項目のプロパティを定義する方法を学びました。また、各項目に対して何らかのアクションを実行するコールバック関数を作成する方法も学びました。