Message Boards Message Boards


Animating a Round of Golf

Posted 6 months ago
1 Reply
3 Total Likes

The video is here.

Sample frame

A few weeks ago, I played my second round of golf. I wanted to make an animation of the round afterwards, so I used my phone to copy my GPS coordinates into an email prior to every shot. The first few lines of the email look like:

(30.4459697,-98.0058705) 1 1 D
(30.4452072,-98.0076069) 1 2 7
(30.4445089,-98.0074688) 1 3 9
(30.4443100,-98.0079318) 1 4 P

The columns after the coordinates are the hole number, stroke number for that hole, and the club I used. This was at a neighborhood course outside of Austin, Texas, while I was visiting a friend. I was playing with a borrowed set of clubs from the 60s, which had woods made of actual wood and no wedges. That's why I was using a 9-iron in the third shot instead of a pitching wedge. Spoiler warning: I'm pretty bad. I shot a 52 on 9 holes, and that is not counting a few re-hits.

There are a few other relevant points to mention on my ad hoc data collection. After I finished a hole, I put a line that had the letter H for the stroke number (for "hole"). Ideally, this would be so I could show the final putt rolling into the hole. But in practice, the GPS positioning wasn't good enough, and it was too tedious to record all of that. So often for the last few putts I just pasted duplicate coordinates, which makes the ball look like it's sitting still at the end of a hole while the final strokes are counted.

On to the coding, at which I'm a bit more experienced. First, we need to import the data and parse it into an association so it's easier to work with.

data = Import["GolfDataLagoVista20180427.txt", "Table"] // 
    Map[PadRight[#, 4, Null] &] // 
   MapAt[Interpreter@"GeoCoordinates", {All, 1}] // 
  Map[AssociationThread[{"Coordinates", "Hole", "Shot", 
       "Club"} -> #] &]

For the design of the animation, I considered having the ball move at a constant speed throughout. But this would lead to the short shots being too fast and hard to understand. So I opted for having each shot, no matter the distance, take two seconds. Roughly, this causes the virtual ball to move much faster during a drive than a putt, as in reality. I wanted the final animation to be a smooth 30 FPS on YouTube, not a choppy GIF, so I opted for 60 frames or 2 seconds per shot. So here is the main function to generate the image for a given frame.

framesPerShot = 60;

frame[n_] := Module[{segment, center, path},
  segment = Floor[(n - 1)/framesPerShot] + 1;
  center = 
   Partition[data, 2, 1][[segment]] // 
    GeoDestination[#[[1, "Coordinates"]], 
      MapAt[#*Mod[n - 1, framesPerShot]/framesPerShot &, 
       GeoDisplacement[#[[1, "Coordinates"]], #[[2, 
          "Coordinates"]]], {1, 1}]] &;
  path = data[[;; segment + 1]] // 
      ReplacePart[{segment + 1, "Coordinates"} -> center] // 
     GroupBy[#, #Hole & -> (#Coordinates &), 
       If[Length@# > 1, {Red, Thickness@.01, CapForm@"Round", Line@#},
          Nothing] &] & // Values;
         NumberQ@data[[segment, "Shot"]], {White, PointSize@.02, 
        }, GeoCenter -> center, GeoRange -> 100, 
       GeoServer -> "DigitalGlobe", ImageSize -> 500], 
      ImageSize -> 500, RasterSize -> 500],
     {300, 500}],
        StringTemplate["Hole: ``  Shot: ``  Club: ``"][
         If[data[[segment, "Shot"]] != "H", data[[segment, "Hole"]], 
          ""], data[[segment, "Shot"]] /. "H" -> "", 
         data[[segment, "Club"]] /. Null -> ""], Scaled@{.5, 1.5}], 18]
      }, ImageSize -> {300, 500}]

Basically, I calculate which shot I'm on (the segment), calculate the frame center by interpolating the GPS coordinates of that segment, generate the lines for the path that has been traced so far, draw the image, and then overlay the text. It is important to set the GeoServer to "DigitalGlobe" in order to get detailed enough images to show the golf course.

Then I just export the frames. It takes about a second per frame on my laptop, or about an hour for this whole animation.

  Export["C:\\users\\michael\\desktop\\frames\\frame" <> ToString@i <>
     ".png", frame@i], {i, 3600}], i]

Finally, I converted the frames into a video with a free program called Blender. Technically, you can do that in Mathematica too, but for this common task, Blender is fast, has a visual display of progress, lots of options, and can handle longer videos because it doesn't load all of the frames into memory at once. Some things that might be simplified in future versions of the Wolfram Language are having built-in interpolation support for GeoPositions/Paths and having AspectRatio work for GeoGraphics. Then I wouldn't have to rasterize and then crop the image. The latter is already working in internal builds. If I continue to play golf (which I've been told to do), maybe I'll continue to improve the presentation and data collection process for future rounds.

I've attached the data file and notebook if you want to follow along at home.

enter image description here - Congratulations! This post is now a Staff Pick as distinguished by a badge on your profile! Thank you, keep it coming!

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
or Discard

Group Abstract Group Abstract