はじめに
この実験では、Matplotlib を使って簡単なメニューを作成する方法を学びます。メニューには項目のリストが含まれ、各項目はユーザーによって選択できます。選択された項目は、何らかのアクションを実行するコールバック関数をトリガーします。
VM のヒント
VM の起動が完了したら、左上隅をクリックしてノートブックタブに切り替え、Jupyter Notebook を使って練習しましょう。
時々、Jupyter Notebook が読み込み終了するまで数秒待つ必要がある場合があります。Jupyter Notebook の制限により、操作の検証を自動化することはできません。
学習中に問題に遭遇した場合は、Labby にお問い合わせください。セッション後にフィードバックを提供してください。そうすれば、迅速に問題を解決します。
ライブラリのインポート
始めるには、必要なライブラリをインポートする必要があります。この場合、matplotlib.pyplot、matplotlib.artist、matplotlib.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クラスを定義します。このクラスには、グラフ、ラベル文字列、プロパティ、ホバー時のプロパティ、および選択時のコールバック関数をパラメータとして渡します。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 クラスを定義する
また、メニューを作成するために使用される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クラスを作成する方法、および各項目のプロパティを定義する方法を学びました。また、各項目に対して何らかのアクションを実行するコールバック関数を作成する方法も学びました。