I'm using the following code to produce an animation with matplotlib that is intended to visualize my experiments.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import ArtistAnimation, PillowWriter
plt.rcParams['animation.html'] = 'jshtml'
def make_grid(X, description=None, labels=None, title_fmt="label: {}", cmap='gray', ncols=3, colors=None):
L = len(X)
nrows = -(-L // ncols)
frame_plot = []
for i in range(L):
plt.subplot(nrows, ncols, i + 1)
im = plt.imshow(X[i].squeeze(), cmap=cmap, interpolation='none')
if labels is not None:
color = 'k' if colors is None else colors[i]
plt.title(title_fmt.format(labels[i]), color=color)
plt.xticks([])
plt.yticks([])
frame_plot.append(im)
return frame_plot
def animate_step(X):
return X ** 2
n_splots = 6
X = np.random.random((n_splots,32,32,3))
Y = X
X_t = []
for i in range(10):
Y = animate_step(Y)
X_t.append((Y, i))
frames = []
for X, step in X_t:
frame = make_grid(X,
description="step={}".format(step),
labels=range(n_splots),
title_fmt="target: {}")
frames.append(frame)
anim = ArtistAnimation(plt.gcf(), frames,
interval=300, repeat_delay=8000, blit=True)
plt.close()
anim.save("test.gif", writer=PillowWriter())
anim
The result can be seen here:
https://i.stack.imgur.com/OaOsf.gif
It works fine so far, but I'm having trouble getting a shared xlabel to add a description for all of the 6 subplots in the animation. It is supposed to show what step the image is on, i.e. "step=5".
Since it is an animation, I cannot use xlabel or set_title (since it would be constant over the whole animation) and have to draw the text myself.
I've tried something along the lines of..
def make_grid(X, description=None, labels=None, title_fmt="label: {}", cmap='gray', ncols=3, colors=None):
L = len(X)
nrows = -(-L // ncols)
frame_plot = []
desc = plt.text(0.5, .04, description,
size=plt.rcparams["axes.titlesize"],
ha="center",
transform=plt.gca().transAxes
)
frame_plot.append(desc)
...
This, of course, won't work, because the axes are not yet created. I tried using the axis of another subplot(nrows, 1, nrows), but then the existing images are drawn over..
Does anyone have a solution to this?
Edit:
unclean, hacky solution for now:
Wait for the axes of the middle image of the last row to be created and use that for plotting the text.
In the for loop:
...
if i == int((nrows - 0.5) * ncols):
title = ax.text(0.25, -.3, description,
size=plt.rcParams["axes.titlesize"],
# ha="center",
transform=ax.transAxes
)
frame_plot.append(title)
...
To me, your case is easier to solve with FuncAnimation instead of ArtistAnimation, even if you already have access to the full list of data you want to show animated (see this thread for a discussion about the difference between the two functions).
Inspired from this FuncAnimation example, I wrote the code below that does what you needed (using the same code with ArtistAnimation and correct list of arguments does not work).
The main idea is to initialize all elements to be animated at the beginning, and to update them over the animation frames. This can be done for the text object (step_txt = fig.text(...)) in charge of displaying the current step, and for the images out from ax.imshow. You can then update whatever object you would like to see animated with this recipe.
Note that the technique works if you want the text to be an x_label or any text you choose to show. See the commented line in the code.
#!/Users/seydoux/anaconda3/envs/jupyter/bin/python
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
# parameters
n_frames = 10
n_splots = 6
n_cols = 3
n_rows = n_splots // n_cols
def update_data(x):
return x ** 2
# create all snapshots
snapshots = [np.random.rand(n_splots, 32, 32, 3)]
for _ in range(n_frames):
snapshots.append(update_data(snapshots[-1]))
# initialize figure and static elements
fig, axes = plt.subplots(2, 3)
axes = axes.ravel() # so we can access all axes with a single index
for i, ax in enumerate(axes):
ax.set_xticks([])
ax.set_yticks([])
ax.set_title("target: {}".format(i))
# initialize elements to be animated
step_txt = fig.text(0.5, 0.95, "step: 0", ha="center", weight="bold")
# step_txt = axes[4].set_xlabel("step: 0") # also works with x_label
imgs = list()
for a, s in zip(axes, snapshots[0]):
imgs.append(a.imshow(s, interpolation="none", cmap="gray"))
# animation function
def animate(i):
# update images
for img, s in zip(imgs, snapshots[i]):
img.set_data(s)
# update text
step_txt.set_text("step: {}".format(i))
# etc
anim = FuncAnimation(fig, animate, frames=n_frames, interval=300)
anim.save("test.gif", writer=PillowWriter())
Here is the output I got from the above code:
Related
I'm trying to plot data that is generated in runtime. In order to do so I'm using matplotlib.animation.FuncAnimation.
While the data is displayed correctly, the axis values are not updating accordingly to the values that are being displayed:
The x axis displays values from 0 to 10 eventhough I update them in every iteration in the update_line function (see code below).
DataSource contains the data vector and appends values at runtime, and also returns the indexes of the values being returned:
import numpy as np
class DataSource:
data = []
display = 10
# Append one random number and return last 10 values
def getData(self):
self.data.append(np.random.rand(1)[0])
if(len(self.data) <= self.display):
return self.data
else:
return self.data[-self.display:]
# Return the index of the last 10 values
def getIndexVector(self):
if(len(self.data) <= self.display):
return list(range(len(self.data)))
else:
return list(range(len(self.data)))[-self.display:]
I've obtained the plot_animation function from the matplotlib docs.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from datasource import DataSource
def update_line(num, source, line):
data = source.getData()
indexs = source.getIndexVector()
if indexs[0] != 0:
plt.xlim(indexs[0], indexs[-1])
dim=np.arange(indexs[0],indexs[-1],1)
plt.xticks(dim)
line.set_data(indexs,data)
return line,
def plot_animation():
fig1 = plt.figure()
source = DataSource()
l, = plt.plot([], [], 'r-')
plt.xlim(0, 10)
plt.ylim(0, 1)
plt.xlabel('x')
plt.title('test')
line_ani = animation.FuncAnimation(fig1, update_line, fargs=(source, l),
interval=150, blit=True)
# To save the animation, use the command: line_ani.save('lines.mp4')
plt.show()
if __name__ == "__main__":
plot_animation()
How can I update the x axis values in every iteration of the animation?
(I appreciate suggestions to improve the code if you see any mistakes, eventhough they might not be related to the question).
Here is a simple case of how you can achieve this.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
%matplotlib notebook
#data generator
data = np.random.random((100,))
#setup figure
fig = plt.figure(figsize=(5,4))
ax = fig.add_subplot(1,1,1)
#rolling window size
repeat_length = 25
ax.set_xlim([0,repeat_length])
ax.set_ylim([-2,2])
#set figure to be modified
im, = ax.plot([], [])
def func(n):
im.set_xdata(np.arange(n))
im.set_ydata(data[0:n])
if n>repeat_length:
lim = ax.set_xlim(n-repeat_length, n)
else:
lim = ax.set_xlim(0,repeat_length)
return im
ani = animation.FuncAnimation(fig, func, frames=data.shape[0], interval=30, blit=False)
plt.show()
#ani.save('animation.gif',writer='pillow', fps=30)
Solution
My problem was in the following line:
line_ani = animation.FuncAnimation(fig1, update_line, fargs=(source, l),
interval=150, blit=True)
What I had to do is change the blit parameter to False and the x axis started to move as desired.
I'm trying to recreate Comway's game of life from this website: https://www.geeksforgeeks.org/conways-game-life-python-implementation/
And I'm facing an issue with the next section of the code:
def main():
# Command line args are in sys.argv[1], sys.argv[2] ..
# sys.argv[0] is the script name itself and can be ignored
# parse arguments
parser = argparse.ArgumentParser(description="Runs Conway's Game of Life simulation.")
# add arguments
parser.add_argument('--grid-size', dest='N', required=False)
parser.add_argument('--mov-file', dest='movfile', required=False)
parser.add_argument('--interval', dest='interval', required=False)
parser.add_argument('--glider', action='store_true', required=False)
parser.add_argument('--gosper', action='store_true', required=False)
args, unknown = parser.parse_known_args()
# args = parser.parse_args()
# set grid size
N = 100
if args.N and int(args.N) > 8:
N = int(args.N)
# set animation update interval
updateInterval = 50
if args.interval:
updateInterval = int(args.interval)
# declare grid
grid = np.array([])
# check if "glider" demo flag is specified
if args.glider:
grid = np.zeros(N*N).reshape(N, N)
addGlider(1, 1, grid)
elif args.gosper:
grid = np.zeros(N*N).reshape(N, N)
addGosperGliderGun(10, 10, grid)
else: # populate grid with random on/off -
# more off than on
grid = randomGrid(N)
%matplotlib notebook
# set up animation
fig, ax = plt.subplots()
img = ax.imshow(grid, interpolation='nearest')
ani = animation.FuncAnimation(fig, update, fargs=(img, grid, N, ),
frames = 10,
interval=updateInterval,
save_count=50)
# # of frames?
# set output file
if args.movfile:
ani.save(args.movfile, fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()
# call main
if __name__ == '__main__':
main()
I already did some changes to the code since I'm working on Jupyter Notebook and parser arguments were not working as initially stated.
The idea of this exercise is to generate an animation. Nonetheless, the animation is not working and it just shows a sort of .png image which is not animated.
As per this response, I should add the next line (which I did):
%matplotlib tk
And it generates an interactive backend with the following options: home, back, forward, pan, zoom and download buttons. However, they are not working either. All the available frames show the same image and download button shows an empty tab.
So, my question is the following: How can this code be improved in order to get the animation working? I think that %matplotlib tk may go anywhere else (like before an specific line) but I have tried some combinations and what I got has been the closest to what I'm looking for.
Pd: I also looked at this response, but this approach didn't work.
I try this, and run:
%matplotlib tk
N = 100
updateInterval = 50
grid = randomGrid(N)
fig, ax = plt.subplots()
img = ax.imshow(grid, interpolation='nearest')
ani = animation.FuncAnimation(
fig,
update,
fargs=(img, grid, N, ),
frames=10,
interval=updateInterval,
save_count=50
)
plt.show()
I only clean the code removing argparse and add '%matplotlib tk' as you say, in one cell and run.
Edit #1
To help you with your question in comments I write this function.
def makeGrid(grid, text):
for i, line in enumerate(text.splitlines()[1:]):
print(line)
for j, point in enumerate(line):
if point != " ":
grid[i][j] = 255
return grid
Try this:
%matplotlib tk
N = 50
updateInterval = 50
grid = randomGrid(N)
grid.fill(0)
grid = makeGrid(grid, '''
x
x x
xx xx xx
x x xx xx
xx x x xx
xx x x xx x x
x x x
x x
xx
''')
fig, ax = plt.subplots()
img = ax.imshow(grid, interpolation='nearest')
ani = animation.FuncAnimation(
fig,
update,
fargs=(img, grid, N, ),
frames=10,
interval=updateInterval,
save_count=50
)
plt.show()
Edit #2
I like this, and I update how to modify the grid...
gliderstr = '''
--x
x-x
-xx
'''
gunstr = '''
------------------------x
----------------------x-x
------------xx------xx------------xx
-----------x---x----xx------------xx
xx--------x-----x---xx
xx--------x---x-xx----x-x
----------x-----x-------x
-----------x---x
------------xx
'''
def fill_grid(grid, iterable, value=255):
for x, y in iterable:
grid[x][y] = value
return grid
def iter_text(text, accept='x', x=0, y=0):
for i, line in enumerate(text.splitlines()):
for j, ch in enumerate(line):
if ch == accept:
yield i + x, j + y
Use like:
%matplotlib tk
N = 100
update_interval = 50
grid = make_grid(N)
fill_grid(grid, iter_text(gunstr, 20, 20))
fill_grid(grid, iter_text(gliderstr, 0, 0))
fig, ax = plt.subplots()
img = ax.imshow(grid, interpolation='nearest')
ani = animation.FuncAnimation(
fig,
update,
fargs=(img, grid, N, ),
frames=10,
interval=update_interval,
save_count=50
)
plt.show()
I'm trying to plot the time evolution of a function f(x,t). The data is stored in a file which has the following format:
1st row:f(0,0) f(0,1) f(0,2) ....f(0,N)
2nd row:f(1,0) f(1,1) f(1,2) ....f(1,N)
Mth row:f(M,0) f(M,1) f(M,2) ....f(M,N)
where N is the no: of points of the simulation box and M is the number of timesteps.
I used basic_animation by Jake Vanderplas (https://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/) to start with, the original example works fine as long as i put blit=False.
Then i tried to replace x by :
x= np.arange(0,192)
and y by the contents of the file mentioned above.
If i do just plt.plot(x,y), it does plot f(x,t) at a given time t, but I want the animation of f(x,t) in time.
set_data should accept 2 1Darrays and I've checked that len(x)=len(y).
But I get the following error message:
'RuntimeError: xdata and ydata must be the same length'
This is the code (in the future i would like to plot multiple functions):
"""
Modified Matplotlib Animation Example
original example:
email: vanderplas#astro.washington.edu
website: http://jakevdp.github.com
license: BSD
Feel free to use and modify this, but keep the above information.
"""
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
from itertools import islice
filename = 'DensityByPropagation__a_0_VHxcS_kick'
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 192), ylim=(-2, 2))
lineS, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
lineS.set_data([], [])
return lineS,
# animation function. This is called sequentially
def animate(i):
w = np.linspace(0, 2, 1000)
z = np.sin(2 * np.pi * (w - 0.01 * i))
x= np.arange(0,192)
with open(filename) as fobj:
ketchup = islice(fobj, 0, None, 10)
for line in ketchup:
x,y = x,zip(*([float(y) for y in line.split("\t")] for line in fobj))
#plt.plot(x,y)
#plt.show()
#print len(x)
#print len(y)
#lineS.set_data(w,z)
lineS.set_data(x,y)
return lineS,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=False)
# save the animation as an mp4. This requires ffmpeg or mencoder to be
# installed. The extra_args ensure that the x264 codec is used, so that
# the video can be embedded in html5. You may need to adjust this for
# your system: for more information, see
# http://matplotlib.sourceforge.net/api/animation_api.html
anim.save('movieJoh.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()
I'm not sure what exactly is causing your error, but let me point something out, then I'll make a toy example that should help clarify what's happening.
These lines seem unnecessarily complicated.
with open(filename) as fobj:
ketchup = islice(fobj, 0, None, 10)
for line in ketchup:
x,y = x,zip(*([float(y) for y in line.split("\t")] for line in fobj))
If your data is in fact in the simple format you stated, i.e., values separated by spaces, np.loadtxt() would load all the values into an easy to manage array.
Example
Lets assume this is your data file (10 time steps, 2 points on plot at each step):
0 0 0 0 0 0 0 0 0 0
9 8 7 6 5 4 3 2 1 0
Now some code:
filename = 'data.txt'
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 1), ylim=(0, 9))
lineS, = ax.plot([], [], lw=2)
x = range(2) # the domain
Now we load the data in with np.loadtxt(), this creates a 2-d matrix with t in the columns and x in the rows. We then transpose it to make indexing each time step possible in animate().
# load the data from file
data = np.loadtxt(filename)
# transpose so we could easily index in the animate() function
data = np.transpose(data)
Now for animation functions. This part is really quite simple. animate(i) takes one argument - the frame number. Using the frame number, we extract the values of f(x,t=frameNumber) and set that as the data on the plot.
# initialization function: plot the background of each frame
def init():
lineS.set_data([], [])
return lineS,
# animation function. This is called sequentially
def animate(i):
lineS.set_data(x, data[i])
return lineS,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=10, interval=100, blit=True)
plt.show()
This is the working code:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# Input
filename = 'PeriodicDensity' # Filename
x = np.linspace(-7.5,7.5,192) # Domain
xLimits=[-7.5,7.5] # x limits
yLimits=[0,1] # y limits
framesToUse = range(1,9000,150)# The time-steps to plot
# load the data from file
data = np.loadtxt(filename)
# Set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=xLimits,ylim=yLimits)
lineS, = ax.plot([], [], lw=2)
# Initialisation function
def init():
lineS.set_data([],[])
return lineS,
# Animation function (called sequentially)
def animate(i):
lineS.set_data(x,data[i])
return lineS,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,interval=1000, frames=framesToUse, blit=True)
# save the animation as an mp4. This requires ffmpeg or mencoder to be
# installed. The extra_args ensure that the x264 codec is used, so that
# the video can be embedded in html5. You may need to adjust this for
# your system: for more information, see
# http://matplotlib.sourceforge.net/api/animation_api.html
anim.save('movieDensity.mp4', fps=1, extra_args=['-vcodec', 'libx264'])
plt.show()
I was wondering how I am able to plot images side by side using matplotlib for example something like this:
The closest I got is this:
This was produced by using this code:
f, axarr = plt.subplots(2,2)
axarr[0,0] = plt.imshow(image_datas[0])
axarr[0,1] = plt.imshow(image_datas[1])
axarr[1,0] = plt.imshow(image_datas[2])
axarr[1,1] = plt.imshow(image_datas[3])
But I can't seem to get the other images to show. I'm thinking that there must be a better way to do this as I would imagine trying to manage the indexes would be a pain. I have looked through the documentation although I have a feeling I may be look at the wrong one. Would anyone be able to provide me with an example or point me in the right direction?
EDIT:
See the answer from #duhaime if you want a function to automatically determine the grid size.
The problem you face is that you try to assign the return of imshow (which is an matplotlib.image.AxesImage to an existing axes object.
The correct way of plotting image data to the different axes in axarr would be
f, axarr = plt.subplots(2,2)
axarr[0,0].imshow(image_datas[0])
axarr[0,1].imshow(image_datas[1])
axarr[1,0].imshow(image_datas[2])
axarr[1,1].imshow(image_datas[3])
The concept is the same for all subplots, and in most cases the axes instance provide the same methods than the pyplot (plt) interface.
E.g. if ax is one of your subplot axes, for plotting a normal line plot you'd use ax.plot(..) instead of plt.plot(). This can actually be found exactly in the source from the page you link to.
One thing that I found quite helpful to use to print all images :
_, axs = plt.subplots(n_row, n_col, figsize=(12, 12))
axs = axs.flatten()
for img, ax in zip(imgs, axs):
ax.imshow(img)
plt.show()
You are plotting all your images on one axis. What you want ist to get a handle for each axis individually and plot your images there. Like so:
fig = plt.figure()
ax1 = fig.add_subplot(2,2,1)
ax1.imshow(...)
ax2 = fig.add_subplot(2,2,2)
ax2.imshow(...)
ax3 = fig.add_subplot(2,2,3)
ax3.imshow(...)
ax4 = fig.add_subplot(2,2,4)
ax4.imshow(...)
For more info have a look here: http://matplotlib.org/examples/pylab_examples/subplots_demo.html
For complex layouts, you should consider using gridspec: http://matplotlib.org/users/gridspec.html
If the images are in an array and you want to iterate through each element and print it, you can write the code as follows:
plt.figure(figsize=(10,10)) # specifying the overall grid size
for i in range(25):
plt.subplot(5,5,i+1) # the number of images in the grid is 5*5 (25)
plt.imshow(the_array[i])
plt.show()
Also note that I used subplot and not subplots. They're both different
Below is a complete function show_image_list() that displays images side-by-side in a grid. You can invoke the function with different arguments.
Pass in a list of images, where each image is a Numpy array. It will create a grid with 2 columns by default. It will also infer if each image is color or grayscale.
list_images = [img, gradx, grady, mag_binary, dir_binary]
show_image_list(list_images, figsize=(10, 10))
Pass in a list of images, a list of titles for each image, and other arguments.
show_image_list(list_images=[img, gradx, grady, mag_binary, dir_binary],
list_titles=['original', 'gradx', 'grady', 'mag_binary', 'dir_binary'],
num_cols=3,
figsize=(20, 10),
grid=False,
title_fontsize=20)
Here's the code:
import matplotlib.pyplot as plt
import numpy as np
def img_is_color(img):
if len(img.shape) == 3:
# Check the color channels to see if they're all the same.
c1, c2, c3 = img[:, : , 0], img[:, :, 1], img[:, :, 2]
if (c1 == c2).all() and (c2 == c3).all():
return True
return False
def show_image_list(list_images, list_titles=None, list_cmaps=None, grid=True, num_cols=2, figsize=(20, 10), title_fontsize=30):
'''
Shows a grid of images, where each image is a Numpy array. The images can be either
RGB or grayscale.
Parameters:
----------
images: list
List of the images to be displayed.
list_titles: list or None
Optional list of titles to be shown for each image.
list_cmaps: list or None
Optional list of cmap values for each image. If None, then cmap will be
automatically inferred.
grid: boolean
If True, show a grid over each image
num_cols: int
Number of columns to show.
figsize: tuple of width, height
Value to be passed to pyplot.figure()
title_fontsize: int
Value to be passed to set_title().
'''
assert isinstance(list_images, list)
assert len(list_images) > 0
assert isinstance(list_images[0], np.ndarray)
if list_titles is not None:
assert isinstance(list_titles, list)
assert len(list_images) == len(list_titles), '%d imgs != %d titles' % (len(list_images), len(list_titles))
if list_cmaps is not None:
assert isinstance(list_cmaps, list)
assert len(list_images) == len(list_cmaps), '%d imgs != %d cmaps' % (len(list_images), len(list_cmaps))
num_images = len(list_images)
num_cols = min(num_images, num_cols)
num_rows = int(num_images / num_cols) + (1 if num_images % num_cols != 0 else 0)
# Create a grid of subplots.
fig, axes = plt.subplots(num_rows, num_cols, figsize=figsize)
# Create list of axes for easy iteration.
if isinstance(axes, np.ndarray):
list_axes = list(axes.flat)
else:
list_axes = [axes]
for i in range(num_images):
img = list_images[i]
title = list_titles[i] if list_titles is not None else 'Image %d' % (i)
cmap = list_cmaps[i] if list_cmaps is not None else (None if img_is_color(img) else 'gray')
list_axes[i].imshow(img, cmap=cmap)
list_axes[i].set_title(title, fontsize=title_fontsize)
list_axes[i].grid(grid)
for i in range(num_images, len(list_axes)):
list_axes[i].set_visible(False)
fig.tight_layout()
_ = plt.show()
As per matplotlib's suggestion for image grids:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
fig = plt.figure(figsize=(4., 4.))
grid = ImageGrid(fig, 111, # similar to subplot(111)
nrows_ncols=(2, 2), # creates 2x2 grid of axes
axes_pad=0.1, # pad between axes in inch.
)
for ax, im in zip(grid, image_data):
# Iterating over the grid returns the Axes.
ax.imshow(im)
plt.show()
I end up at this url about once a week. For those who want a little function that just plots a grid of images without hassle, here we go:
import matplotlib.pyplot as plt
import numpy as np
def plot_image_grid(images, ncols=None, cmap='gray'):
'''Plot a grid of images'''
if not ncols:
factors = [i for i in range(1, len(images)+1) if len(images) % i == 0]
ncols = factors[len(factors) // 2] if len(factors) else len(images) // 4 + 1
nrows = int(len(images) / ncols) + int(len(images) % ncols)
imgs = [images[i] if len(images) > i else None for i in range(nrows * ncols)]
f, axes = plt.subplots(nrows, ncols, figsize=(3*ncols, 2*nrows))
axes = axes.flatten()[:len(imgs)]
for img, ax in zip(imgs, axes.flatten()):
if np.any(img):
if len(img.shape) > 2 and img.shape[2] == 1:
img = img.squeeze()
ax.imshow(img, cmap=cmap)
# make 16 images with 60 height, 80 width, 3 color channels
images = np.random.rand(16, 60, 80, 3)
# plot them
plot_image_grid(images)
Sample code to visualize one random image from the dataset
def get_random_image(num):
path=os.path.join("/content/gdrive/MyDrive/dataset/",images[num])
image=cv2.imread(path)
return image
Call the function
images=os.listdir("/content/gdrive/MyDrive/dataset")
random_num=random.randint(0, len(images))
img=get_random_image(random_num)
plt.figure(figsize=(8,8))
plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
Display cluster of random images from the given dataset
#Making a figure containing 16 images
lst=random.sample(range(0,len(images)), 16)
plt.figure(figsize=(12,12))
for index,value in enumerate(lst):
img=get_random_image(value)
img_resized=cv2.resize(img,(400,400))
#print(path)
plt.subplot(4,4,index+1)
plt.imshow(img_resized)
plt.axis('off')
plt.tight_layout()
plt.subplots_adjust(wspace=0, hspace=0)
#plt.savefig(f"Images/{lst[0]}.png")
plt.show()
Plotting images present in a dataset
Here rand gives a random index value which is used to select a random image present in the dataset and labels has the integer representation for every image type and labels_dict is a dictionary holding key val information
fig,ax = plt.subplots(5,5,figsize = (15,15))
ax = ax.ravel()
for i in range(25):
rand = np.random.randint(0,len(image_dataset))
image = image_dataset[rand]
ax[i].imshow(image,cmap = 'gray')
ax[i].set_title(labels_dict[labels[rand]])
plt.show()
I have made an animation from a set of images like this (10 snapshots):
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import time
infile = open ('out.txt')
frame_counter = 0
N_p = 100
N_step = 10
N_line = N_p*N_step
for s in xrange(N_step):
x, y = [], []
for i in xrange(N_p):
data = infile.readline()
raw = data.split()
x.append(float(raw[0]))
y.append(float(raw[1]))
xnp = np.array(x)
ynp = np.array(y)
fig = plt.figure(0)
ax = fig.add_subplot(111, aspect='equal')
for x, y in zip(xnp, ynp):
cir = Circle(xy = (x, y), radius = 1)
cir.set_facecolor('red')
ax.add_artist(cir)
cir.set_clip_box(ax.bbox)
ax.set_xlim(-10, 150)
ax.set_ylim(-10, 150)
fig.savefig("step.%04d.png" % frame_counter)
ax.remove()
frame_counter +=1
Now I want to add a legend to each image showing the time step.
For doing this I must set legends to each of these 10 images. The problem is that I have tested different things like ax.set_label , cir.set_label, ...
and I get errors like this:
UserWarning: No labelled objects found. Use label='...' kwarg on individual plots
According to this error I must add label to my individual plots, but since this is a plot of Artists, I don't know how I can do this.
If for whatever reason you need a legend, you can show your Circle as the handle and use some text as the label.
ax.legend(handles=[cir], labels=["{}".format(frame_counter)])
If you don't really need a legend, you can just use some text to place inside the axes.
ax.text(.8,.8, "{}".format(frame_counter), transform=ax.transAxes)