Legend Picking Breaks When Drawing `plot`s Instead Of `scatter`s
Solution 1:
Ok, so I know this is not the answer, but the comments don't allow me to do this kind of brainstorming. I tried a couple of things, and noticed the following. When you print the axes
of the legendHandles
artists in your for loop, it returns None
for both legends in the case of the scatter plot / PathCollection
artists. However, in the case of the 'normal' plot / Line2D
artists, it returns axes objects! And even more than that; even though in the terminal their representations seem to be the same (AxesSubplot(0.125,0.11;0.775x0.77)
), if you check if they are == ax2
, for the legendHandles
artist of legend1
it returns False
, while for the one of legend2
, it returns True
. What is happening here?
So I tried to not only remove legend1
from ax1
and add it again to ax2
but to also do the same with the legendHandles
object. But it doesn't allow me to do that:
NotImplementedError: cannot remove artist
To me it looks like you found a bug, or at least inconsistent behaviour. Here is the code of what I tried so far, in case anybody else would like to play around with it further.
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use('Qt5Agg')
import numpy as np
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
X = np.linspace(0, 2*np.pi, 100)
Y1 = X**0.5 * np.sin(X)
Y2 = -np.cos(X)
USE_LINES = True # <--- set this to True or False to test both cases.
if USE_LINES:
ax1.plot(X, Y1, color="green", label="$Y_1$")
ax2.plot(X, Y2, color="red", label="$Y_2$")
else:
ax1.scatter(X, Y1, color="green", label="$Y_1$")
ax2.scatter(X, Y2, color="red", label="$Y_2$")
# Put both legends on ax2 so that pick events also work for ax1's legend.
legend1 = ax1.legend(loc="upper left")
legend2 = ax2.legend(loc="upper right")
legend1.remove()
ax2.add_artist(legend1)
# legend1.legendHandles[0].remove()
# ax2.add_artist(legend1.legendHandles[0])
for n, legend in enumerate((legend1, legend2)):
legend_item = legend.legendHandles[0]
legend_item.set_gid(n+1)
legend_item.set_picker(10)
print(
f'USE_LINES = {USE_LINES}', f'legend{n+1}',
legend_item.axes.__repr__() == legend.axes.__repr__(),
legend_item.axes == legend.axes,
legend_item.axes.__repr__() == ax2.__repr__(),
legend_item.axes == ax2, type(legend_item),
)
# When a legend element is picked, hide/show the associated curve.
def on_graph_pick_event(event):
gid = event.artist.get_gid()
print(f"Picked Y{gid}'s legend.")
ax = {1: ax1, 2: ax2}[gid]
artist = ax.lines[0] if USE_LINES else ax.collections[0]
artist.set_visible(not artist.get_visible())
plt.draw()
fig.canvas.mpl_connect("pick_event", on_graph_pick_event)
plt.show()
Post a Comment for "Legend Picking Breaks When Drawing `plot`s Instead Of `scatter`s"