【问题标题】:matplotlib(mpl_connect) in for loop to create many interactive plots does not work在 for 循环中创建许多交互式绘图的 matplotlib(mpl_connect) 不起作用
【发布时间】:2021-06-01 03:54:39
【问题描述】:

我有一个 for 循环生成不同的数据帧(熊猫)然后绘制它。 我想创建许多交互式绘图,以便可以在图表中显示和隐藏不同的线。 为此,我正在使用 on_pick 函数(如 here 所述)

问题是,当我绘制一个表格时,它可以工作并且我有交互式图例,但是当我尝试在 for 循环中绘制多个图表时,所有图例都不再是交互式的了。

df = pd.DataFrame(np.array([[0.45,0.12,0.66,0.76,0.22],[0.22,0.24,0.12,0.56,0.34],[0.12,0.47,0.93,0.65,0.21]]),
                    columns=[60.1,65.5,67.3,74.2,88.5])
df['name']=['A1','B4','B7']
df=df.set_index('name')

#plot alone:
fig, ax = plt.subplots()
df.T.plot(ax=ax)
lines = ax.get_lines()
leg = ax.legend(fancybox=True, shadow=True)
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):
    #On the pick event, find the original line corresponding to the legend
    #proxy line, and toggle its visibility.
    legline = event.artist
    origline = lined[legline]
    visible = not origline.get_visible()
    origline.set_visible(visible)
    #Change the alpha on the line in the legend so we can see what lines
    #have been toggled.
    legline.set_alpha(1.0 if visible else 0.2)
    fig.canvas.draw()

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

结果:我可以启用和禁用图例中的线条:

#plot many plots in for loop:
nums=[5,8,0.3]

for n in nums:
    db=df*n
    
    fig, ax = plt.subplots()
    db.T.plot(ax=ax)
    lines = ax.get_lines()
    leg = ax.legend(fancybox=True, shadow=True)
    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):
        #On the pick event, find the original line corresponding to the legend
        #proxy line, and toggle its visibility.
        legline = event.artist
        origline = lined[legline]
        visible = not origline.get_visible()
        origline.set_visible(visible)
        #Change the alpha on the line in the legend so we can see what lines
        #have been toggled.
        legline.set_alpha(1.0 if visible else 0.2)
        fig.canvas.draw()
        
    fig.canvas.mpl_connect('pick_event', on_pick)
    plt.show()
    

结果:我得到了图表,但无法处理将显示哪些行。

*当我触摸线条时,它仍然以交互方式显示 x 和 y 值,但图例不是交互的。

我的最终目标:在 matplotlib 的 for 循环中生成多个交互式绘图,并能够启用和禁用图例项。

【问题讨论】:

  • 你需要使用matplotlib吗?如果我是你,我会选择更简单、更直观的交互式任务
  • 我无法重现该问题。你的 MWE 对我来说工作得很好——有和没有 for 循环。你的设置是什么?
  • 我也没有发现问题
  • 我也无法重现该问题。但是,当我将 plt.show() 从 for 循环中取出时,我确实遇到了错误。这是问题吗?
  • 它在 lop 内为您创建的所有地块是否同时具有交互性?

标签: python for-loop matplotlib legend interactive


【解决方案1】:

以下是同时显示它们的方法,使用fig 作为lined 的载体

多个独立的地块

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

df = pd.DataFrame(np.array([[0.45,0.12,0.66,0.76,0.22],[0.22,0.24,0.12,0.56,0.34],[0.12,0.47,0.93,0.65,0.21]]),
                    columns=[60.1,65.5,67.3,74.2,88.5])
df['name']=['A1','B4','B7']
df=df.set_index('name')

#plot many plots in for loop:
nums=[5,8,0.3]


def on_pick(event):
    #On the pick event, find the original line corresponding to the legend
    #proxy line, and toggle its visibility.
    legline = event.artist
    origline = event.canvas.figure.lined[legline]
    visible = not origline.get_visible()
    origline.set_visible(visible)
    #Change the alpha on the line in the legend so we can see what lines
    #have been toggled.
    legline.set_alpha(1.0 if visible else 0.2)
    event.canvas.draw()

for n in nums:
    db=df*n
    
    fig, ax = plt.subplots()
    db.T.plot(ax=ax)
    lines = ax.get_lines()
    leg = ax.legend(fancybox=True, shadow=True)
    fig.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.
        fig.lined[legline] = origline
        
        
    fig.canvas.mpl_connect('pick_event', on_pick)

plt.show()

使用子图

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

df = pd.DataFrame(np.array([[0.45,0.12,0.66,0.76,0.22],[0.22,0.24,0.12,0.56,0.34],[0.12,0.47,0.93,0.65,0.21]]),
                    columns=[60.1,65.5,67.3,74.2,88.5])
df['name']=['A1','B4','B7']
df=df.set_index('name')

#plot many plots in for loop:
nums=[5,8,0.3]


def on_pick(event):
    #On the pick event, find the original line corresponding to the legend
    #proxy line, and toggle its visibility.
    legline = event.artist
    origline = event.canvas.figure.lined[legline]
    visible = not origline.get_visible()
    origline.set_visible(visible)
    #Change the alpha on the line in the legend so we can see what lines
    #have been toggled.
    legline.set_alpha(1.0 if visible else 0.2)
    event.canvas.draw()

nrows = int(np.ceil(np.sqrt(len(nums))))
ncols = int(np.ceil(len(nums) / nrows))
fig, axs = plt.subplots(nrows=nrows,ncols=ncols)
if not isinstance(axs,np.ndarray):
  axs = np.array([[axs]])
if len(axs.shape)==1:
  axs = np.expand_dims(axs,axis=1)

fig.lined = {}  # Will map legend lines to original lines.
for idx,n in enumerate(nums):
    db=df*n
    
    ax = axs[int(idx/ncols),idx % ncols]
    
    db.T.plot(ax=ax)
    lines = ax.get_lines()
    leg = ax.legend(fancybox=True, shadow=True)
    for legline, origline in zip(leg.get_lines(), lines):
        legline.set_picker(True)  # Enable picking on the legend line.
        fig.lined[legline] = origline
        
        
fig.canvas.mpl_connect('pick_event', on_pick)
plt.show()

【讨论】:

    【解决方案2】:

    您可以将 PyQT5 用于多个动态实时图 https://eli.thegreenplace.net/2009/05/23/more-pyqt-plotting-demos

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      • 2021-01-31
      • 2015-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多