3d scatter plot animation with blitting - python

I want to make a 3d line plot animation with a point at the last point plotted, like a trajectory for a particule. In a case without blitting, I did it with a scatter plot and a line plot3d, updating both plots in the update function. I tried doing it in the same way, with blitting, but it throws the following error
TypeError: 'Path3DCollection' object is not iterable
My code is the following
import matplotlib.pyplot as m
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
def ranstep(start,step,stop):
numberlist = int((stop - start)/step + 1)
lista = [0]*numberlist
i = 0
while i <= numberlist:
if i == 0:
lista[i] = start
i = i + 1
if i != 0 and i < numberlist - 1:
lista[i] = lista[i - 1] + step
i = i + 1
if i != 0 and i == numberlist - 1:
lista[i] = stop
break
return(lista)
k1 = 10.0
k2 = 28.0
k3 = 8.0/3.0
czeroA = 1
czeroB = 0
czeroC = 0
step = 0.001
tfinal = 100
time = list(ranstep(0,step,tfinal))
cA = [0]*len(time)
cB = [0]*len(time)
cC = [0]*len(time)
i = 0
while i <= len(time) - 1:
if i == 0:
cA[i] = czeroA
cB[i] = czeroB
cC[i] = czeroC
i = i + 1
else:
cA[i] = cA[i - 1] + k1*(cB[i - 1] - cA[i - 1])*step
cB[i] = cB[i - 1] + (cA[i - 1]*(k2 - cC[i - 1]) - cB[i-1])*step
cC[i] = cC[i - 1] + (cA[i - 1]*cB[i-1] - k3*cC[i-1])*step
i = i + 1
fig, ax = m.subplots()
ax = fig.add_subplot(111, projection='3d')
line, = ax.plot3D([], [], [], c = 'blue', lw = 1)
line, = ax.scatter([],[],[], c = 'red', s = 30)
def init():
ax.set_xlim([-20,20])
ax.set_ylim([-20,20])
ax.set_zlim([0,50])
ax.set_xlabel('$x(t)$')
ax.set_ylabel('$y(t)$')
ax.set_zlabel('$z(t)$')
return line,
def update(frame):
line.set_data(cA[0:frame*50],cB[0:frame*50])
line.set_3d_properties(cC[0:frame*50])
line.set_data(cA[frame*500,frame*500 + 1],cB[frame*500,frame*500 + 1])
line.set_3d_properties(cC[frame*500,frame*500 + 1])
return line,
ani = animation.FuncAnimation(fig, update,interval=5, frames = len(time),init_func=init, blit=True)
m.show()

Related

Monte carlo circle

So I'm trying to draw a circle instead of a quarter circle does anyone knows how do I change the commands ?
I want the center of the circle to be in the coordinates (0.5,0.5) , but I don't know how to change it. I know that the I need to change the radius to 0.5 but I can't figure out where I need to change the values for the center. Thanks!
import matplotlib.pyplot as plt
from matplotlib.pyplot import *
matplotlib.use("TkAgg")
fig = figure(figsize=(8, 8), dpi=120)
nTrials = int(100000)
radius = 1
nInside = 0
nDrops = 0
XrandCoords = np.random.default_rng().uniform(0, 1, (nTrials,))
YrandCoords = np.random.default_rng().uniform(0, 1, (nTrials,))
fig1 = plt.figure(1)
plt.get_current_fig_manager().window.wm_geometry("+00+00") # move the window
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.legend()
isFirst1 = True
isFirst2 = True
piValueI = []
nDrops_arr = []
insideX = []
outsideX = []
insideY = []
outsideY = []
for i in range(nTrials):
x = XrandCoords[i]
y = YrandCoords[i]
nDrops = nDrops + 1
if (x ** 2 + y ** 2) <= radius ** 2:
nInside = nInside + 1
insideX.append(x)
insideY.append(y)
else:
outsideX.append(x)
outsideY.append(y)
if i % 100 == 0:
plt.figure(1)
if isFirst1:
plt.scatter(insideX, insideY, c='blue', s=50, label='În interior')
isFirst1 = False
plt.legend(loc=(0.75, 0.9))
else:
plt.scatter(insideX, insideY, c='blue', s=50)
plt.figure(1)
if isFirst2:
plt.scatter(outsideX, outsideY, c='black', s=50, label='În exterior')
isFirst2 = False
plt.legend(loc=(0.75, 0.9))
else:
plt.scatter(outsideX, outsideY, c='black', s=50)
area = 4 * nInside / nDrops
plt.figure(1)
plt.title('Nr de puncte luate = ' + str(nDrops) + '; Nr punctelor din interiorul cercului = ' + str(
nInside) + r'; π ≈ $4\frac{Nr_\mathrm{interior}}{Nr_\mathrm{total}}=$ ' + str(np.round(area, 6)))
piValueI.append(area)
nDrops_arr.append(nDrops)
plt.pause(0.1)
area = 4 * nInside / nTrials
print("Valoare estimată a lui Pi: ", area)
plt.show()
Please try :
radius = 0.5
XrandCoords = np.random.uniform(0.5, 1, (nTrials,))
YrandCoords = np.random.uniform(0.5, 1, (nTrials,))
radius = 0.5
if ((x-0.5) ** 2 + (y-0.5) ** 2) <= radius ** 2:
....

plt.matshow().set_data() is not updating the AxesImage

Here's a program that I am trying to run for Potts Model. It gives the plot once and then keeps repeating the line <Figure size 432x288 with 0 Axes>. What's the solution to get various plots after certain time steps showing the evolution of the system?
import math
import numpy as np
import matplotlib.pyplot as plt
def largest_primes_under(N):
n = N - 1
while n >= 2:
if all(n % d for d in range(2, int(n ** 0.5 + 1))):
return n
n -= 1
def Neighbors(Lattice,i,j,n=1):
''' Returns an flat array of all neighboring sites in the n-th coordination sphere including the center'''
N, M = Lattice.shape
rows = [(i-1) % N, i, (i+1) % N]
cols = [(j-1) % N, j, (j+1) % M]
return Lattice[rows][:, cols].flatten()
def calc_dE(Lattice, x, y, z):
N, M = Lattice.shape
old_energy = 0
new_energy = 0
for i in [0,1,-1]:
for j in [0,1,-1]:
if i == 0 and j == 0:
continue
if Lattice[x%N,y%M] == Lattice[(x+i)%N,(y+j)%M]:
old_energy += 1
elif z == Lattice[(x+i)%N,(y+j)%M]:
new_energy += 1
return old_energy-new_energy
N, M = 100,100
orientations = 3
MCS = int(10)
a = largest_primes_under(N*M)
L = np.random.randint(1,orientations+1,size=(N,M))
mat = plt.matshow(L,cmap = plt.get_cmap('plasma', orientations+1), vmin = -0.5, vmax = orientations+0.5, interpolation='kaiser')
plt.axis('off')
for t in range(1,MCS+1):
rand = np.random.random_integers(N*M)
for i in range(0,N**2):
index = (a*i + rand) % (N**2)
x = index % N
y = index // N
n = Neighbors(L,x,y)
if len(n)-1 == 0:
continue
else:
z = np.random.choice(n)
dE = calc_dE(L,x,y,z)
if (dE < 0):
L[x%N,y%N] = z
elif np.random.sample() < math.exp(-dE*2.5):
L[x%N,y%N] = z
mat.set_data(L)
plt.draw()
plt.pause(0.1)
mat.set_data(L) is not updating the data
In the for-loop, replace mat.set_data(L) with:
mat = plt.matshow(L, cmap = plt.get_cmap('plasma', orientations+1), vmin = -0.5, vmax = orientations+0.5, interpolation='kaiser')
The plots successfully showed up when I tested the code with the change.
Also np.random.random_integers(N*M) is deprecated in numpy v1.20.1. In the code below, np.random.randint(N*M) is used, but this change isn't related to the question in the OP.
for t in range(1, MCS+1):
rand = np.random.randint(N*M)
for i in range(0, N**2):
index = (a*i + rand) % (N**2)
x = index % N
y = index // N
n = Neighbors(L, x, y)
if len(n)-1 == 0:
continue
else:
z = np.random.choice(n)
dE = calc_dE(L, x, y, z)
if (dE < 0):
L[x%N, y%N] = z
elif np.random.sample() < math.exp(-dE*2.5):
L[x%N, y%N] = z
mat = plt.matshow(L, cmap = plt.get_cmap('plasma', orientations+1), vmin = -0.5, vmax = orientations+0.5, interpolation='kaiser')
# mat.set_data(L)
plt.draw()
plt.pause(0.1)
Alternative
In this case it might be more interesting to animate the progression
Implemented with Animate quadratic grid changes (matshow)
In the following code, save_count=MCS takes the place of the original outer loop for t in range(1, MCS+1), where t was just a throwaway variable.
import matplotlib.animation as animation
def generate_data():
rand = np.random.randint(N*M)
for i in range(0, N**2):
index = (a*i + rand) % (N**2)
x = index % N
y = index // N
n = Neighbors(L, x, y)
if len(n)-1 == 0:
continue
else:
z = np.random.choice(n)
dE = calc_dE(L, x, y, z)
if (dE < 0):
L[x%N, y%N] = z
elif np.random.sample() < math.exp(-dE*2.5):
L[x%N, y%N] = z
return L
def update(data):
mat.set_data(data)
return mat
def data_gen():
while True:
yield generate_data()
N, M = 100, 100
orientations = 3
MCS = 10
a = largest_primes_under(N*M)
L = np.random.randint(1, orientations+1, size=(N, M))
fig, ax = plt.subplots()
mat = ax.matshow(generate_data(), cmap=plt.get_cmap('plasma', orientations+1), vmin=-0.5, vmax=orientations+0.5, interpolation='kaiser')
plt.colorbar(mat)
ani = animation.FuncAnimation(fig, update, data_gen, interval=500, save_count=MCS)
plt.show()
ani.save('animation.gif')

