matplotlib 3.5.1

>>> """
====
Menu
====

"""
... 
... import matplotlib.artist as artist
... import matplotlib.patches as patches
... import matplotlib.pyplot as plt
... from matplotlib.transforms import IdentityTransform
... 
... 
... 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
... 
... 
... 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
... 
... 
... 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()
...