MATLAB Tip of the Day: Counting in the Command Window

This is actually a two-fer: padding a number with a variable number of leading zeros or spaces and updating text in the Command Window without creating a bunch of new lines.

Variable number padding

The sprintf function includes in its documentation the instructions for padding a number with leading zeros.

myNumber = 4
paddedNumber = sprintf('%02d', myNumber)

paddedNumber =
        04

But what do you do when you don't know how many zeros you'll want to use? You need another variable. The syntax looks like this:

paddedNumber = sprintf('%0*d', numDigits, myNumber)

If I specify numDigits, I can pad myNumber with any number of zeros I choose. Of course, I need to define numDigits somehow. In the FrameCounter function below, I want to have enough leading zeros that my last frame has no zeros out front. So if my last frame is 123, I should get two leading zeros for numbers less than 10, one leading zero for numbers up to 99, and then no leading zeros for the rest. Here's how I like to do it:

numDigits = length(sprintf('d', lastNumber));

This is to say, I write out the number as a string and calculate how many characters that is (i.e. the length of the string). That's how many digits I need to do the padding. Simple.

Updating text in the Command Window

I was using a program in MATLAB that took a long time to run and had an unfortunate tendency to crash1. I wanted to know which frame it had been working on before it failed, and in general I wanted to have some idea how much progress it had made. At the time, I wasn't aware of the built-in progress bar, and then I learned that that can actually slow down whatever process it is you're trying to keep tabs on, so I wrote my own. It just printed the current frame number to the Command Window every ten frames or so, which was enough to narrow down the range of the failed frame. Every time a new frame was printed to the Command Window, though, it made a new line, and after thousands of successful frames, I had a Command Window full of numbers. What I wanted was a way to update the number in place, without printing a new line.

In 2011, I went to the CPLC Summer School at UIUC (which was pretty fun and enlightening) and I saw what I wanted in action in an analysis program. I didn't have a chance to look at the source, though, so I asked how it worked. The student I was working with said he didn't recall for sure, but he thought it had something to do with backspaces. That clue was enough for me to figure it out on my own.

Here's how it works:

  1. Print the text you want to display to the Command Window using fprintf.
  2. Print enough backspace characters (again, with fprintf) to delete each of the characters that need to change.
  3. Print the new text.

Getting it to work as a separate function took a little thinking, but turned out to be pretty simple. The result is below. I hope you find it (or its components) as useful as I have over the years.

FrameCounter

function FrameCounter(first_num, last_num, current_num, show_text)
%%  Determine the number of digits in the number
num_digits = length(sprintf('%d',last_num));
text = 'Frame ';
if nargin < 4
    show_text = 0;
end
%%  Before displaying the first number
if current_num == first_num
    if show_text == 1
        %%
        % Display "Frame " before the numbers
        fprintf(text)
    end
    for aaa = 1:num_digits
        %% Prime the counter with spaces
        fprintf(' ')
    end
end
%% Remove the previous number
for bbb = 1:num_digits
    fprintf('\b')
end
%%  Display the current number
fprintf('%0*d', num_digits, current_num)
%%  Last number
if current_num == last_num
    if show_text == 1
        char_num = length(sprintf(text));
    else %if show_text == 0
        char_num = 0;
    end
    backspaces = char_num + num_digits;
    pause(.1) % Without this pause, the last number sometimes doesn't display properly.
    %% Remove last number and "Frame " text
    for ccc = 1:backspaces
        fprintf('\b')
    end
end
end

1: The source of the crash was a read/write conflict with the Windows 7 indexing system. More on that conflict here if you're interested.