1

I have created animation plot of x_graph and y_graph which plots the path of the planet and the plot of x_sun and y_sun in the same plot of x_graph and y_graph having marker = 'o', where the position is fixed for the entire animation i.e., at (-0.8,0). Also I need to show the motion of the planet as a blue dot moving around the sun leaving a small trail behind but not the complete path of its motion.

This is my code but it does not seem to work. The output is just the motion of the planet as an animation. I am not getting that blue dot from the plot of x_sun and y_sun which should be at (-0.8, 0)

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

n = int(input("Enter the number of steps\n"))
s = int(n/2)

def f(r, u, t):
    return 1/r**3-1/r**2  # Equation of r

def g(theta, r, t):
    return 1/r**2  # Equation of theta

x_graph = []
y_graph = []

x1 = []
y1 = []

def func(r_0, theta_0, u_0, t_0, h):
    x = -0.98  # initial value of x
    y = 0      # initial value of y
    for i in range(1, n + 1):
        m1 = h * u_0
        k1 = h * f(r_0, u_0, t_0)
        l1 = h * g(theta_0, r_0, t_0)
        m2 = h * (u_0 + 0.5 * k1)
        k2 = h * f(r_0 + 0.5 * m1, u_0 + 0.5 * k1, t_0 + 0.5 * h)
        l2 = h * g(theta_0 + 0.5 * l1, r_0 + 0.5 * k1, t_0 + 0.5 * h)
        m3 = h * (u_0 + 0.5 * k2)
        k3 = h * f(r_0 + 0.5 * m2, u_0 + 0.5 * k2, t_0 + 0.5 * h)
        l3 = h * g(theta_0 + 0.5 * l2, r_0 + 0.5 * k2, t_0 + 0.5 * h)
        m4 = h * (u_0 + k3)
        k4 = h * f(r_0 + m3, u_0 + k3, t_0 + h)
        l4 = h * g(theta_0 + l3, r_0 + k3, t_0 + h)
        r_0 += (m1 + 2 * m2 + 2 * m3 + m4) / 6
        u_0 += (k1 + 2 * k2 + 2 * k3 + k4) / 6
        theta_0 += (l1 + 2 * l2 + 2 * l3 + l4) / 6
        x = r_0 * np.cos(theta_0)
        y = r_0 * np.sin(theta_0)
        t_0 += h
        x_graph.append(x)
        y_graph.append(y)
    return x, y

fig = plt.figure()
p1 = fig.add_subplot(111)

l1, = p1.plot([],[])
l2, = p1.plot([],[],marker= 'o', ls='')

print(func(0.98, -np.pi, 0, 0, 0.001))
x_sun = np.linspace(-0.8, -0.8, len(x_graph))
y_sun = np.linspace(0,0,len(y_graph))
plt.xlim(-1.2,1.5)
plt.ylim(-1.5,1.5)
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.title('Planet\'s orbit')

def polar_animator(i):
    l1.set_data(x_graph[:i], y_graph[:i])
    return l1, 
def animate(i):
    l2.set_data(x_sun[:i], y_sun[:i])
    return l2,
    
ani = animation.FuncAnimation(fig, polar_animator, frames= len(x_graph), interval=1, 
blit=True)
anim = animation.FuncAnimation(fig, animate, interval=1, blit=True)
ani.save('planet.mp4', writer= 'ffmpeg')

Currently the output looks something like this but I want to have a marker(like a big dot) at point (-0.8, 0) representing sun. Since SO doesn't allow to embed videos, I was unable to attach the video. I am attaching a .png instead

enter image description here

Mr. T
  • 11,960
  • 10
  • 32
  • 54
  • Welcome to SO! Your question is too broad and might receive less attention. It is a good practice at SO to add information like: what you expected, what current output looks like, and your debugging attempt? – vyi Dec 07 '20 at 13:47
  • You can always [embed a gif](https://stackoverflow.com/a/65181776/8881141). – Mr. T Dec 07 '20 at 14:23

1 Answers1

0

Running your code on my machine gives the following output : enter image description here

A few things look out of place.

The animation is being called twice (this caused flickering in my pc). So just call the animation once and update both the elements (infact you only need to touch the sun plotting once so you can still cut on unnecessarily plotting sun every time).

def animate(i):
    l2.set_data(x_sun[:i], y_sun[:i])
    l1.set_data(x_graph[:i], y_graph[:i])
    return l2,l1,
    

Call the animation func once like follows:

anim = animation.FuncAnimation(fig, animate, frames=100, interval=1, blit=True)
vyi
  • 1,078
  • 1
  • 19
  • 46
  • If `sun` does not have to be updated, wouldn't it be better to plot it in an `ini()` function? And shouldn't it be `frames=n` or something similar? – Mr. T Dec 07 '20 at 14:40
  • @vvy. This works fine. Thank you. I wanted to have motion of planet like this – QuantumOscillator Dec 07 '20 at 14:42
  • @Mr.T I don't know much about animations. This is my first time making one. I don't know what ini() function is – QuantumOscillator Dec 07 '20 at 14:44
  • @Mr.T I think you are referring to the `init_func` arg of `animation.FuncAnimation`. I think the sun can be plotted in the initialization of `l1` as follows `l1, = p1.plot(x_val, y_val, marker='o')`. @Arnav if the answer solves the original problem you can accept it. – vyi Dec 07 '20 at 14:51
  • @vvy If I take l1, as you said, in the comment, it doesnt work. It just plots sun and not the planet – QuantumOscillator Dec 07 '20 at 16:03
  • My bad, I confused `l1` and `l2` (room for improving variable naming). What I meant is that you need to move the instruction to plot the sun out of the `animate` method. Here `l2` is the one that plots sun so plot it only once when initializing and comment it out inside the `animate` function (also return only l1 from `animate` function). – vyi Dec 07 '20 at 16:12
  • @vvy I've done that only. It plots sun only and not the planet – QuantumOscillator Dec 07 '20 at 16:19
  • @Arnav Check out [this](https://pastebin.com/zEY2S2Lu) – vyi Dec 07 '20 at 16:20