matplotlib 小部件更新了错误的数据

matplotlib widget updates the wrong data

我正在绘制一个图来比较两种不同方法的能带结构计算。这意味着为每组数据绘制多条线。我想要一组小部件来分别控制每组数据。如果我只绘制一组数据,下面的代码可以工作,但我无法让小部件为两组数据正常工作。

#!/usr/bin/env python3

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, TextBox

#cols = ['blue', 'red', 'green', 'purple']
cols = ['#3f54bf','#c14142','#59bf3f','#b83fbf']

finam = ['wan_band.dat','wan_band.pwx.dat']
#finam = ['wan_band.dat'] # this works

lbot = len(finam)*0.09 + 0.06
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=lbot)
ax.margins(x=0) # lines go to the edge of the horizontal axes

def setlines(lines, txbx1, txbx2):
    ''' turn lines on/off based on text box values '''
    try:
        mn = int(txbx1) - 1
        mx = int(txbx2) - 1
        for ib in range(len(lines)): 
            if (ib<mn) or (ib>mx):
                lines[ib].set_visible(False)
            else :
                lines[ib].set_visible(True)

        plt.draw()
    except ValueError as err:
        print('Invalid range')
#end def setlines(cnt, lines, txbx1, txbx2):

def alphalines(lines, valin):
    ''' set lines' opacity '''
    maxval = int('ff',16)
    maxval = hex(int(valin*maxval))[2:]
    for ib in range(bcnt):
        lines[ib].set_color(cols[cnt]+maxval)
    plt.draw()
#end def alphalines(lines, valtxt):

lines  = [0]*len(finam) # 2d list to hold Line2Ds
txbox1 = [0]*len(finam) # list of Lo Band TextBoxes
txbox2 = [0]*len(finam) # lsit of Hi Band TextBoxes
alslid = [0]*len(finam) # list of Line Opacity Sliders

for cnt, fnam in enumerate(finam):

    ptcnt = 0 # point count
    fid   = open(fnam, 'r')
    fiit  = iter(fid)
    for line in fiit:
        if line.strip() == '' :
            break
        ptcnt += 1
    fid.close()

    bandat_raw = np.loadtxt(fnam)
    bcnt = int(np.round((bandat_raw.shape[0] / (ptcnt))))

    print(ptcnt)
    print(bcnt)

    # get views of the raw data that are easier to work with
    kbandat = bandat_raw[:ptcnt,0]                       # k point length along path
    ebandat = bandat_raw.reshape((bcnt,ptcnt,2))[:,:,1]  # band energy @ k-points

    lines[cnt] = [0]*bcnt # point this list element to another list
    for ib in range(bcnt):
        #l, = plt.plot(kbandat, ebandat[ib], c=cols[cnt],lw=1.0)
        l, = ax.plot(kbandat, ebandat[ib], c=cols[cnt],lw=1.0)
        lines[cnt][ib] = l

    y0 = 0.03 + 0.07*cnt
    bxht = 0.035
    axbox1 = plt.axes([0.03, y0, 0.08, bxht]) # x0, y0, width, height
    axbox2 = plt.axes([0.13, y0, 0.08, bxht])
    txbox1[cnt] = TextBox(axbox1, '', initial=str(1))
    txbox2[cnt] = TextBox(axbox2, '', initial=str(bcnt))
    txbox1[cnt].on_submit( lambda x: setlines(lines[cnt], x, txbox2[cnt].text) ) 
    txbox2[cnt].on_submit( lambda x: setlines(lines[cnt], txbox1[cnt].text, x) ) 

    axalpha = plt.axes([0.25, y0, 0.65, bxht])
    alslid[cnt] = Slider(axalpha, '', 0.1, 1.0, valinit=1.0)
    salpha = alslid[cnt]
    alslid[cnt].on_changed( lambda x: alphalines(lines[cnt], x) )

#end for cnt, fnam in enumerate(finam):

plt.text(0.01, 1.2, 'Lo Band', transform=axbox1.transAxes)
plt.text(0.01, 1.2, 'Hi Band', transform=axbox2.transAxes)
plt.text(0.01, 1.2, 'Line Opacity', transform=axalpha.transAxes)
plt.show()

所有小部件只控制最后绘制的数据集,而不是我试图与每个小部件关联的单个数据集。这是一个示例输出:

这里底部的滑块应该改变蓝线的不透明度,但它却改变了红线的不透明度。最初变量 txbox1txbox2alslid 不是列表。虽然我将它们更改为列表以确保它们不会被垃圾收集,但它并没有改变任何东西。

这是我一直在使用的测试数据set1 and set2。根据代码中的硬编码列表 finam,它们应保存为文件 'wan_band.dat' 和 'wan_band.pwx.dat'。

我想通了,使用 lambda 部分执行带有迭代器值的一些函数意味着它们总是用迭代器的最后一个值进行计算。切换到 functools.partial 解决了这个问题。