Почему выбор легенды работает только для `ax.twinx ()`, а не для `ax`? - PullRequest
1 голос
/ 11 февраля 2020

Добрый день. Приведенный ниже минимальный код позволяет пользователю щелкнуть элемент легенды, чтобы скрыть / показать связанный набор данных. По какой-то причине он работает только на одном из ax, несмотря на то, что код очень «обычный» и не обрабатывает последний топор по-другому. Первый топор, похоже, не выбирает pick_event с. Как это исправить?

Нажмите на пузыри, чтобы проверить:

enter image description here

import numpy as np
import matplotlib.pyplot as plt

# Create dummy data.
fig = plt.gcf()
ax1 = plt.gca()
ax2 = ax1.twinx()
X = np.arange(-5, +5.01, 0.5)
Y1 = -X**2
Y2 = -0.5*X**2
ax1.scatter(X, Y1, color="red", label="1")
ax2.scatter(X, Y2, color="blue", label="2")
ax1.legend(loc="upper left")
ax2.legend(loc="upper right")
ax1.set_ybound(+5, -30)
ax2.set_ybound(+5, -30)

# Enable the pickable legend elements.
for ax in (ax1, ax2):
    for legend_item in ax.get_legend().legendHandles:
        legend_item.set_gid("1" if ax is ax1 else "2")
        legend_item.set_picker(10)

# Connect the pick event to a function.
def hide_or_show_data(event):
    """Upon clicking on a legend element, hide/show the associated data."""

    artist = event.artist
    gid = artist.get_gid()

    if gid == "1":
        scatter = ax1.collections[0]
    elif gid == "2":
        scatter = ax2.collections[0]

    scatter.set_visible(not scatter.get_visible())
    plt.draw()        

fig.canvas.mpl_connect("pick_event", hide_or_show_data)

Мое чувство кишки является то, что ax1 игнорирует события, потому что это «ниже» ax2, если это имеет смысл.

Ответы [ 2 ]

3 голосов
/ 11 февраля 2020

Вы можете создать легенду для нижних осей в верхних осях. Тогда события пика будут срабатывать только по верхним осям.

import numpy as np
import matplotlib.pyplot as plt

# Create dummy data.
fig = plt.gcf()
ax1 = plt.gca()
ax2 = ax1.twinx()
X = np.arange(-5, +5.01, 0.5)
Y1 = -X**2
Y2 = -0.5*X**2
ax1.scatter(X, Y1, color="red", label="1")
ax2.scatter(X, Y2, color="blue", label="2")
ax1.set_ybound(+5, -30)
ax2.set_ybound(+5, -30)


h,l=ax1.get_legend_handles_labels()
leg1 = ax2.legend(h,l,loc="upper left")
leg2 = ax2.legend(loc="upper right")
ax2.add_artist(leg1)


# Enable the pickable legend elements.
for leg in [leg1, leg2]:
    for legend_item in leg.legendHandles:
        legend_item.set_gid("1" if leg is leg1 else "2")
        legend_item.set_picker(10)

# Connect the pick event to a function.
def hide_or_show_data(event):
    """Upon clicking on a legend element, hide/show the associated data."""

    artist = event.artist
    gid = artist.get_gid()

    if gid == "1":
        scatter = ax1.collections[0]
    elif gid == "2":
        scatter = ax2.collections[0]

    scatter.set_visible(not scatter.get_visible())
    plt.draw()        

fig.canvas.mpl_connect("pick_event", hide_or_show_data)

plt.show()
0 голосов
/ 11 февраля 2020

Перед тем, как приходит реальный ответ, позвольте мне поделиться обходным путем на основе этого вопроса . Мы можем объединить обе легенды и поместить их в ax2, чтобы включить сбор. Если вы введете их в ax1, это не сработает.

# Create dummy data.
...

# Build a legend manually.
scatters = ax1.collections + ax2.collections # This is great if you can't save the return value of `ax.scatter(...)` because they are made somewhere else.
labels = [s.get_label() for s in scatters]
ax2.legend(scatters, labels, loc="upper left") # MUST use ax2.

# Enable the pickable legend elements.
 for n, legend_item in enumerate(ax2.get_legend().legendHandles, start=1):
        legend_item.set_gid(str(n))
        legend_item.set_picker(10) 

# Connect the pick event to a function.
...

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...