Thanks to visit codestin.com
Credit goes to github.com

Skip to content

The busy cursor is annoying in some instances #9546

Closed
@ronaldnie

Description

@ronaldnie

Bug report

Bug summary

The new busy cursor in 2.1.0 can be annoying when the rendering does not take long. I have a simple implementation of a menu based on Legend which becomes slow when hovering switches to a different menu item.

Code for reproduction

# -*- coding: utf-8 -*-
"""
A simple menu based on matplotlib figure.legend
"""
import matplotlib.pyplot as plt
import matplotlib.lines as mline
from matplotlib.text import Text
from math import ceil
from PyQt5 import QtWidgets   # , QtGui, QtCore

class Menu:
    '''a simple matplotlib menu based on Legend
    
    Steps:
        (1) menu = Menu()
        (2) use menu as a decorator to add menu items
        (3) call create_menu(fig, ncol) to actually create the menu
        (4) menu.add_qt_toolbar_button()
    '''
    def __init__(self):
        self.label_funcs = {}  # 
        
    def __call__(self, label):
        'may need to refine to distinguish function and method'
        def wrap(f):
            def wrapped_f(*args):
                f(*args)

            self.add_menu_item(label, wrapped_f)
            return wrapped_f
        return wrap    
    
    def add_menu_item(self, label, func):
        'just collect, because Legend does not allow incrementally add entries'
        self.label_funcs[label] = func
        
    # the following functions needs figure
    def create_menu(self, fig, ncol):
        'create menu'
        self.fig = fig
        dummy = mline.Line2D((0, 1), (0, 1) )
        self.num = num = len(self.label_funcs)
        self.ncol = ncol
        self.nrow = nrow = ceil(num/ncol)

        self.leg = leg = fig.legend([dummy]*num, 
                     self.label_funcs.keys(),
             loc='upper right',
             ncol=ncol,  
             borderaxespad=0., 
             handlelength=0, handleheight=0,
             fancybox=True, shadow=True,
             framealpha=0.3,
             # title='Menu',
             )
        leg.draggable(True)  
        leg.set_visible(True)

        for t in leg.get_texts():
            t.set_picker(5)  # 5 pts tolerance

        # inner function to create_menu
        last_pick = None
        def onpick(event):
            nonlocal last_pick
            if not isinstance(event.artist, Text):
                return
           
            # restore lp
            if last_pick:
                last_pick.set_bbox(None)

            # set new pick
            last_pick = legtext = event.artist
            label = legtext.get_text()
            legtext.set_backgroundcolor('#87CEEBB0')
            self.label_funcs[label]()
            fig.canvas.draw_idle()
        
        self.cid_pick = fig.canvas.mpl_connect('pick_event', onpick)
        
        last_hover = None
        def onhover(event):
            nonlocal last_hover
            if not self.leg.get_visible(): return
            over, junk = self.leg.contains(event)
            if not over: return
            
            x0, y0, width, height = self.leg.get_window_extent().bounds
            idx = int((event.x - x0)/width * self.ncol)
            idy = int(self.nrow - (event.y - y0)/height * self.nrow)
            id = idx * self.nrow + idy
            
            t = self.leg.get_texts()[id]
            
            if t == last_hover:
                return
            else:
                if last_hover:
                    last_hover.set_alpha(1.0)
                last_hover = t
                t.set_alpha(0.3)
                    
            fig.canvas.draw_idle()
         
        # matplotlib 2.1.0 busy cursor makes hovering annoying
        self.cid_hover = fig.canvas.mpl_connect('motion_notify_event', onhover)

    def add_qt_toolbar_button(self):             
        # add a toolbar button to toggle the menu
        # inner function for toolbutton
        def onoff(label):
            if self.leg.get_visible():
                self.leg.set_visible(False)
            else:
                self.leg.set_visible(True)
            fig.canvas.draw_idle()
            
        toolbar = fig.canvas.toolbar
        mtb = QtWidgets.QToolButton(toolbar)
        style = QtWidgets.QStyle
        stdicon = mtb.style().standardIcon
        mtb.setIcon(stdicon(style.SP_VistaShield))
        #mtb.setIconSize(QtCore.QSize(48, 48))
        mtb.setText('Menu')
        mtb.setToolTip('Menu')
        toolbar.addWidget(mtb)
        mtb.clicked.connect(onoff)
        
if __name__ == '__main__':
    import numpy as np
    
    menu = Menu()
    
    fig, ax = plt.subplots()
    plt.subplots_adjust(bottom=0.2)
    t = np.arange(0.0, 1.0, 0.001)
    s = np.sin(2*np.pi*5*t)
    line, = plt.plot(t, s, lw=2)

    
    @menu('Red')
    def abc():
        line.set_color('red')
    
    @menu('Blue')
    def cde():
        line.set_color('blue')

    @menu('Black')
    def fgh():
        line.set_color('black')

    @menu('Thick')
    def f1():
        line.set_linewidth(5)

    @menu('3 pts')
    def f2():
        line.set_linewidth(3)

    @menu('Thin')
    def f3():
        line.set_linewidth(1)
        
    @menu('Dash')
    def fd():
        line.set_linestyle('--')

    @menu('Solid')
    def fs():
        line.set_linestyle('-')     
        
    @menu('Dotted')
    def fo():
        line.set_linestyle(':')  
        
    menu.create_menu(fig, ncol=3)
    menu.add_qt_toolbar_button()
       
    plt.show()

Expected outcome

fig.canvas.draw and draw_idle have a time shreshold to show busy cursor.

Matplotlib version

  • Operating system: Window 10
  • Matplotlib version: 2.1.0
  • Matplotlib backend (print(matplotlib.get_backend())): Qt5
  • Python version: 3.6.2
  • Jupyter version (if applicable):
  • Other libraries:

Used conda to updated to the current matploblib, probably through some default channel because I did not specify a channel.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions