I'm working on an animation that involves two stages, a "rotate" phase and a "fade" phase. The initial graph looks like this:
What I want is to first rotate the graph so that the black line is on the horizontal. Once that's accomplished, I want to fade out the red lines and blue points, so only the red points and black line are visible. My code for attempting this is below (this is in a jupyter cell).
data = m
def init():
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
ax.set(xlim=(-1.2, 1.2), ylim=(-1.2, 1.2))
ax.axis('off')
# Calculate Projections
best_u = get_best_u(m)
projected_points = line_projection(best_u, m)
projection_main_line, = ax.plot(projected_points[0], projected_points[1], c='black')
projection_points, = ax.plot(projected_points[0], projected_points[1], 'or')
projection_lines = []
for i in range(projected_points.shape[1]):
temp_line = ax.plot([m[0, i], projected_points[0, i]], [m[1, i], projected_points[1, i]], '-r')
projection_lines.append(temp_line)
data_line, = ax.plot(m[0], m[1], linestyle='', marker='o')
proj_lines = update_helper(projection_lines, 0)
return [data_line, projection_main_line, projection_points, *proj_lines]
def update_helper(projection_lines, i):
return_list = []
if i < len(projection_lines):
line, = projection_lines[0]
return [line]
else:
line, = projection_lines[i]
return_list.append(line)
next_list = update_helper(projection_lines, i+1)
return return_list + next_list
def rotate_stage(deg, data):
data = rotate_matrix(data, -deg).T
best_u = get_best_u(data)
projected_points = line_projection(best_u, data)
projection_main_line.set_data(projected_points[0], projected_points[1])
projection_points.set_data(projected_points[0], projected_points[1])
for i in range(len(projection_lines)):
line, = projection_lines[i]
line.set_data(
[data[0, i], projected_points[0, i]],[data[1, i], projected_points[1, i]]
)
data_line.set_data(data[0], data[1])
proj_lines = update_helper(projection_lines, 0)
return [data_line, projection_main_line, projection_points, *proj_lines]
def fade_stage(i):
for i in range(len(projection_lines)):
line, = projection_lines[i]
line.set_alpha(max(1 - i*0.05, 0))
data_line.set_alpha(max(1 - i*0.05, 0))
proj_lines = update_helper(projection_lines, 0)
return [data_line, *proj_lines]
def update(i, data):
if i < 45:
return rotate_stage(i, data)
else:
return fade_stage(i - 44)
anim = FuncAnimation(fig, update, interval=1, init_func=init, fargs=[data],frames=64, blit=True)
HTML(anim.to_html5_video())
anim.save('test.mp4', fps=20, dpi=80)
The resulting output looks like this:
I don't quite understand why this is happening - I thought it would first cycle through the rotation and then cycle through the fade, but clearly that's not what's happening. Any insights would be appreciated.
Related
I try to create a live graph with matplotlib animation. below code report error:
UnboundLocalError: local variable 'lines' referenced before assignment
lines is defined above!
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import random
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
queue = []
qSize = 20
N = 3
lines = []
xidx = list(range(0, qSize))
def init():
for i in range(qSize):
queue.append([0]*N)
for i in range(N):
xdata = []
ydata = []
line, = ax.plot(xdata, ydata,label=str(i))
lines.append([line,xdata,ydata])
ax.legend(loc=2)
plt.xticks(rotation=45, ha='right')
#plt.subplots_adjust(bottom=0.30)
plt.title('Demo')
plt.ylabel('x')
plt.ylabel('Value')
return
def tick():
arr = []
for i in range(N):
d = random.randint(i*10,i*10+5)
arr.append(d)
queue.append(arr)
lines = lines[-qSize:]
return
def animate(i):
tick()
df = pd.DataFrame(data)
ax.set_xlim(0,qSize)
ax.set_ylim(df.min().min(),df.max().max())
for i,colname in enumerate(df.columns):
line,xdata,ydata = lines[i]
xdata = xidx
ydata = df[colname]
line.set_xdata(xdata)
line.set_ydata(ydata)
plt.draw()
return
init()
ani = animation.FuncAnimation(fig, animate, fargs=(), interval=1000)
plt.show()
Here is my code.
xls_file = pd.ExcelFile('file.xlsx')
df = xls_file.parse('fileTab')
chart = {'Date': df['Date'],
'Total': df['Total']
}
df = pd.DataFrame(chart, columns = ['Date', 'Total'])
title = 'Total'
x = np.array(df.index)
y = np.array(df['Total'])
yData = pd.DataFrame(y,x)
yData.columns = {title}
fig = plt.figure(figsize=(10,6))
# plt.xlim(df['Date'][0])
plt.gcf().subplots_adjust(bottom=.20)
plt.gcf().subplots_adjust(left=.20)
plt.ylim(np.min(yData)[0], np.max(yData)[0])
plt.xlabel('Yr',fontsize=20)
plt.ylabel(title,fontsize=20)
plt.xticks(rotation=90)
ax = plt.subplot(111)
ax.set_xticks(range(43))
ax.set_xticklabels(df['Date'])
def formatY(x, pos):
s = '%d' % x
groups = []
while s and s[-1].isdigit():
groups.append(s[-3:])
s = s[:-3]
return s + ','.join(reversed(groups))
def animate(i):
data = yData.iloc[:int(i+1)] #select data range
p = sns.lineplot(x=data.index, y=data[title], color="r")
p.tick_params(labelsize=7)
plt.setp(p.lines,linewidth=2)
ani = matplotlib.animation.FuncAnimation(fig, animate, interval = 50, repeat=False)
ax.yaxis.set_major_formatter(tkr.FuncFormatter(formatY))
plt.show()
I am trying to only animate the line itself. However, currently, the xAxis animates with the line. Each index on the X axis shows up during each interval. How can I have the xAxis show when the graph loads?
I'm trying to write a piece of code that generates a random walk for a scatterplot in pyplot, but keeping getting error: TypeError: object of type 'NoneType' has no len()
from random import choice
class RandomWalk:
def __init__(self, num_points=5000):
self.num_points = num_points
self.x_values = [0]
self.y_values = [0]
def get_step(self):
step = (choice([x for x in range(20)])) * (choice([1, -1]))
return step
def fill_walk(self):
while len(self.x_values) < self.num_points:
x_step = self.get_step()
y_step = self.get_step()
if x_step == 0 and y_step == 0:
continue
self.x_values = self.x_values.append((self.x_values[-1] + x_step))
self.y_values = self.y_values.append((self.y_values[-1] + y_step))
And this is the plot code:
rw = RandomWalk(5_000)
rw.fill_walk()
plt.style.use('classic')
fix, ax = plt.subplots(figsize=(15, 9))
point_numbers = range(rw.num_points)
ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.rainbow, edgecolors='none', s=5)
ax.scatter(0, 0, c='green', edgecolors='none', s=100)
ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none', s=100)
plt.show()
For some reason self.x_values is not being passed, and I get the TypeError for this line:
while len(self.x_values) < self.num_points:
Any idea why it's not being passed?
self.x_values = self.x_values.append(...)
The issue is in the line above - append just return None
Trying to plot persuit curves with spiraling in lines and a shrinking, rotating polygon with corners at each of the current points
problem = can't get both line of sight lines and main lines to simultaneously plot
The figure flicks back and forth between the shrinking polygon(described by SightLine) and the main persuit curves (MainLines)
When individually animated one at a time, the polygon and pursuit curves plot fine but I just can't get them to work together on the same figure.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
%matplotlib notebook
plt.style.use('dark_background')
NumOfPoints = 6
deltaT = 0.005
duration = 50
steps = int(duration / deltaT)
speed = 0.2
num = 0
CurrentXPoints = []
CurrentYPoints = []
DeltaX = np.zeros(NumOfPoints)
DeltaY = np.zeros(NumOfPoints)
MagnitudeDelta = np.zeros(NumOfPoints)
VelocityX = np.zeros(NumOfPoints)
VelocityY = np.zeros(NumOfPoints)
#Creates Initial Points by equally spacing the points around a polygon inscribed around circle
for i in range(0,NumOfPoints):
x = np.cos(((i/NumOfPoints)*2)*np.pi)
y = np.sin(((i/NumOfPoints)*2)*np.pi)
CurrentXPoints.append(x)
CurrentYPoints.append(y)
AllXPoints = np.array([CurrentXPoints])
AllYPoints = np.array([CurrentYPoints])
#Fills out both AllXPoints and AllYPoints with all points in duration
for i in range(int(steps)):
for j in range(0,NumOfPoints-1): #Calculates deltaX and deltaY at this timestep
DeltaX[j] = CurrentXPoints[j+1] - CurrentXPoints[j]
DeltaY[j] = CurrentYPoints[j+1] - CurrentYPoints[j]
DeltaX[NumOfPoints-1] = CurrentXPoints[0] - CurrentXPoints[NumOfPoints-1]
DeltaY[NumOfPoints-1] = CurrentYPoints[0] - CurrentYPoints[NumOfPoints-1]
for j in range(0,NumOfPoints): # calculats new X and Y Points
MagnitudeDelta[j] = ((DeltaX[j])**2 + (DeltaY[j])**2)**(1/2)
VelocityX[j] = speed * (DeltaX[j]/MagnitudeDelta[j])
VelocityY[j] = speed * (DeltaY[j]/MagnitudeDelta[j])
CurrentXPoints[j] += deltaT * VelocityX[j]
CurrentYPoints[j] += deltaT * VelocityY[j]
CurrentXPointsArr = np.array(CurrentXPoints)
CurrentYPointsArr = np.array(CurrentYPoints)
AllXPoints = np.vstack((AllXPoints,CurrentXPointsArr))
AllYPoints = np.vstack((AllYPoints,CurrentYPointsArr))
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
MainLines = []
SightLines= []
AllLines = MainLines + SightLines
for i in range(NumOfPoints):
line, = ax.plot([AllXPoints[j][i] for j in range(steps)], [AllYPoints[j][i] for j in range(steps)])
MainLines.append(line)
SightLines.append(line)
def UpdateMain(num, AllXPoints, AllYPoints, MainLines):
for line in MainLines:
position = MainLines.index(line)
line.set_data([AllXPoints[i][position] for i in range(num)], [AllYPoints[i][position] for i in range(num)])
def UpdateSight(num, AllXPoints, AllYPoints, SightLines):
for line in SightLines:
position = SightLines.index(line)
if position < (NumOfPoints-1):
line.set_data([AllXPoints[num][position],AllXPoints[num][position+1]],
[AllYPoints[num][position],AllYPoints[num][position+1]])
else:
line.set_data([AllXPoints[num][position],AllXPoints[num][0]],
[AllYPoints[num][position],AllYPoints[num][0]])
ani1 = animation.FuncAnimation(fig, UpdateMain,steps, fargs=[AllXPoints, AllYPoints, MainLines],
interval=1, blit=True)
ani2 = animation.FuncAnimation(fig, UpdateSight,steps, fargs=[AllXPoints, AllYPoints, SightLines],
interval=1, blit=True)
plt.show()
First, you should use only one FuncAnimation that updates all the artists.
The main problem of your code are the lines
for i in range(NumOfPoints):
line, = ax.plot([AllXPoints[j][i] for j in range(steps)], [AllYPoints[j][i] for j in range(steps)])
MainLines.append(line)
SightLines.append(line)
where you are creating one artist (line) and assign it to two different lists. If you create 2 different lines for each list, then the output is as expected.
Full working code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
%matplotlib notebook
plt.style.use('dark_background')
NumOfPoints = 6
deltaT = 0.005
duration = 50
steps = int(duration / deltaT)
speed = 0.2
num = 0
CurrentXPoints = []
CurrentYPoints = []
DeltaX = np.zeros(NumOfPoints)
DeltaY = np.zeros(NumOfPoints)
MagnitudeDelta = np.zeros(NumOfPoints)
VelocityX = np.zeros(NumOfPoints)
VelocityY = np.zeros(NumOfPoints)
def update(num, AllXPoints, AllYPoints, MainLines, SightLines):
out = []
out.append(UpdateMain(num, AllXPoints, AllYPoints, MainLines))
out.append(UpdateSight(num, AllXPoints, AllYPoints, SightLines))
return out
def UpdateMain(num, AllXPoints, AllYPoints, MainLines):
for line in MainLines:
position = MainLines.index(line)
line.set_data([AllXPoints[i][position] for i in range(num)], [AllYPoints[i][position] for i in range(num)])
return MainLines
def UpdateSight(num, AllXPoints, AllYPoints, SightLines):
for line in SightLines:
position = SightLines.index(line)
if position < (NumOfPoints-1):
line.set_data([AllXPoints[num][position],AllXPoints[num][position+1]],
[AllYPoints[num][position],AllYPoints[num][position+1]])
else:
line.set_data([AllXPoints[num][position],AllXPoints[num][0]],
[AllYPoints[num][position],AllYPoints[num][0]])
return SightLines
#Creates Initial Points by equally spacing the points around a polygon inscribed around circle
for i in range(0,NumOfPoints):
x = np.cos(((i/NumOfPoints)*2)*np.pi)
y = np.sin(((i/NumOfPoints)*2)*np.pi)
CurrentXPoints.append(x)
CurrentYPoints.append(y)
AllXPoints = np.array([CurrentXPoints])
AllYPoints = np.array([CurrentYPoints])
#Fills out both AllXPoints and AllYPoints with all points in duration
for i in range(int(steps)):
for j in range(0,NumOfPoints-1): #Calculates deltaX and deltaY at this timestep
DeltaX[j] = CurrentXPoints[j+1] - CurrentXPoints[j]
DeltaY[j] = CurrentYPoints[j+1] - CurrentYPoints[j]
DeltaX[NumOfPoints-1] = CurrentXPoints[0] - CurrentXPoints[NumOfPoints-1]
DeltaY[NumOfPoints-1] = CurrentYPoints[0] - CurrentYPoints[NumOfPoints-1]
for j in range(0,NumOfPoints): # calculats new X and Y Points
MagnitudeDelta[j] = ((DeltaX[j])**2 + (DeltaY[j])**2)**(1/2)
VelocityX[j] = speed * (DeltaX[j]/MagnitudeDelta[j])
VelocityY[j] = speed * (DeltaY[j]/MagnitudeDelta[j])
CurrentXPoints[j] += deltaT * VelocityX[j]
CurrentYPoints[j] += deltaT * VelocityY[j]
CurrentXPointsArr = np.array(CurrentXPoints)
CurrentYPointsArr = np.array(CurrentYPoints)
AllXPoints = np.vstack((AllXPoints,CurrentXPointsArr))
AllYPoints = np.vstack((AllYPoints,CurrentYPointsArr))
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
MainLines = []
SightLines= []
AllLines = MainLines + SightLines
for i in range(NumOfPoints):
line1, = ax.plot([AllXPoints[j][i] for j in range(steps)], [AllYPoints[j][i] for j in range(steps)])
line2, = ax.plot([AllXPoints[j][i] for j in range(steps)], [AllYPoints[j][i] for j in range(steps)])
MainLines.append(line1)
SightLines.append(line2)
ani = animation.FuncAnimation(fig, update, steps, fargs=[AllXPoints, AllYPoints, MainLines, SightLines], interval=1, blit=True)
plt.show()
I've made a graph and here is my code:
def graphdraw(self):
self.xaxis = []
self.yaxis = []
fig=plt.figure(1)
self.ax=fig.add_subplot(111)
plt.xlabel('Wavelenght[nm]')
plt.ylabel('Intensity[arb. unit]')
self.line, = self.ax.plot(self.xaxis,self.yaxis,'g-', linewidth=1.5, markersize=4)
self.ax.set_xlim(-250,250)
self.ax.set_ylim(0,40000)
def drawg(self):
self.graphdraw()
i = -200
while i <= 200:
self.xaxis.append(i)
self.yaxis.append(i*i)
self.line.set_data(self.xaxis,self.yaxis)
plt.draw()
plt.pause(0.1)
i = i + 1
But I'd like it to autoscale axis, and when i do something like this: self.ax.autoscale_view(True,True,True) instead of these lines: self.ax.set_lim... it does not work. I know it may be stupid and trivial question but can anyone help me please?
Ok, nevermind. I've made my own autoscale.
def graphdraw(self):
self.xaxis = []
self.yaxis = []
fig=plt.figure(1)
self.ax=fig.add_subplot(111)
plt.xlabel('Wavelenght[nm]')
plt.ylabel('Intensity[arb. unit]')
self.line, = self.ax.plot(self.xaxis,self.yaxis,'g-', linewidth=1.5, markersize=4)
self.ax.set_xlim(-250,250)
def drawg(self):
self.graphdraw()
i = -200
start = 50
while i <= 200:
z = random.randint(0,450)
self.ax.set_ylim(0,start)
self.xaxis.append(i)
self.yaxis.append(z)
if z > start:
start= z
self.ax.set_ylim(0,start + 50)
self.line.set_data(self.xaxis,self.yaxis)
plt.draw()
plt.pause(0.1)
i = i + 1