簡體   English   中英

Matplotlib - 在 fill_between 上選取圖例

[英]Matplotlib - legend picking on fill_between

我正在嘗試在 matplotlib 的 fill_between ( 鏈接到 fill_between 文檔)上使用圖例選擇( 鏈接到圖例選擇文檔)。

當我使用 matplotlib.pyplot.plot 時它工作得很好,但是當我在 matplotlib.pyplot.fill_between 上使用它時沒有任何反應,但我沒有收到要修復的錯誤。 我懷疑我與填充命令不是線條有關,我使用 get_lines() 函數,但我很難真正理解正在發生的事情。

使用 plt.plot 輸出“工作線”上的額外逗號是由於 plot 返回一個元組而 fill_between 返回一個值。

    df = pd.DataFrame(...)
    
    x_dist = df['distance']
    df.pop('distance')

    labels = []
    lines = []

    fig, ax = plt.subplots()

    cols = df.columns
    for i, col in enumerate(cols):
        bot = df[cols[i]]  # layer bot as bot
        top = df[cols[i - 1]]  # previous layer bot as top

        # plot layer if the layer has different values from the layers above
        if col[:4] != '0000':  # discard terrain (first entry)
            if not bot.equals(top):
                pl = ax.fill_between(x_dist, top, bot, label=col)  # non-working line
                # pl, = ax.plot(x_dist, bot, label=col)  # working line
                lines.append(pl)
                labels.append(pl.get_label())

    # set grid on plot
    ax.grid('both')

    # set legend on plot and place it outside plot
    box = ax.get_position()
    ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
    leg = ax.legend(fancybox=True, shadow=True, loc='center left', bbox_to_anchor=(1, 0.5))

    lined = {}  # Will map legend lines to original lines.
    for legline, origline in zip(leg.get_lines(), lines):
        legline.set_picker(True)  # Enable picking on the legend line.
        lined[legline] = origline

    def on_pick(event):
        legline = event.artist
        origline = lined[legline]
        visible = not origline.get_visible()
        origline.set_visible(visible)
        legline.set_alpha(1.0 if visible else 0.2)
        fig.canvas.draw()

    fig.canvas.mpl_connect('pick_event', on_pick)
    plt.show()

找到了解決方案。

代替 leg.get_lines() 使用 leg.findobj ,我在 findobj 函數中使用“match”參數搜索 patch.Rectangles 。 請記住“從 matplotlib 導入補丁”導入庫。

出於某種原因,在 python 3.9 中,當單擊圖例並禁用繪圖並更改圖例矩形的不透明度時,矩形的顏色變為默認藍色(不知道為什么?!)。 為了解決這個問題,我必須從 fill_between 圖中獲取顏色,並在 on_pick 函數中設置圖例矩形的顏色。 編輯:如果我更改為另一個 python exe(仍然是 3.9 版),則不會發生此錯誤,並且“leg_obj.set_color(fill_plot_color)”不是必需的。

我上面的代碼的解決方案:

df = pd.DataFrame(...)

x_dist = df['distance']
df.pop('distance')

labels = []
lines = []

fig, ax = plt.subplots()

cols = df.columns
for i, col in enumerate(cols):
    bot = df[cols[i]]  # layer bot as bot
    top = df[cols[i - 1]]  # previous layer bot as top

    # plot layer if the layer has different values from the layers above
    if col[:4] != '0000':  # discard terrain (first entry)
        if not bot.equals(top):
            pl = ax.fill_between(x_dist, top, bot, label=col)  # non-working line
            # pl, = ax.plot(x_dist, bot, label=col)  # working line
            lines.append(pl)
            labels.append(pl.get_label())

# set grid on plot
ax.grid('both')

# set legend on plot and place it outside plot
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
leg = ax.legend(fancybox=True, shadow=True, loc='center left', bbox_to_anchor=(1, 0.5))

lined = {}  # Will map legend lines to original lines.
for legline, origline in zip(leg.findobj(patches.Rectangle), lines):
    legline.set_picker(True)  # Enable picking on the legend line.
    lined[legline] = origline

def on_pick(event):
    legline = event.artist
    origline = lined[legline]
    color_fill = origline.get_facecolor()
    visible = not origline.get_visible()
    origline.set_visible(visible)
    legline.set_alpha(1.0 if visible else 0.2)
    legline.set_color(color_fill)
    fig.canvas.draw()

fig.canvas.mpl_connect('pick_event', on_pick)
plt.show()

一個更通用的答案:

from matplotlib import pyplot as plt, patches
import numpy as np

x = np.linspace(1, 10, 10)
y1 = np.linspace(1, 5, 10)
y2 = np.linspace(10, 20, 10)

fig, ax = plt.subplots()
pl = ax.fill_between(x, y1, y2, label='fill_plot')
leg = ax.legend()
fill_plots = [pl]

leg_to_fill = {}
for leg_obj, fill_plot in zip(leg.findobj(patches.Rectangle), fill_plots):
    leg_obj.set_picker(True)
    leg_to_fill[leg_obj] = fill_plot


def on_pick(event):
    leg_obj = event.artist
    fill_plot = leg_to_fill[leg_obj]
    # fill_plot_color = fill_plot.get_facecolor() # set if all blue plots
    visible = not fill_plot.get_visible()
    fill_plot.set_visible(visible)
    leg_obj.set_alpha(1.0 if visible else 0.2)
    # leg_obj.set_color(fill_plot_color) # set if all blue plots
    fig.canvas.draw()

fig.canvas.mpl_connect('pick_event', on_pick)
plt.show()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM