I have this piece of code which works perfectly fine for scrolling through 2D slices of a 3D numpy array.
import matplotlib.pyplot as plt
import numpy as np
class IndexTracker(object):
def __init__(self, ax, X):
self.ax = ax
ax.set_title('use scroll wheel to navigate images')
self.X = X
rows, cols, self.slices = X.shape
self.ind = self.slices // 2
self.im = ax.imshow(self.X[:, :, self.ind], cmap="gray")
self.update()
def onscroll(self, event):
print("%s %s" % (event.button, event.step))
if event.button == 'up':
self.ind = (self.ind + 1) % self.slices
else:
self.ind = (self.ind - 1) % self.slices
self.update()
def update(self):
self.im.set_data(self.X[:, :, self.ind])
self.ax.set_ylabel('slice %s' % self.ind)
self.im.axes.figure.canvas.draw()
def plot3d(image):
fig, ax = plt.subplots(1, 1)
tracker = IndexTracker(ax, image)
fig.canvas.mpl_connect('scroll_event', tracker.onscroll)
plt.show()
if __name__ == "__main__":
img = np.array([[[0, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 0, 0], [1, 1, 1], [0, 0, 0]],
[[0, 0, 0], [0, 1, 0], [0, 0, 0]]])
plot3d(img)
I would like to have the same functionality but for scrolling through two, equally sized, 3D numpy arrays at the same. One of the arrays shall be displayed with a certain level of opacity and a different color scheme, so both arrays can be inspected at the same time. Without scrolling, for a 2D slice, this can be achieved easily:
img1 = np.array([[[0, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 0, 0], [1, 1, 1], [0, 0, 0]],
[[0, 0, 0], [0, 1, 0], [0, 0, 0]]])
img2 = np.array([[[0, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 1, 0], [0, 1, 0], [0, 1, 0]],
[[0, 0, 0], [0, 1, 0], [0, 0, 0]]])
plt.imshow(img1[:, :, 1], cmap="gray")
plt.imshow(img2[:, :, 1], cmap="jet", alpha=0.25)
plt.show()
I tried to extend the IndexTracker class to accept a second 3D array and display one slice of each volume (with the same index) using imshow(). Also, it was intended to update the displayed images on each scroll event using set_data(). However, this did not succeed.
import numpy as np
import matplotlib.pyplot as plt
class IndexTracker(object):
def __init__(self, ax, X, Y):
self.ax = ax
self.X = X
self.Y = Y
_, _, self.slices = X.shape
self.ind = self.slices // 2
self.im = ax.imshow(self.X[:, :, self.ind], cmap="gray")
self.im = ax.imshow(self.Y[:, :, self.ind], cmap="jet", alpha=0.25)
self.update()
def onscroll(self, event):
print("%s %s" % (event.button, event.step))
if event.button == 'up':
self.ind = (self.ind + 1) % self.slices
else:
self.ind = (self.ind - 1) % self.slices
self.update()
def update(self):
self.im.set_data(self.X[:, :, self.ind])
self.im.set_data(self.Y[:, :, self.ind])
self.ax.set_ylabel('slice %s' % self.ind)
self.im.axes.figure.canvas.draw()
def plot3d(image1, image2):
image1 = np.rot90(image1, k=-1)
image2 = np.rot90(image2, k=-1)
fig, ax = plt.subplots(1, 1)
tracker = IndexTracker(ax, image1, image2)
fig.canvas.mpl_connect('scroll_event', tracker.onscroll)
plt.show()
if __name__ == "__main__":
img1 = np.array([[[0, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 0, 0], [1, 1, 1], [0, 0, 0]],
[[0, 0, 0], [0, 1, 0], [0, 0, 0]]])
img2 = np.array([[[0, 0, 0], [0, 1, 0], [0, 0, 0]],
[[0, 1, 0], [0, 1, 0], [0, 1, 0]],
[[0, 0, 0], [0, 1, 0], [0, 0, 0]]])
plot3d(img1, img2)
Do you have any idea on how to solve the given problem using matplotlib? Ideally by extending the first code snippet containing the IndexTracker class.
Edit: Added second image as parameter to plot3d() call
Happily enough if you keep track of the two Axes.imshow
objects (returned by plt.imshow
) separately, then matplotlib will deal with the layering of the images for you. Then you can use set_data on each of these individually. When doing so you need to keep the same colormap and alpha values for each of the images, you can accomplish this using a combination of im.to_rgba
and im.get_alpha
. Here are the modifications you need to make to your class for this too work:
class IndexTracker(object):
def __init__(self, ax, X, Y):
...
self.im1 = ax.imshow(self.X[:, :, self.ind], cmap="gray")
self.im2 = ax.imshow(self.Y[:, :, self.ind], cmap="jet", alpha=.25)
...
def update(self):
im1_data = self.im1.to_rgba(self.X[:, :, self.ind], alpha=self.im1.get_alpha())
im2_data = self.im2.to_rgba(self.Y[:, :, self.ind], alpha=self.im2.get_alpha())
self.im1.set_data(im1_data)
self.im2.set_data(im2_data)
...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.