I'm working on some computer vision algorithm and I'd like to show how a numpy array changes in each step.
What works now is that if I have a simple imshow( array )
at the end of my code, the window displays and shows the final image.
However what I'd like to do is to update and display the imshow window as the image changes in each iteration.
So for example I'd like to do:
import numpy as np import matplotlib.pyplot as plt import time array = np.zeros( (100, 100), np.uint8 ) for i in xrange( 0, 100 ): for j in xrange( 0, 50 ): array[j, i] = 1 #_show_updated_window_briefly_ plt.imshow( array ) time.sleep(0.1)
The problem is that this way, the Matplotlib window doesn't get activated, only once the whole computation is finished.
I've tried both native matplotlib and pyplot, but the results are the same. For plotting commands I found an .ion()
switch, but here it doesn't seem to work.
Q1. What is the best way to continuously display updates to a numpy array (actually a uint8 greyscale image)?
Q2. Is it possible to do this with an animation function, like in the dynamic image example? I'd like to call a function inside a loop, thus I don't know how to achieve this with an animation function.
MatPlotLib with Python Create an array to plot an image, using numpy. Display the image using the imshow() method. To make a slider axis, create an axes and a slider, with facecolor=yellow. To update the image, while changing the slider, we can write a user-defined method, i.e., update().
We can use matplotlib to Plot live data with Matplotlib. With the help of matplotlib. pyplot. draw() function we can update the plot on the same figure during the loop.
Just specify vmin=0, vmax=1 . By default, imshow normalizes the data to its min and max. You can control this with either the vmin and vmax arguments or with the norm argument (if you want a non-linear scaling).
imshow. The matplotlib function imshow() creates an image from a 2-dimensional numpy array. The image will have one square for each element of the array. The color of each square is determined by the value of the corresponding array element and the color map used by imshow() .
You don't need to call imshow
all the time. It is much faster to use the object's set_data
method:
myobj = imshow(first_image) for pixel in pixels: addpixel(pixel) myobj.set_data(segmentedimg) draw()
The draw()
should make sure that the backend updates the image.
UPDATE: your question was significantly modified. In such cases it is better to ask another question. Here is a way to deal with your second question:
Matplotlib's animation only deals with one increasing dimension (time), so your double loop won't do. You need to convert your indices to a single index. Here is an example:
import numpy as np from matplotlib import pyplot as plt from matplotlib import animation nx = 150 ny = 50 fig = plt.figure() data = np.zeros((nx, ny)) im = plt.imshow(data, cmap='gist_gray_r', vmin=0, vmax=1) def init(): im.set_data(np.zeros((nx, ny))) def animate(i): xi = i // ny yi = i % ny data[xi, yi] = 1 im.set_data(data) return im anim = animation.FuncAnimation(fig, animate, init_func=init, frames=nx * ny, interval=50)
I struggled to make it work because many post talk about this problem, but no one seems to care about providing a working example. In this case however, the reasons were different :
Also Tiago mentioned calling draw()
, but without specifying where to get it from - and by the way, you don't need it. the function you really need to call is flush_event()
. sometime it works without, but it's because it has been triggered from somewhere else. You can't count on it. The real tricky point is that if you call imshow()
on an empty table, you need to specify vmin and vmax or it will fail to initialize it's color map and set_data will fail too.
Here is a working solution :
IMAGE_SIZE = 500 import numpy as np import matplotlib.pyplot as plt plt.ion() fig1, ax1 = plt.subplots() fig2, ax2 = plt.subplots() fig3, ax3 = plt.subplots() # this example doesn't work because array only contains zeroes array = np.zeros(shape=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8) axim1 = ax1.imshow(array) # In order to solve this, one needs to set the color scale with vmin/vman # I found this, thanks to @jettero's comment. array = np.zeros(shape=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8) axim2 = ax2.imshow(array, vmin=0, vmax=99) # alternatively this process can be automated from the data array[0, 0] = 99 # this value allow imshow to initialise it's color scale axim3 = ax3.imshow(array) del array for _ in range(50): print(".", end="") matrix = np.random.randint(0, 100, size=(IMAGE_SIZE, IMAGE_SIZE), dtype=np.uint8) axim1.set_data(matrix) fig1.canvas.flush_events() axim2.set_data(matrix) fig1.canvas.flush_events() axim3.set_data(matrix) fig1.canvas.flush_events() print()
UPDATE : I added the vmin/vmax solution based on @Jettero's comment (I missed it at first).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With