Two figures opening, first one is empty - python

screen_width = 45
screen_height = 45
plt.rcParams["figure.figsize"] = (screen_width, screen_height)
plt.style.use('fivethirtyeight')
plt.tight_layout()
fig, (ax1, ax2) = plt.subplots(2,1)
ax1.set_title("Voltage vs samples")
ax1.grid()
ax1.set_ylabel("Voltage (V)")
ax1.set_xlabel("Samples")
ax2.set_title("Current vs samples")
ax2.set_ylabel("Current (A)")
ax2.set_xlabel("Samples")
ax2.grid()
# animation def
def animate(i):
plt.cla()
ax1.plot(x_vals, y_vals, 'ro')
ax2.plot(x_vals_1, y_vals_1, 'bo')
plt.tight_layout
ani = FuncAnimation(fig, animate, interval=1000)
The code works somewhat. It does animate and update the data how I want it. However, it creates two figures, the first figure is empty and the second figure is the one being updated. Why is this the case?

When plt.tight_layout() is called prior to the creation of a figure, one is created on-the-fly. To avoid the creation of this figure you can simply call plt.tight_layout() after creating a Figure instance, i.e.
# ...
fig, (ax1, ax2) = plt.subplots(2, 1)
plt.tight_layout()
# ...
Also note that the line
def animate(i):
# ...
plt.tight_layout
Does nothing because the function is not called without the trailing parentheses. If you want to call tight_layout in your animate function it should be
def animate(i):
# ...
plt.tight_layout()

Related

How to make a title for this multi-axis matplotlib plot?

This function:
def plotGrid(ax, grid, text=''):
ax.imshow(grid, cmap=cmap, norm=Normalize(vmin=0, vmax=9))
ax.grid(True, which='both', color='lightgrey', linewidth=0.5)
ax.set_yticks([x-0.5 for x in range(1+len(grid))])
ax.set_xticks([x-0.5 for x in range(1+len(grid[0]))])
ax.set_xticklabels([])
ax.set_yticklabels([])
ax.set_title(text)
def plotTaskGrids(task):
nTrain = len(task['train'])
fig, ax = plt.subplots(2, nTrain, figsize=(3*nTrain, 3*2))
for i in range(nTrain):
plotGrid(ax[0, i], task['train'][i]['input'], 'train input')
plotGrid(ax[1, i], task['train'][i]['output'], 'train output')
plt.tight_layout()
plt.title('title')
plt.show()
displays this window:
I would like to replace Figure 1 in the window title with title, but plt.title('title') doesn't accomplish that, instead it changes one of the subtitles. What is the solution?
Perhaps you could try adding num="title" when calling plt.subplots?
fig, ax = plt.subplots(2, nTrain, figsize=(3*nTrain, 3*2), num="title")
This should get passed to the plt.figure call within the subplots call.

Matplotlib plot shows 2 labels on the y-axis

