Python Matplotlib更新滑块小部件范围

Python Matplotlib更新滑块小部件范围,python,widget,matplotlib,slider,Python,Widget,Matplotlib,Slider,我试图编写一小段代码,使用matplotlib以交互方式删除图像系列中的选定切片。我创建了一个“删除”按钮,它存储了在选择“更新”按钮时要删除的一些索引。但是,我目前无法重置滑块小部件的范围,即从valmax中删除已删除切片的数量。这个问题的pythonic解决方案是什么 这是我的密码: import dicom import numpy as np import matplotlib.pyplot as plt from matplotlib.widgets import Slider, Bu

我试图编写一小段代码,使用matplotlib以交互方式删除图像系列中的选定切片。我创建了一个“删除”按钮,它存储了在选择“更新”按钮时要删除的一些索引。但是,我目前无法重置滑块小部件的范围,即从valmax中删除已删除切片的数量。这个问题的pythonic解决方案是什么

这是我的密码:

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

frame = 0
#store indices of slices to be deleted
delete_list = []


def main():

    data = np.random.rand(16,256,256)
    nframes = data.shape[0]

    raw_dicom_stack = []
    for x in range (nframes):
        raw_dicom_stack.append(data[x,:,:])

    #yframe = 0

    # Visualize it
    viewer = VolumeViewer(raw_dicom_stack, nframes)
    viewer.show()

class VolumeViewer(object):
    def __init__(self, raw_dicom_stack, nframes):

        global delete_list

        self.raw_dicom_stack = raw_dicom_stack
        self.nframes = nframes
        self.delete_list = delete_list

        # Setup the axes.
        self.fig, self.ax = plt.subplots()
        self.slider_ax = self.fig.add_axes([0.2, 0.03, 0.65, 0.03])
        self.delete_ax = self.fig.add_axes([0.85,0.84,0.1,0.04])
        self.update_ax = self.fig.add_axes([0.85,0.78,0.1,0.04])
        self.register_ax = self.fig.add_axes([0.85,0.72,0.1,0.04])
        self.add_ax = self.fig.add_axes([0.85,0.66,0.1,0.04])

        # Make the slider
        self.slider = Slider(self.slider_ax, 'Frame', 1, self.nframes, 
                            valinit=1, valfmt='%1d/{}'.format(self.nframes))
        self.slider.on_changed(self.update)

        #Make the buttons
        self.del_button = Button(self.delete_ax, 'Delete')
        self.del_button.on_clicked(self.delete)

        self.upd_button = Button(self.update_ax, 'Update')
        self.upd_button.on_clicked(self.img_update)

        self.reg_button = Button(self.register_ax, 'Register')

        self.add_button = Button(self.add_ax, "Add")

        # Plot the first slice of the image
        self.im = self.ax.imshow(np.array(raw_dicom_stack[0]))

    def update(self, value):
        global frame
        frame = int(np.round(value - 1))

        # Update the image data
        dat = np.array(self.raw_dicom_stack[frame])
        self.im.set_data(dat)

        # Reset the image scaling bounds (this may not be necessary for you)
        self.im.set_clim([dat.min(), dat.max()])

        # Redraw the plot
        self.fig.canvas.draw()

    def delete(self,event):
        global frame
        global delete_list

        delete_list.append(frame)
        print 'Frame %s has been added to list of slices to be deleted' %str(frame+1)
        print 'Please click update to delete these slices and show updated image series \n'

        #Remove duplicates from delete list

    def img_update(self,event):
        #function deletes image stacks and updates viewer
        global delete_list

        #Remove duplicates from list and sort into numerical order
        delete_list = list(set(delete_list))
        delete_list.sort()

        #Make sure delete_list is not empty
        if not delete_list:
            print "Delete list is empty, no slices to delete"
        #Loop through delete list in reverse numerical order and remove slices from series
        else:
            for i in reversed(delete_list):
                self.raw_dicom_stack.pop(i)
                print 'Slice %i removed from dicom series \n' %(i+1)

        #Can now remove contents from delete_list
        del delete_list[:]
        #Update slider range
        self.nframes =  len(self.raw_dicom_stack)


    def show(self):
        plt.show()

if __name__ == '__main__':
    main()

滑块似乎无法更新范围()。我建议将滑块的范围设置为[0,1],然后执行以下操作

frame = int(self.nframes * value)

与此相关的一点是,我会将
frame
实例变量作为数据属性,而不是全局变量()。

为了更新滑块范围,您可以直接设置其最小值和最大值

slider.valmin = 3
slider.valmax = 7
为了在滑块轴中反映此变化,您需要设置轴的限制

slider.ax.set_xlim(slider.valmin,slider.valmax)
一个完整的示例,其中键入任何数字都会将滑块的
valmin
更改为该值

import matplotlib.pyplot as plt
import matplotlib.widgets

fig, (ax,sliderax) = plt.subplots(nrows=2,gridspec_kw=dict(height_ratios=[1,.05]))

ax.plot(range(11))
ax.set_xlim(5,None)
ax.set_title("Type number to set minimum slider value")
def update_range(val):
    ax.set_xlim(val,None)

def update_slider(evt):
    print(evt.key)
    try:
        val = int(evt.key)
        slider.valmin = val
        slider.ax.set_xlim(slider.valmin,None)
        if val > slider.val:
            slider.val=val
            update_range(val)
        fig.canvas.draw_idle()
    except:
        pass

slider=matplotlib.widgets.Slider(sliderax,"xlim",0,10,5)
slider.on_changed(update_range)

fig.canvas.mpl_connect('key_press_event', update_slider)

plt.show()

谢谢你的回复。我仍然在学习python,但我很喜欢它。实例变量是局部变量。我只是在main函数中设置frame=0吗?
self.frame
,一个变量的值绑定到类的实例上(我把术语弄乱了一点,应该说是“数据属性”)。看见