How to animate multiple points moving using funcanimation (not ax.scatter())?

I have the code below. If you run that program a scatter plot is created. The plot is very messy. I want every point to represent one car. I only want to see the point of the current position of each car in the animation. I am not very good at matplotlib, but how would I do that?
from matplotlib import pyplot as plt
import random
import math
from matplotlib import animation
import numpy as np
roadLength = 100
numFrames = 200
numCars = 60
velocities = []
positions = []
theta = []
r = []
color = []
probability = 0.5
vmax = 1
flowr = []
fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
ax.axis('off')
for i in range(numCars):
positions.append(i * 2)
theta.append(0)
r.append(1)
color.append(i)
velocities.append(0)
def pos(k):
rand = random.uniform(0,1)
if velocities[k] < vmax:
velocities[k] += 1
if k < numCars-1 and (positions[k+1] - positions[k]) <= velocities[k]:
velocities[k] = positions[k+1] - positions[k] - 1
if k == numCars-1 and (roadLength - (positions[k] - positions[0])) <= velocities[k]:
velocities[k] = roadLength - (positions[k] - positions[0]) - 1
if rand < probability and velocities[k] > 0:
velocities[k] = velocities[k] - 1
positions[k] = positions[k] + velocities[k]
return positions[k]
def animate(frameNr):
for i in range(numCars):
theta[i] = pos(i) * 2 * math.pi / roadLength
flowr.append(velocities[i])
ax.scatter(theta, r, c=color)
return ax.scatter(theta, r, c=color),
def simulate():
anim = animation.FuncAnimation(fig, animate,
frames=numFrames, interval=10, blit=True, repeat=False)
plt.show()
simulate()
Thanks in advance!
Edit:
I fixed so that it became a point plot I am now storing velocity, position and lane in an object for a later problem. My question is:
How do I make the points have different colors?
from matplotlib import pyplot as plt
import random
import math
from matplotlib import animation
import numpy as np
from operator import attrgetter
roadLength = 100
numFrames = 200
nlanes = 1
numCars = 20
posss =[]
theta = []
r = []
color = []
probability = 0.5
vmax = 1
flowr = []
cars=[]
class Car:
def __init__(self, position, velocity, lane):
self.position = position
self.velocity = velocity
self.lane = lane
def pos(car,k):
rand = random.uniform(0,1)
if car[k].velocity < vmax:
car[k].velocity += 1
if k < numCars-1 and (car[k+1].position - car[k].position) <= car[k].velocity:
car[k].velocity = car[k+1].position - car[k].position - 1
if k == numCars-1 and (roadLength - (car[k].position - car[0].position)) <= car[k].velocity:
car[k].velocity = roadLength - (car[k].position - car[0].position) - 1
if rand < probability and car[k].velocity > 0:
car[k].velocity = car[k].velocity - 1
car[k].position = car[k].position + car[k].velocity
return car[k].position
for i in range(numCars):
cars.append(Car(i, 0, 1))
theta.append(0)
r.append(1)
color.append(i)
posss.append(i)
fig = plt.figure()
ax = fig.add_subplot(111)
point, = ax.plot(posss, r, 'o')
ax.set_xlim(-10, 1.2*numFrames)
ax.set_ylim(-2, nlanes + 3)
def animate(frameNr):
sort_cars = sorted(cars, key=attrgetter("position"))
for i in range(numCars):
pos(sort_cars,i)
for k in range(numCars):
theta[k]=cars[k].position
point.set_data(theta, r)
return point,
def simulate():
anim = animation.FuncAnimation(fig, animate,
frames=numFrames, interval=10, blit=True, repeat=False)
plt.show()
simulate()
plot() returns a Line2D object, in which all points have the same color.
If you want your points to have different colors, you should use scatter(). The logic is exactly the same, except you use set_offsets(<2D array>) instead of set_data().
See this question for more details

