This is part 11 of an N part series detailing how I make my animations.
So you’ve made a data visualisation but how do you show it off?
To do that we need to output the animation to some sort of video file and then find some site willing to host it.
I found Processing’s default video creation somewhat underwhelming so I used a slightly more tricky but far superior technique. You will need to download two things, a video creation tool called ffmpeg and a library that plugs into Processing which uses that called Video Export.
First download ffmpeg from ffmpeg.org. I use windows so merely unzip it somewhere (I have a folder called c:\tools\
for such things where I unzipped it and renamed the folder to ffmpeg
. Put c:\tools\ffmpeg\bin
into the user path — I use eveditor.com for this — and you’re good to go).
Now install Video Export by running Processing and open the Contribution Manager by going to the Tools/Add Tool...
menu. Select the Libraries tab and search for Video Export. Click install and you’re done. There’s more info on funprogramming.org.
To use Video Export you first need to import it into your sketch so add these lines to the top of the file:
import com.hamoid.*;VideoExport videoExport;
hamoid
is the github user id of the developer (check out his github account) so I guess he named all the libraries with that as a prefix. The second line defines a variable called videoExport
of the type VideoExport
. Looks confusing until you get used to it.
Next thing we need to do is tell Video Export about our sketch so in setup()
add the following:
videoExport = new VideoExport(this);videoExport.setFrameRate(30);videoExport.startMovie();
new VideoExport(this);
creates an instance of the type VideoExport
providing the current sketch denoted by this
so that it can access the frames.
We are now ready to save individual frames to the video so at the end of draw()
add:
videoExport.saveFrame();
It is important to execute videoExport.endMovie()
when the animation finishes as the video file may get corrupted, if the video doesn’t play then check that this command is executed.
This creates a video file called processing-movie.mp4
in your sketch folder which you can play in your favorite video player.
On your first run of a sketch using Video Export a window will show asking for where you installed ffmpeg.
Check the end of the post to see the full source code of the Keeling animation including the Video Export commands.
So now how do you create a gif? By using ffmpeg of course!
You can simply open a dos prompt¹ or terminal and execute:
ffmpeg -i processing-movie.mp4 processing-movie.gif
This will work most of the time but if you create a video with more than 256 colours you’ll find the quality drops considerably in which case things get a tad more tricky. In this case you need to execute two ffmpeg commands. First is to find out all the colours used in your video and then create the gif using that palette by using these two commands:
ffmpeg -i processing-movie.mp4 -vf "palettegen" -y palette.pngffmpeg -i processing-movie.mp4 -i palette.png -lavfi "fps=50,paletteuse" -y out.gif
For the full gory details read pkh’s blog. I turned the above into a batch script file called makegif.bat
:
ffmpeg -i %1 -vf "palettegen" -y palette.pngffmpeg -i %1 -i palette.png -lavfi "fps=50,paletteuse" -y out.gif
Simply executed by makegif processing-movie.mp4
and it creates a gif called out.gif
.
Now we have an mp4
and a gif
file! What do we do with it? We need to host it somewhere so it can be shared. So here are your options:
Twitter: Simply attach your mp4
file to a tweet. If it’s longer than a certain amount a trimming dialog appears but if you move the start and stop indicators to the beginning and end of the video twitter will happily host it.
YouTube: Upload and go, can add music from YouTube’s free music library, which is nice.
FaceBook: Simply attach your mp4
to a post.
imgur.com: (Pronounced “imager” apparently) is a perfect place to host gifs so you can then post to sites like reddit.com², add the link to emails or perhaps write stories on some site called medium.com. I find that sharing with the imgur community is highly worthwhile too. When hosting there you can either link to the gif directly or to a faster loading gifv
simply by adding a v
to the end of the URL.
Here’s the complete source code of the Keeling animation using Video Export:
import com.hamoid.*;VideoExport videoExport;
import java.time.*;import de.looksgood.ani.*;Ani _ani;
FloatDict _data = new FloatDict();LocalDate _startDate = LocalDate.of(1958, 3, 29);
void setup(){loadData();size(500,500);background(0);stroke(255,255,0);textAlign(CENTER);
Ani.init(this);Ani.setDefaultTimeMode(Ani.FRAMES);_ani = new Ani(this, 530, "_change", 6, Ani.EXPO_IN);
videoExport = new VideoExport(this);videoExport.setFrameRate(30);videoExport.startMovie();}
float yScale = 20.0;
boolean _coda = false;int _codaCount = 0;
float _change = 1.0;final int MARGIN = 60;final float CO2MIN = 313.04;
void draw(){if(_change >= 6.0){if(!_coda){_coda = true;_codaCount = frameCount;}if(frameCount - _codaCount > 120){videoExport.endMovie();exit();}videoExport.saveFrame();return;}
background(0);strokeWeight(1);
line(MARGIN, 0, MARGIN, height);line(0, height - MARGIN, width, height - MARGIN);
drawGraph(MARGIN, height - MARGIN, width - MARGIN, height - MARGIN);videoExport.saveFrame();}
void drawGraph(int xPos, int yPos, int graphWidth, int graphHeight){text("Atmospheric CO₂ concentration 1958 - 2017\nR. F. Keeling, S. J. Walker, S. C. Piper and A. F. Bollenbacher\nMauna Loa, Observatory, Hawaii", MARGIN + graphWidth / 2.0, MARGIN);int deltaX = int(frameCount * _change);
float xScale = 1.0;
int xAxisMaximum = graphWidth;
if(deltaX > graphWidth){xAxisMaximum = deltaX;xScale = float(graphWidth) / float(deltaX);}
text("Year", MARGIN + graphWidth / 2, height - 20);drawXAxis(xAxisMaximum, xScale);
strokeWeight(3);
float co2Max = 0.0;
for(int dataIndex = 1; dataIndex <= deltaX; dataIndex++){
int daysFromStart = (dataIndex - 1) \* 7;
LocalDate frameDate = \_startDate.plusDays(daysFromStart);
if(\_data.hasKey(frameDate.toString()))
{
float co2 = \_data.get(frameDate.toString());
if(co2 > co2Max) co2Max = co2;
float x = dataIndex;
float y = (co2 - CO2MIN);
if(y \* yScale > graphHeight)
{
yScale = float(graphHeight)/y;
}
point(xPos + x \* xScale, yPos - (y \* yScale));
}
}
if((co2Max - CO2MIN) * yScale < graphHeight)co2Max = graphHeight / yScale + CO2MIN;
pushMatrix();translate(0, graphWidth / 2);rotate(-PI / 2.0);text("CO₂ concentration (PPM)", 0, 20);popMatrix();
drawYAxis(co2Max, yScale);}
void drawYAxis(float co2Max, float yScale){float co2Tick = 320.0;strokeWeight(1);
while(co2Tick <= co2Max){float yAxisTickPos = height - MARGIN - (co2Tick - CO2MIN) * yScale;
line(MARGIN, yAxisTickPos, MARGIN - 5.0, yAxisTickPos);
text(int(co2Tick), MARGIN - 15, yAxisTickPos+3);
co2Tick += 10.0;
}}
void drawXAxis(int xAxisMaximum, float xScale){int yPos = height - MARGIN;float xAxisTick = 279.0 / 7.0;int axisYear = 1959;
while(xAxisTick <= xAxisMaximum){int tickLength = 5;int xPos = MARGIN + int(xAxisTick * xScale);
if(axisYear % 5 == 0)
{
text(axisYear, xPos, yPos + 22);
tickLength = 10;
}
line(xPos, yPos, xPos, yPos + tickLength);
xAxisTick += 365.25 / 7.0;
axisYear++;
}}
void loadData(){String[] lines = loadStrings("weekly_in_situ_co2_mlo.csv");
for (String line : lines){if( line.startsWith("\"") ) continue;
String\[\] values = split(line, ',');
String date = values\[0\];
float co2 = parseFloat(values\[1\]);
\_data.set(date, co2);
}}
To thank you for getting this far here’s a dog wanting more peanut butter (source):
Yes, this is blatant click-bait.
¹ Tip for windows users is to open Windows Explorer to the location you want, press F4
and replace the contents of the text box with cmd
and press enter. This opens a dos prompt for this directory.
² Best places on reddit.com are r/dataisbeautiful, r/visualization, and r/climate.