Issue 1:
Bug report

Hi,

I have a notebook that allows to draw geometrical shapes using mouse, and buttons from matplotlib.widgets.

After upgrade from matplotlib 3.1.1 to 3.3.1, my interactive plot has become excruciatingly slow.

It used to work fine with "%matplotlib notebook" under matplotlib 3.3.1.

Accessorily, %matplotlib notebook works for me only in chrome with 3.3.1, not firefox anymore.

However, the code works with also with "%matplotlib widgets" and "%matplotlib ipympl"

on both firefox and chrome, but it is slow in all cases with version matplotlib 3.3.1.

I can revert to matplotlib 3.1.1 but that considerably restricts my options due to lack of compatibility with other modules I'd like to use jointly (in particular pygimli).

Any help appreciated

Code for reproduction

# Paste your code here
####
# Here is the code example. This is what it does:
# allows to draw polygons with mouse clicks
# automatically labels the polygons each time "next poly" button is clicked
# allows to delete any of the polygons by specifying the label in inteactive text box and clickin g butto "delete poly"
####

# first, import modules:
import numpy as np
%matplotlib notebook
import matplotlib.pyplot as plt
from matplotlib.widgets import Button, TextBox
from operator import itemgetter

##################

# second, define a few functions:
def onclick2(event):
global pos
if event.inaxes in [ax1] and event.button == 1:
ax1.text(event.xdata, event.ydata, 'o', color='r', weight='bold',\
horizontalalignment='center',verticalalignment='center');
pos.append([event.xdata,event.ydata])
#ax1.set_title('%.1f' % pos[-1:][0][0] + ',' + '%.1f' % pos[-1:][0][1])

def f_next(event):
global pos,apos,pop,axpos,aypos,axposp,ayposp
if event.inaxes in [ax_next] and event.button == 1:
pop = np.array(pos).T.tolist()
pos=[]
axpos.append(pop[0])
aypos.append(pop[1])
ax1.clear()
ax1.set_xlim(left,right);ax1.set_ylim(bottom,top)
f_replot()

def f_delone(event):
global axpos,aypos
if event.inaxes in [ax_delone] and event.button == 1:
del axpos[ddata-1]
del aypos[ddata-1]
f_replot()
pos=[]

def getx(lst):
xx=list(map(itemgetter(0), lst))
return(xx)

def gety(lst):
yy=list(map(itemgetter(1), lst))
return(yy)

def f_replot():
ax1.clear()
ax1.set_xlim(left,right);ax1.set_ylim(bottom,top)
for ii in range(len(axpos)):
ax1.plot(axpos[ii],aypos[ii],'o');
ax1.plot(axpos[ii] + [axpos[ii][0]],aypos[ii] + [aypos[ii][0]],'-');
ax1.text(axpos[ii][0],aypos[ii][0], str(1+ii));
for ii in range(len(layers)):
ax1.plot(getx(layers[ii]),gety(layers[ii]),'-')

def f_plotlayers():
ax1.set_xlim(left,right);ax1.set_ylim(bottom,top)
for ii in range(len(layers)):
ax1.plot(getx(layers[ii]),gety(layers[ii]),'-')

def f_textbox(text):
global ddata
ddata = int(text)

def all_buttons():
global ax_next,ax_delall,ax_texbox,ax_delone,ax_save,ax_read,ax_filename
global b_next, b_delall, b_textbox, b_delone, b_save, b_filename, b_read
ax_next = fig0.add_axes([0.10, 0.07+0.2*hi+.5, 0.1, 0.075])
ax_textbox = fig0.add_axes([0.5,0.07+0.2*hi+.5,0.08,0.075])
ax_delone = fig0.add_axes([0.5,0.07+0.11*hi+.5,0.08,0.075])
#
b_next = Button(ax_next, 'Next poly',hovercolor='green')
b_next.on_clicked(f_next)
b_textbox = TextBox(ax_textbox, 'Del. nr:', initial=" ")
b_textbox.on_text_change(f_textbox)
b_delone = Button(ax_delone, 'Del poly', hovercolor='red')
b_delone.on_clicked(f_delone)

###############################################

