This is part 7 of an N part series detailing how I make my animations.

Now we have reached the limits of what we can display in our 500x500 animation so we will need to change the scale to fit the plot for the full 58 years of data.

So once x is greater than 500 we can start reducing the x scale along with the y. Let’s do that:

float xScale = 1.0;

float yScale = 40.0;

if(frameCount > width)

{

xScale = float(width) / float(frameCount);

}

float x = frameCount * xScale;

float y = (co2 - 313.04) * yScale;

ellipse(x, height - y, 1, 1);

What’s with the `float()`

? Because `width`

and `framcCount`

are integers when you divide them the result is an integer. Unfortunately 500/501 as an integer results in 0, not 0.998 so we have to convert the integer values into floats. You’ll also note that when I am using a constant value, like `40.0`

I include the decimal point, this causes the computer to do floating point arithmetic and not integer arithmetic. For example the result of 1/10 would equal 0 while the result of 1.0/10.0 would be 0.1 as expected. Be aware that 1.0/10 would also result in 0!

Oh, well that’s not what we want! The image doesn’t scale and the last few dots are all squashed up against the right side of the image.

Our code is plotting one dot per frame and keeping all the other dots previously drawn visible. This means that when we change the scale we are only changing the scale for the next dot drawn, not for all the dots previously drawn.

So to overcome this we have to redraw all previous dots and the next one each time. This is done with a `for()`

loop of a different format to the one in `loadData()`

for(int dataIndex = 1; dataIndex <= frameCount; dataIndex++)

{}

This loop defines a variable called `dataIndex`

which starts at 1 and increases by 1 until it reaches the current `frameCount`

. The `dataIndex++`

notation is a shorthand way of saying `dataIndex = dataIndex + 1`

Here it is in context:

void draw()

{

float xScale = 1.0;

float yScale = 40.0;

if(frameCount > width)

{

xScale = float(width) / float(frameCount);

}

for(int dataIndex = 1; dataIndex <= frameCount; dataIndex++)

{

int daysFromStart = (dataIndex - 1) * 7;

LocalDate frameDate = _startDate.plusDays(daysFromStart);

if(_data.hasKey(frameDate.toString()))

{

float co2 = _data.get(frameDate.toString());

float x = dataIndex * xScale;

float y = (co2 - 313.04) * yScale;

ellipse(x, height - y, 1, 1);

}

}

}

So this basically draws all previous points for every frame and then increases that count by one each time. Once the count gets above 500 then we start adjusting the `xScale`

to

And here we have it:

Huh? Oh, I forgot to clear the frame for each draw!

Simply add `background(0);`

to the first line of `draw()`

. Now we get:

Lovely. Now let’s do the same to the y axis.

This’ll be a tad different as the y value doesn’t increase linearly so we’ll keep a running maximum value and scale according to that. As we already multiply our y-axis by 40 already it naturally leads to us setting:

float yScale = 40.0;

Place that line just before the `void draw()`

definition so that `yScale`

is remembered between `draw()`

executions.

Now each time we calculate a new y value we need to check if this exceeds the previous `height`

value, if so then calculate the new `yScale`

:

if(y * yScale > height)

{

yScale = float(height)/y;

}

Resulting in:

Here’s the entire code:

import java.time.*;

FloatDict _data = new FloatDict();

LocalDate _startDate = LocalDate.of(1958, 3, 29);

void setup()

{

loadData();

size(500,500);

background(0);

stroke(255,255,0);

}

float yScale = 40.0;

void draw()

{

background(0);

float xScale = 1.0;

if(frameCount > width)

{

xScale = float(width) / float(frameCount);

}

for(int dataIndex = 1; dataIndex <= frameCount; dataIndex++)

{

int daysFromStart = (dataIndex - 1) * 7;

LocalDate frameDate = _startDate.plusDays(daysFromStart);

if(_data.hasKey(frameDate.toString()))

{

float co2 = _data.get(frameDate.toString());

float x = dataIndex;

float y = (co2 - 313.04) ;

if(y * yScale > height)

{

yScale = float(height)/y;

}

ellipse(x * xScale, height - (y * yScale), 1, 1);

}

}

}

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);

}

}

Join me next week when we play with speed and add some text and axis and stuff…

Edit: When I first published this I had a more complicated way of calculating `yScale`

, this is now simpler.