Matplotlib 更新滑块小部件范围
问题描述
我正在尝试编写一小段代码,使用 matplotlib 以交互方式删除图像系列中的选定切片.我创建了一个删除"按钮,它存储了在选择更新"按钮时要删除的许多索引.但是,我目前无法重置滑块小部件的范围,即从 valmax 中删除已删除切片的数量.这个问题的pythonic解决方案是什么?
I am trying to write a small bit of code that interactively deletes selected slices in an image series using matplotlib. I have created a button 'delete' which stores a number of indices to be deleted when the button 'update' is selected. However, I am currently unable to reset the range of my slider widget, i.e. removing the number of deleted slices from valmax. What is the pythonic solution to this problem?
这是我的代码:
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
'
#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
' %(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()
解决方案
看起来滑块没有办法更新范围(api).我建议将滑块的范围设置为 [0,1] 并做
It looks like the slider does not have a way to update the range (api). I would suggest setting the range of the slider to be [0,1] and doing
frame = int(self.nframes * value)
在一些相关的注释中,我会将 frame
实例变量 设为数据属性而不是全局变量(教程).
On a somewhat related note, I would have made frame
an instance variable a data attribute instead of a global variable (tutorial).
相关文章