2012-11-21 64 views
2

我想写一小段代码,交互式删除图像系列中使用matplotlib选定的切片。我创建了一个按钮'删除',当按钮'update'被选中时,它存储了许多要删除的索引。但是,我目前无法重置滑块小部件的范围,即从valmax删除已删除的切片数。这个问题的pythonic解决方案是什么?Matplotlib更新滑块小部件范围

这里是我的代码:

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() 

回答

1

它看起来像滑块没有办法更新范围(api)。我建议设置滑块的范围为[0,1],做

frame = int(self.nframes * value) 

在一个有点相关的说明,我会作出frame实例变量数据属性,而不是一个全局变量( tutorial)。

+0

感谢您的回复。我仍然在与Python握手,但享受它。是一个实例变量是一个局部变量。我只是在主函数中设置frame = 0吗? – moadeep

+1

'self.frame',一个变量的价值是与类的实例相关联的(我搞砸了一点,应该说'数据属性')。请参阅http://docs.python.org/2/tutorial/classes.html#instance-objects。 – tacaswell

0

为了更新则可以设置最低和它直接最大值一个滑块范围,

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()