# third, construct a plot and launch the interaction, by calling "all_buttons() and mpl_connect with "onclick2":

top=10;bottom=-60;left=0;right=256;# model size
layers=[]
# First "layer" is topography [[x0,y0], [x1,y1], ... [xn,yn]] i.e., flat horizontal [[0,0],[333,0]]:
layers.append([[0,0],[50,0],[60,3],[67,4],[70,3],[73,0],[256,0]])
# add as many layers as needed, or none. Negative is down:
layers.append([[0,-20],[256,-20]])
layers.append([[0,-30],[256,-50]])
mle=max([top-bottom,left-right])
hi=(top-bottom)/mle
wi=(right-left)/mle
pos=[]; mona='m_tmp.csv'
fig0 = plt.figure(figsize=(8,4));
ax1 = fig0.add_axes([0.07, 0.07, 0.2*wi, 0.2*hi*2]) #[left bottom width height]
ax1.set_xlim(left,right);ax1.set_ylim(bottom,top)

all_buttons()
f_plotlayers()
if 'axpos' in globals():
for i in range(len(axpos)):
f_replot()
else:
axpos=[]; aypos=[];
#
cid=fig0.canvas.mpl_connect('button_press_event', onclick2)
#
###########################

Actual outcome

# If applicable, paste the console output here
#
#

Expected outcome

Matplotlib version

matplotlib 3.1.1

Operating system: linux mint

Matplotlib version: 3.3.1

Matplotlib backend (print(matplotlib.get_backend())): nbAgg

Python version: 3.7.8

Jupyter version (if applicable):

jupyter core : 4.6.3

jupyter-notebook : 6.1.4

qtconsole : 4.7.5

ipython : 7.17.0

ipykernel : 5.3.4

jupyter client : 6.1.6

jupyter lab : not installed

nbconvert : 5.6.1

ipywidgets : 7.5.1

nbformat : 5.0.7

traitlets : 4.3.3

Other libraries:

installed with conda

the working environment was installed from conda. Channels are:

gimli

anaconda

conda-forge

defaults

######################################################

Issue 2:
Bug report

Bug summary

I encountered a performance regression starting in Matplotlib v3.3.0 when using a figure with a button widget. Any mouse motion appears to trigger canvas draw events. The issue bisected to commit f6b8891 and is not present in v3.2.2.

Code for reproduction

from matplotlib import pyplot as plt
from matplotlib.widgets import Button

if __name__ == "__main__":
def on_draw(evt):
global redraw_count
redraw_count += 1
btn.label.set_text(btn_txt.format(redraw_count))

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
redraw_count = 0
btn_txt = "Redraws: {}"
btn = Button(ax, btn_txt.format(redraw_count))
fig.canvas.mpl_connect("draw_event", on_draw)
plt.show()

Actual outcome

Motion anywhere in the figure increments the number of redraw events. The issue appears to result from the comparison between the Button's stored color value and the Axes's returned facecolor (see here). The default Button color is given and stored as a string of a float, while the Axes get_facecolor returns a tuple in RGBA format.

Expected outcome

Redraws are only triggered when moving into or out of the button to show the hover color change. A workaround is to give the color and hovercolor parameters to Button as RGBA values, such as:

btn = Button(ax, "Label", color=(0.2, 0.3, 0.4, 1.0), hovercolor=(0.3, 0.4, 0.5, 1.0))

A fix would be to convert the found color value in the Button._motion function to RGBA when comparing with the current facecolor, such as this change in the Button class (after adding an import to colors):

def _motion(self, event):
if self.ignore(event):
return
c = self.hovercolor if event.inaxes == self.ax else self.color
# changed c to colors.to_rgba(c)
if colors.to_rgba(c) != self.ax.get_facecolor():
self.ax.set_facecolor(c)
if self.drawon:
self.ax.figure.canvas.draw()

If this seems reasonable, I can submit a PR.

Matplotlib version

Operating system: macOS 10.15.5

Matplotlib version: 3.3.1 (tested on latest commit, ce6ac2d)

Matplotlib backend (print(matplotlib.get_backend())): MacOSX

Python version: 3.7.6

Jupyter version (if applicable): n/a

Other libraries: n/a