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

时间:2019-07-17 05:02:05

标签: python matplotlib matplotlib-widget

我正在作图,比较两种不同方法的能带结构计算。这意味着为每组数据绘制多条线。我想拥有一组分别控制每组数据的小部件。如果仅绘制一组数据,下面的代码将起作用,但是对于两套数据,我无法使小部件正常工作。

#!/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()

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

在此,底部滑块应更改蓝线的不透明度,但应更改红线的不透明度。最初,变量txbox1txbox2alslid不是列表。我将它们更改为列表,以确保它们没有被垃圾收集,但是它没有任何改变。

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

1 个答案:

答案 0 :(得分:0)

我想出了办法,使用lambda部分执行带有迭代器值的某些函数意味着它们总是使用迭代器的最后一个值进行评估。切换到functools.partial可以解决此问题。