Matplotlib Actualizando el rango del widget del control deslizante

Estoy tratando de escribir un pequeño fragmento de código que elimine interactivamente los cortes seleccionados en una serie de imágenes usando matplotlib. He creado un botón ‘eliminar’ que almacena una serie de índices que se eliminarán cuando se seleccione el botón ‘actualizar’. Sin embargo, actualmente no puedo restablecer el rango de mi widget de control deslizante, es decir, eliminar el número de segmentos eliminados de valmax. ¿Cuál es la solución pythonica a este problema?

Aquí está mi código:

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

Parece que el control deslizante no tiene una manera de actualizar el rango ( api ). Sugeriría establecer el rango del control deslizante en [0,1] y hacer

 frame = int(self.nframes * value) 

En una nota un tanto relacionada, habría hecho frame una variable de instancia un atributo de datos en lugar de una variable global ( tutorial ).

Para actualizar un rango de control deslizante, puede establecer el valor mínimo y máximo directamente,

 slider.valmin = 3 slider.valmax = 7 

Para reflejar este cambio en los ejes del control deslizante, debe establecer los límites de los ejes,

 slider.ax.set_xlim(slider.valmin,slider.valmax) 

Un ejemplo completo, donde escribir cualquier dígito cambia el valmin del control deslizante a ese valor.

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