I am trying to generate a continously generated plot in matplotlib. The problem that I am facing is related to the labelling on the right y-axis. The range that shows is my desired, however there is also an additional set off labels (0, 0.2, ... 1,0).
def doAnimation():
fig, ax = plt.subplots()
def animate(i):
data=prices(a,b,c) #this gives a DataFrame with 2 columns (value 1 and 2)
plt.cla()
ax.plot(data.index, data.value1)
ax2 = ax.twinx()
ax2.plot(data.index, data.value2)
plt.gcf().autofmt_xdate()
plt.tight_layout()
return ax, ax2
call = FuncAnimation(plt.gcf(), animate, 1000)
return call
callSave = doAnimation()
plt.show()
Any ideas how can I get rid of the set: 0.0, 0.2, 0.4, 0.6, 0.8, 1.0?
This is how the graph looks:
plt.cla clears the current axes. The first time you call plt.cla, the current axes are ax (ax2 doesn't exist yet). Clearing these axes resets both the x and y range of ax to (0,1). However, on line 8, you plot to ax, and both ranges are appropriately adjusted.
On line 9, you create a new set of axes and call them ax2. When you leave the animate function, the name ax2 will go out of scope, but the axes object to which it refers will persist. These axes are now the current axes.
The second time you call animate, plt.cla clears those axes, resetting the x and y range to (0,1). Then, on line 9, you create a new set of axes and call them ax2. These axes are not the same axes as before! ax2 in fact refers to a third set of axes, which will be cleared the next time you call plt.cla. Each new call to animate makes a new set of axes. The offending axes labels appear to be bolded; in fact, they have been drawn a thousand times.
The simplest (fewest changes) fix would be to move ax2 = ax.twinx() outside of animate, and replace plt.cla with separate calls to ax.cla and ax2.cla.
I think a better approach would be to create the lines outside of animate, and modify their data within animate. While we're at it, let's replace those references to plt.gcf() with references to fig, and set tight_layout via an argument to plt.subplots.
Putting said changes together, we get,
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import pandas as pd
import numpy as np
def dummy_prices():
samples = 101
xs = np.linspace(0, 10, samples)
ys = np.random.randn(samples)
zs = np.random.randn(samples) * 10 + 50
return pd.DataFrame.from_records({'value1': ys, 'value2': zs}, index=xs)
def doAnimation():
fig, ax = plt.subplots(1, 1, tight_layout=True)
fig.autofmt_xdate()
ax2 = ax.twinx()
data = dummy_prices()
line = ax.plot(data.index, data.value1)[0]
line2 = ax2.plot(data.index, data.value2, 'r')[0]
def animate(i):
data = dummy_prices()
line.set_data(data.index, data.value1)
line2.set_data(data.index, data.value2)
return line, line2
animator = FuncAnimation(fig, animate, frames=10)
return animator
def main():
animator = doAnimation()
animator.save('animation.gif')
if __name__ == '__main__':
main()
where animation.gif should look something like,

Trying to make a gif in Python

I'm approximating functions with Fourier Series and I would like to make, hopefully in a simple way, an animated gif of the different approximations. With a for and plt.savefig commands I generate the different frames for the gif but I haven't been able to animate them. The idea is to obtain something like this
This can be done using matplotlib.animation.
EDIT
I'm going to show you how to plot even powers of x like x^2, x^4 and so on. take a look at following example :
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# Setting up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(-10, 10), ylim=(-10, 1000))
line, = ax.plot([], [], lw=2)
# initialization method: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation method. This method will be called sequentially
pow_ = 2
def animate(i):
global pow_
x = np.linspace(-10, 10, 1000)
y = x**pow_
pow_+=2
line.set_data(x, y)
return line,
# 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=200, blit=True)
# if you want to save this animation as an mp4 file, uncomment the line bellow
# anim.save('basic_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()

Animated plot for bar graph and line graph using python subplot

I was able to plot animated graphs using advice from the link below.
matplotlib animation multiple datasets
And my code is here.
tt = time_hr.values[:,0]
yy1 =data1.values[:,0]
yy2 =data2.values[:,0]
fig, ax = plt.subplots()
line1, = ax.plot(tt, yy1, color='k')
line2, = ax.plot(tt, yy2, color='r')
def update(num, tt, yy1, yy2, line1, line2):
line1.set_data(tt[:num], yy1[:num])
line1.axes.axis([0, 1, 0, 2500])
line2.set_data(tt[:num], yy2[:num])
line2.axes.axis([0, 1, 0, 2500])
return line1,line2
ani = animation.FuncAnimation(fig, update, len(time_hr), fargs=[tt, yy1, yy2, line1,line2],interval=25, blit=True)
plt.show()
I also have other data set for bar graph and I created animated bar plot using the code below.
x_pos = np.arange(95)
fig = plt.figure()
ax = plt.axis((-1,96,0,1000))
def animate(i):
plt.clf()
pic = plt.bar(x_pos, data3.iloc[i,:], color='c')
plt.axis((-1,96,0,1000))
return pic,
ani = animation.FuncAnimation(fig, animate, interval=25, repeat=False)
plt.show()
My ultimate goal is to plot both animated bar and line graph in one figure using subplot function so that bar graph will be (1,1) and the line graph will be at (2,1) position of the figure.
Could somebody help me to create animated bar and line graphs in one figure window in python ?
More specifically, how to combine both line graphs and bar graph in one animate function ?
Based on comments below, I modified the code like this.
x_pos = np.arange(95)
tt = time_hr.values[:,0]
yy1 =data1.values[:,0]
yy2 =data2.values[:,0]
fig, (ax1, ax2) = plt.subplots(nrows=2)
line1, = ax2.plot(tt, yy1, color='k')
line2, = ax2.plot(tt, yy2, color='r')
rects = ax1.bar(x_pos, data3.iloc[0,:], color='c')
def update(num, tt, yy1, yy2, x_pos, data3, line1, line2, rects):
line1.set_data(tt[:num], yy1[:num])
line1.axes.axis([0, 1, 0, 2500])
line2.set_data(tt[:num], yy2[:num])
line2.axes.axis([0, 1, 0, 2500])
ax1.clear()
rects= ax1.bar(x_pos, data3.iloc[num,:], color='c')
ax1.axis((-1,96,0,1000))
return line1,line2, rects
ani = animation.FuncAnimation(fig, update, len(time_hr), fargs=[tt, yy1, yy2, x_pos,data3, line1,line2,rects], interval=25, blit=True)
plt.show()
But I got error message like this.
"AttributeError: 'BarContainer' object has no attribute 'set_animated'"
Could you help me How to fix this error ?

Matplotlib Animation showing up empty

There was a similar question here but I'm not having the same issue. Below is a snapshot of my dataset:
Essentially, I'd like to animate the drop off coordinates over time. As you can see the dates are sorted by dropoff_datetime. Here is my code (very similar to the question above).
fig = plt.figure(figsize=(10,10))
ax = plt.axes(xlim=xlim, ylim=ylim)
points, = ax.plot([], [],'.',alpha = 0.4, markersize = 0.05)
def init():
points.set_data([], [])
return points,
# animation function. This is called sequentially
def animate(i):
x = test["dropoff_longitude"]
y = test["dropoff_latitude"]
points.set_data(x, y)
return points,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
Similar to the issue in the problem linked above, my plot is just showing up empty. I believe i'm coding it properly and unlike the link above, I do see the that coordinates are changing over time. I'm not sure why the plot is empty.
Per default one pixel is either 1 point or 0.72 points (depending on whether you run the code in a jupyter notebook or as a standalone plot). If you create a plot with a markersize of 0.05, each marker will thus have a size of 0.05 pixels or 0.07 pixels, respectively. Since it is already quite hard to see 1 pixel on a screen, especially if the alpha is set to 0.4, observing one twentieth of a pixel is simply not possible.
Solution: Set markersize = 5 or higher.
A full working example:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import pandas as pd
test = pd.DataFrame({"dropoff_longitude": [-72,-73,-74,-74],
"dropoff_latitude": [40,41,42,43]})
xlim=(-71,-75)
ylim=(39,44)
fig = plt.figure(figsize=(10,10))
ax = plt.axes(xlim=xlim, ylim=ylim)
points, = ax.plot([], [],'.',alpha = 1, markersize =5)
def init():
points.set_data([], [])
return points,
# animation function. This is called sequentially
def animate(i):
x = test["dropoff_longitude"]
y = test["dropoff_latitude"]
points.set_data(x, y)
return points,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()

Categories