Introduction
In this lab, you will learn how to create a simple menu using Matplotlib. The menu will contain a list of items, each of which can be selected by the user. The selected item will then trigger a callback function that will perform some action.
VM Tips
After the VM startup is done, click the top left corner to switch to the Notebook tab to access Jupyter Notebook for practice.
Sometimes, you may need to wait a few seconds for Jupyter Notebook to finish loading. The validation of operations cannot be automated because of limitations in Jupyter Notebook.
If you face issues during learning, feel free to ask Labby. Provide feedback after the session, and we will promptly resolve the problem for you.
Import Libraries
To get started, we need to import the necessary libraries. In this case, we need to import matplotlib.pyplot, matplotlib.artist, matplotlib.patches, and IdentityTransform from matplotlib.transforms.
import matplotlib.pyplot as plt
import matplotlib.artist as artist
import matplotlib.patches as patches
from matplotlib.transforms import IdentityTransform
Define ItemProperties class
Next, we define a ItemProperties class which will be used to set the properties for each menu item. We can set the font size, label color, background color, and alpha value for each item using this class.
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
Define MenuItem class
Now we define a MenuItem class which will be used to create each item in the menu. We pass the figure, label string, properties, hover properties, and on select callback function as parameters to this class. The MenuItem class inherits from the artist.Artist class.
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
## Setting the transform to IdentityTransform() lets us specify
## coordinates directly in pixels.
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) ## Will be updated later.
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):
"""
Update the hover status of event and return whether it was changed.
"""
b, _ = self.rect.contains(event)
changed = (b != self.hover)
if changed:
self.set_hover_props(b)
self.hover = b
return changed
Define Menu class
We also need to define a Menu class which will be used to create the menu. We pass the figure and list of menu items as parameters to this class.
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()
Create the Menu
Now we can create the menu. We create a new figure and adjust the left margin. Then we create a list of menu items and add them to the menu. We also define a callback function for each item which will print out the selected item.
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()
Summary
Congratulations! You have successfully created a simple menu using Matplotlib. You have learned how to create a MenuItem class, a Menu class, and how to define properties for each item. You have also learned how to create a callback function for each item that will perform some action.