Python: Animating two lists of lines using matplotlib.animation but only shows one set of lines at a time

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()

Using matplotlib.pyplot to make the animation of the 1D wave equation

I have been using matplotlib from python to show the animation of 1D wave equation.But I got a problem of making the animation.I want the image of the wave to change with time.It means that I may need a loop to form many different pictures of the wave equation.But it seems that the time cannot be put into the wave functions ,so the images do not change at all.Please help me with the mistake that I made.
Here are the codes that I wrote:(Part of the codes comes from the book "Python Scripting for Computational Science")
from numpy import zeros,linspace,sin,pi
import matplotlib.pyplot as mpl
def I(x):
return sin(2*x*pi/L)
def f(x,t):
return sin(x*t)
def solver0(I,f,c,L,n,dt,tstop):
# f is a function of x and t, I is a function of x
x = linspace(0,L,n+1)
dx = L/float(n)
if dt <= 0:
dt = dx/float(c)
C2 = (c*dt/dx)**2
dt2 = dt*dt
up = zeros(n+1)
u = up.copy()
um = up.copy()
t = 0.0
for i in range(0,n):
u[i] = I(x[i])
for i in range(1,n-1):
um[i] = u[i]+0.5*C2*(u[i-1] - 2*u[i] + u[i+1]) + dt2*f(x[i],t)
um[0] = 0
um[n] = 0
while t <= tstop:
t_old = t
t += dt
#update all inner points:
for i in range(1,n-1):
up[i] = -um[i] + 2*u[i] + C2*(u[i-1] - 2*u[i] + u[i+1]) + dt2*f(x[i],t_old)
#insert boundary conditions:
up[0] = 0
up[n] = 0
#update data structures for next step
um = u.copy()
u = up.copy()
return u
c = 3.0 #given by myself
L = 10
n = 100
dt = 0
tstart = 0
tstop = 6
x = linspace(0,L,n+1)
t_values = linspace(tstart,tstop,31)
mpl.ion()
y = solver0(I, f, c, L, n, dt, tstop)
lines = mpl.plot(x,y)
mpl.axis([x[0], x[-1], -1.0, 1.0])
mpl.xlabel('x')
mpl.ylabel('y')
counter = 0
for t in t_values:
y = solver0(I,f,c,L,n,dt,tstop)
lines[0].set_ydata(y)
mpl.draw()
mpl.legend(['t=%4.1f' % t])
mpl.savefig('sea_%04d.png' %counter)
counter += 1
Maybe that's what you need?
y = solver0(I,f,c,L,n,dt,t)

Categories

Resources