I just submitted a PR to the repo with my EDA nb.
Iāve edited my code above with a little refactoring/upgrading of the original KneePlot
class. But the big addition is a new class that generates an interactive plot of all three imaging planes (axial, sagittal and coronal) for each case.
This is the code to load the data for use in each class.
train_abnl = pd.read_csv(data_path/'train-abnormal.csv', header=None,
names=['Case', 'Abnormal'],
dtype={'Case': str, 'Abnormal': np.int64})
def load_one_stack(case, data_path=train_path, plane='coronal'):
fpath = data_path/plane/'{}.npy'.format(case)
return np.load(fpath)
def load_stacks(case):
x = {}
planes = ['axial', 'coronal', 'sagittal']
for i, plane in enumerate(planes):
x[plane] = load_one_stack(case, plane=plane)
return x
case = train_abnl.Case[0]
x = load_one_stack(case)
x_multi = load_stacks(case)
And this is the code for the new class to generate the multi-viewer.
from ipywidgets import interact, Dropdown, IntSlider
class MultiKneePlot():
def __init__(self, x_multi, figsize=(10, 10)):
self.x = x_multi
self.planes = ['coronal', 'sagittal', 'axial']
self.slice_nums = {plane: self.x[plane].shape[0] for plane in self.planes}
self.figsize = figsize
def _plot_slices(self, plane, im_slice):
fig, ax = plt.subplots(1, 1, figsize=self.figsize)
ax.imshow(self.x[plane][im_slice, :, :])
plt.show()
def draw(self):
planes_widget = Dropdown(options=self.planes)
plane_init = self.planes[0]
slice_init = self.slice_nums[plane_init] - 1
slices_widget = IntSlider(min=0, max=slice_init, value=slice_init//2)
def update_slices_widget(*args):
slices_widget.max = self.slice_nums[planes_widget.value] - 1
slices_widget.value = slices_widget.max // 2
planes_widget.observe(update_slices_widget, 'value')
interact(self._plot_slices, plane=planes_widget, im_slice=slices_widget)
def resize(self, figsize): self.figsize = figsize
Example usage with screenshot of viewer.
plot_multi = MultiKneePlot(x_multi)
plot_multi.draw()