3
$\begingroup$

So I'm trying to create an animation of N interacting particles in two dimensions confined in a box. Generating the data is fine and it's being stored in a text file with two columns for each particle; one for its x coordinate and one for y. At the moment this is the code I've got to animate 4 particles, so a file with 8 columns:

data = Import["many_particles.txt", "Table"];
Animate[Graphics[{PointSize[0.025], Red, 
   Point[{data[[i, 1]], data[[i, 2]]}], PointSize[0.025], Blue, 
   Point[{data[[i, 3]], data[[i, 4]]}], PointSize[0.025], Green, 
   Point[{data[[i, 5]], data[[i, 6]]}], PointSize[0.025], Pink, 
   Point[{data[[i, 7]], data[[i, 8]]}]}, Axes -> False, 
   PlotRange -> {{-4, 4}, {-4, 4}}, Frame -> True], {i, 1, 3000, 1}, 
   AnimationRate -> 30, AnimationRunning -> True]  

And that gives me a visual result that I like, but I'd like to be able to import a data file with any number of columns (so any number of particles), and be able to animate them without writing a ridiculously long animate function to account for every one.

Any help is appreciated, thanks :)

Harry

$\endgroup$
  • 4
    $\begingroup$ Use Partition to break the list onto coordinate pairs, and exploit the fact that Point can contain more than a single point, i.e. Point[{{x1,y1},{x2,y2}}] is valid. Also, consider ListAnimate instead of Animate. $\endgroup$ – Szabolcs Oct 13 '15 at 11:52
4
$\begingroup$

The previous method I posted used ListPlot to generate the frames for the animation, but this is a very slow way to do it if you want to animate thousands of frames. A much quicker way is to just use graphics primitives like in the original post.

Here is a very fast function that will animate an unknown number of particles. I found that using ListAnimate slowed down the execution considerably over Animate, so that is what is used here. Keep in mind, it's usually better to use ListAnimate as it compiles the entire animation before showing it to you so it can handle errors better. When toying around here, I had initially neglected to have Animate only vary the parameter n by integer values, and this made my notebook nearly unresponsive. It's also possible that ListAnimate and Animate use different amounts of memory, but I'm not certain of that.

animation[datalist_, plotopts : OptionsPattern[]] := 
 Module[{point, data2, nparticles, colorlist, imglist, opts, prange},

  (*A simple function to create the graphics primitives*) 
  point[color_, coords_] := {PointSize[0.025], color, Point[coords]};

  (*Partition the data into the right dimensionality*)

  data2 = Partition[#, 2] & /@ datalist;

  (*Generate a list of distinct colors for every particle*)

  nparticles = Length@data2[[1]];
  colorlist = Hue /@ Range[0, 1., 1./nparticles][[2 ;;]];

  (*Generate the list of images*)

  prange = {#, #} &@Through[{Max, Min}[datalist]];
  imglist = 
   Graphics[point @@@ Transpose[{colorlist, #}], 
      Evaluate[FilterRules[{plotopts}, Options[Graphics]]], 
      PlotRange -> prange] & /@ data2;

  (*Animate the list of images - 
  the slower `ListAnimate` is commented out in favor of the more primitive `Animate` *)
  (*ListAnimate[imglist]*)
  Animate[imglist[[n]], {n, 1, Length@imglist, 1}, 
   AnimationRate -> 30, AnimationRunning -> True]
  ]

This can work on OP's data set in about 0.06 seconds on my machine (versus about 50 seconds for the ListPlot solution)

opdata = Import["http://pastebin.com/raw.php?i=6sccqHr8", "Table"];

animation[opdata, BaseStyle -> 20, FrameLabel -> {"x", "y"}, 
  Axes -> False, Frame -> True] // AbsoluteTiming

enter image description here

You can even apply it to a list with 60 particles, and still less than half a second

randomdata = 
  Transpose[
   Table[Accumulate[
     Prepend[RandomReal[{-0.2, 0.2}, {3000}], 
      RandomReal[{-10, 10}]]], {2*60}]];
animation[randomdata, BaseStyle -> 20, FrameLabel -> {"x", "y"}, 
  Axes -> False, Frame -> True] // AbsoluteTiming

enter image description here

Of course, if you want to export the animation for viewing outside the notebook, I would definitely recommend exporting the individual frames as image files and converting them using another program. Mathematica is not great at outputting movie files in my experience.

$\endgroup$
  • $\begingroup$ Thanks for the solution, is certainly works but I'm finding that it takes an awfully long time to run and uses up a lot of memory. Is there a more efficient way of doing it? $\endgroup$ – Harry Keen Oct 14 '15 at 11:57
  • $\begingroup$ Which step takes a long time? Generating the test data, creating the plots, or the final ListAnimate command? I was able to do it all in under 30 seconds on a fresh kernel $\endgroup$ – Jason B. Oct 14 '15 at 11:58
  • $\begingroup$ I'm using my own data now. I commented out the list animate and it still took a while, but it seems that the list animate is where the bulk of the time is taken $\endgroup$ – Harry Keen Oct 14 '15 at 12:03
  • $\begingroup$ Maybe we should adjourn to the chatroom? I could help more, but it will take more specifics and the little icon always pops up here saying to avoid prolonged discussions in the comments section $\endgroup$ – Jason B. Oct 14 '15 at 12:44
  • $\begingroup$ Anyway, if you can point me to your data, maybe put it on pastebin I can look at how long it takes to make the animation. What is your end goal of the animation? To look at in the notebook or to export it to a file to view outside of Mathematica? $\endgroup$ – Jason B. Oct 14 '15 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.