如果图例在轴外,则在鼠标单击时注册双事件 [英] Double event registered on mouse-click if legend is outside axes
问题描述
我必须在一个图中绘制多个数据集.能够突出显示一个或多个图表以进行比较是很有用的.为此,无论何时直接选择一条线,我都会在:"
(背景图)和-"
(突出显示的图)之间切换图的线型,或者通过单击图例中的相应条目.
I have to plot several data sets in one plot. It is useful to be able to highlight one or more of the plots in order to compare them. For this, I toggle the line style of the plot between ":"
(background plot) and "-"
(highlighted plot) whenever a line is selected directly, or, by clicking on the corresponding entry in the legend.
这非常有效,直到我尝试使用 bbox_to_anchor
将图例移到轴外.之后,在图例行上单击鼠标即可连续触发2次单击事件,从而取消了切换效果.
This works perfectly until I try to move the legend outside the axes using bbox_to_anchor
. After this, a single mouse click on the legend line triggers 2 click events in succession, thereby canceling the toggling effect.
如何在保持 pick_event 的正确行为的同时将图例放置在轴外?
How do I place the legend outside the axes while preserving the correct behaviour for the pick_event?
重现该问题的简化代码(单击绘图线可在突出显示"和未突出显示"之间切换,而单击图例行可在返回到之前的状态之前短暂切换绘图线):>
Simplified code that reproduces the problem (Clicking on a plot line toggles between 'highlighted' and 'not-highlighted', whereas clicking on a legend line briefly toggles the plot-line before going back to the previous state):
import pylab
import numpy
# Create data for plotting
t = numpy.linspace(0, 1.0, 100)
a = numpy.sin(2*numpy.pi*t)
# Set up figure
fig = pylab.figure()
ax = pylab.subplot(111)
# Plot figures
lines = []
for i in range(5):
line = ax.plot(t, (i+1)*a, linestyle=':', picker=5, label='line%d'%(i+1))
lines.append(line[0]) # Save plot lines
# Create legend
leg = ax.legend(bbox_to_anchor=(1.01, 1), loc=2) # Does not work as expected
# leg = ax.legend() # Works!!
# Get legend lines
leglines = leg.get_lines()
# Set event for legend lines
for line in leglines:
line.set_picker(5)
# Create a 2 way mapping between legend lines <-> plot lines
line2leg = dict(zip(lines+leglines, leglines+lines))
# Define event function
def onpick(event):
thisline = event.artist
if thisline.get_linestyle()==':':
print ": -> -" # For debugging
thisline.set_linestyle('-')
line2leg[thisline].set_linestyle('-')
else:
print "- -> :" # For debugging
thisline.set_linestyle(':')
line2leg[thisline].set_linestyle(':')
fig.canvas.draw()
# connect event function
fig.canvas.mpl_connect('pick_event', onpick)
pylab.show()
推荐答案
如果您使用以下内容修改 Artist.pick
:
If you monkey patch Artist.pick
with the following:
matplotlib.artist.Artist.orig_pick = matplotlib.artist.Artist.pick
def nu_pick(self, me):
print self
matplotlib.artist.Artist.orig_pick(self, me)
matplotlib.artist.Artist.pick = nu_pick
您可以查看艺术家如何在挑选事件中递归.(每个 Artist
对象在其自身上然后在其所有子代上调用 pick
).由于我不明白的原因,图例的绘图区域中每条线都有两个副本(并且在内部和外部时表现不同).
You can look at how the artists recurse on a pick event. (Each Artist
object calls pick
on it's self and then on all of it's children). For reasons I don't understand, there are two copies of each line in the drawing area of the legend (and it behaves differently when it is inside and outside).
一个简单的解决方案是只计算 leglines
被击中的次数,并且只切换奇数:
A way-hacky solution is to just count how many times the leglines
have been hit, and only toggle on the odd ones:
import pylab
import numpy
# Create data for plotting
t = numpy.linspace(0, 1.0, 100)
a = numpy.sin(2*numpy.pi*t)
# Set up figure
fig = pylab.figure()
ax = pylab.subplot(111)
# Plot figures
lines = []
for i in range(5):
line = ax.plot(t, (i+1)*a, linestyle=':', picker=5, label='line%d'%(i+1))
lines.append(line[0]) # Save plot lines
# Create legend
leg = ax.legend(bbox_to_anchor=(1.01, 1), loc=2) # Does not work as expected
#leg = ax.legend() # Works!!
# Get legend lines
leglines = leg.get_lines()
# Set event for legend lines
for line in leglines:
line.set_picker(5)
# Create a 2 way mapping between legend lines <-> plot lines
line2leg = dict(zip(lines+leglines, leglines+lines))
count_dict = dict((l, 0) for l in lines )
# Define event function
def onpick(event):
thisline = event.artist
print event
print thisline
if thisline in lines:
print 'lines'
count_dict[thisline] = 0
elif thisline in leglines:
print 'leglines'
thisline = line2leg[thisline]
count_dict[thisline] += 1
print 'added'
if (count_dict[thisline] % 2) == 1:
print count_dict[thisline]
return
print 'tested'
if thisline.get_linestyle()==':':
print ": -> -" # For debugging
thisline.set_linestyle('-')
line2leg[thisline].set_linestyle('-')
else:
print "- -> :" # For debugging
thisline.set_linestyle(':')
line2leg[thisline].set_linestyle(':')
fig.canvas.draw()
# connect event function
fig.canvas.mpl_connect('pick_event', onpick)
pylab.show()
(我把所有的调试语句都留在了里面).
(I left all my de-bugging statements in).
如果您不想在github上创建问题,请确保这是一个错误.
Pretty sure this is a bug, if you don't want to create an issue on github I will.
这篇关于如果图例在轴外,则在鼠标单击时注册双事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!