It really helps others reading your code if you split things up and name parts of the code. Let's start with the polynomial.
polynomial[k_] := Total[x^Range[0, 20, 3]] + k x^3;
and the function that finds the roots, and the function that visualizes them
roots[poly_, x_] := roots[poly, x] = Through@*{Re, Im} /@ (x /. NSolve[poly, x])
frame[k_, opacity_] := ListPlot[
roots[polynomial[k], x],
PlotStyle -> Opacity[opacity]
]
And the background can also have its own name so that it is clearly distinguishable in the code.
background = Graphics[{
Gray, Circle[{0, 0}, 1]
},
PlotRange -> 2 {{-1, 1}, {-1, 1}},
Axes -> True
];
Now, a ghost trail is nothing but a plot that includes the current frame and the last lag
number of frames, with each frame faded by age.
visualize[k_, lag_, {min_, max_}] :=
visualize[k, lag, {min, max}] = Module[{mink, frames},
mink = Max[min, k - lag];
frames = frame[#, (# - mink)/(k - mink)] & /@ Range[mink, k];
Show[background, Sequence @@ frames]
]
And so finally:
Animate[
visualize[k, 10, {-50,50}],
{k, -50, 50}
]
Animate
. $\endgroup$