0

I am writing an image processing module in Python using matplotlib.pyplot and numpy backend. The images will largely be in tiff format, so the code below uses tifffile to convert a 3D image file to a 4D array in numpy. The below code aims to move through the z-plane of the 3D image, one image at a time, using z and x as hotkeys. My problem is quite interesting and I can't figure it out: the time between event and action (pressing x and displaying z+1 image) gets twice as long with each event. I timed it, results below: 1st z-press: 0.124 s 2nd z-prss: 0.250 s 3rd z-press: 0.4875 s

It is a bonafide linear increase, but I can't find where in my code the bug could be.

import matplotlib.pyplot as plt
import numpy as np
import tifffile as tiff

class Image:
    def __init__ (self, fname):
        self.fname = fname
        self.fig = plt.figure()
        self.z = 0
        self.ax = self.fig.add_subplot(111)
        self.npimg = tiff.imread(self.fname)
        self.plotimg()
        self.connect()

    def plotimg(self):
        plt.imshow(self.npimg[self.z][0])
        plt.show()

    def connect(self):
        self.cidkeypress = self.fig.canvas.mpl_connect('key_press_event',self.keypress)

    def disconnect(self):
        self.fig.canvas.mpl_disconnect(self.cidkeypress)

    def keypress(self, event):
        if event.key == 'x':
            self.z += 1
            self.plotimg()
        elif event.key == 'z':
            self.z -= 1
        self.plotimg()
JBM37
  • 15
  • 2

1 Answers1

0

Since you didn't provide an example file, I can't test your code. But I think the problem is, that you call plt.imshow() repeatedly. Each time a new AxesImage object is added to the Figure. This is why the timings increase linearly.

So the solution is to only have one AxesImage object and only update the data. Adapt __init__ and plotimg as follows:

def __init__ (self, fname):
    self.fname = fname
    self.fig = plt.figure()
    self.z = 0
    self.ax = self.fig.add_subplot(111)
    self.npimg = tiff.imread(self.fname)
    self.pltim = plt.imshow(self.npimg[self.z][0])
    self.connect()
    plt.show()

def plotimg(self):
    self.pltim.set_data(self.npimg[self.z][0])
    plt.draw()

Beware: Untested code!

EDIT:

Difference between plt.imshow and plt.show:

Despite their similar name, they do very different things: plt.imshow is a plotting function, which draws an image to the current axes (similar to plt.plot, plt.scatter, etc.) plt.show however, dispays the figure on the screen and enters the backends mainloop (i.e. blocks your code). This answer explains it in more detail

Community
  • 1
  • 1
hitzg
  • 12,133
  • 52
  • 54
  • That did the trick. Question: plt.imshow creates an AxesImage object? What is the difference between plt.show and plt.imshow? – JBM37 Dec 18 '14 at 22:31