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.

Swift

I got an iPod Touch in 20091 and wished from the start that I could write my own apps for it.2 I knew approximately nothing about coding, though, so it was a rather far-away sort of wish.

In grad school I learned to code in Matlab. It was a sink-or-swim kind of thing. With the help of another grad student, two books, the wonders of Matlab Central (and later StackExchange), and lots of practice, I learned how to write and debug programs.

My brother is a programmer, and by his standards I'm a hobbyist at best, but I can make the computer do what I need, and I've gotten better as I've gone. Still, he teases me about how I should learn a "real" language, and I kind of agree. So about a year ago, after listening to a Mac Power Users episode about learning to code, I bought a book about learning Objective-C.3 I got a little better than halfway through it before other things got in the way; it's one of the things I was planning to come back to this summer between grad school and job.4

Those summer plans may have just changed, though. A week or two ago at the WWDC Keynote, Apple announced a new programming language called Swift and I think I'm in love. I watched the demo and thought "I can definitely do this." I may finally be able to write the apps I wished for. There's an eBook about the language, which I've already started reading. Though it starts from "Hello world," I don't think it would be much help if you had no familiarity with programming whatsoever,5 but it does look promising for someone (like me) who has at least dipped their toes into the programming pool before.

So that's my next side project: learn another language, try to make an app (I have several ideas), and see how it goes. I'm excited to get started.


1: Nearly 5 years later, it's a bit sluggish but still kicking.

2: I was also bowled over by the idea that the device playing podcasts in my pocket had a bigger hard drive than my laptop's original drive: 64 vs 60 GB. When I stop to think about it, it still amazes me how powerful the gadgets in my pockets and bags are. And then I start feeling old…

3: It's a really good book, too: The Big Nerd Ranch Guide. My inability to finish it has much more to do with being an overwhelmed graduate student in need of "off" time for my brain than the quality of the book. I highly recommend it, and I think it's an excellent example of instructional writing.

4: Oh yeah, I accepted a job about the same time I was completely overloaded with dissertation and defense stuff. The defense is done, the dissertation is submitted, and though I wrote about the stresses and thrills of job-hunting, I guess never did mention here that I did accept an offer. More on that another time. Short version: I have a job starting in August and I'm excited about it!

5: This is actually the same gripe I have about the Matlab Getting Started Guide and books for "beginners." All of these say that you can start from scratch, but they usually assume knowledge and vocabulary that a first-time programmer may not have. (I'm looking at you, floating-point array.)

Consider these programming languages like human languages: the Getting Started Guide might tell me how a verb is conjugated, but if I don't know what "conjugation" is, I don't know what to do with that information. If you've learned another language before, you've probably learned the meta-terminology already, and have some kind of structure for understanding this new set of words, sounds, and grammar rules.

MATLAB Tip of the Day: Better Histograms

My undergrad has a lot of histograms to compare, and the MATLAB defaults can get in the way. You can set the number of bins, but if your data sets span slightly different ranges, you'll quickly find that your bins have different widths or different maxima and minima. They're okay defaults for making a single histogram, but if you want to compare multiple figures, as we do, it gets frustrating fast.

Read More

Matlab Tip of the Day: Changing line properties programmatically

I have an undergraduate working with me on some simulations, and I've been teaching him Matlab for the last year. This week I showed him a useful trick for changing the look of some line plots. He has a whole bunch of these to do, and instead of replotting the data or using the Plot Tools GUI to edit each figure, I taught him how you can get at the various properties of the plot. Once he figured out which properties he wanted to change, and which way, he could save the commands as a script, and run it on any open image to get a consistent look.

Read More

MATLAB tip of the day: Toggling scales

The Problem

Some of the figures I create can be presented on either logarithmic or linear scales. After creating a plot, I may want to switch scales, but I don't want to type set(gca, 'XScale', 'log') every time (nor do I want to pull it out of the Command History). I want a faster way to switch between lin and log axes.

My Solution

A shortcut, of course. I love shortcuts. This shortcut determines the current scale used for the selected axis, and switches the scaling to the other choice.

Here's the code:

% Toggle scale of Y axis
scaleType = get(gca, 'YScale');
switch scaleType
    case 'linear'
        set(gca, 'YScale', 'log')
        disp('y scale is now log')
    case 'log'
        set(gca, 'YScale', 'lin')
        disp('y scale is now linear')
end

I have two such shortcuts, one for X, and one for Y. (Obviously, for X, you swap in 'XScale' for 'YScale'.)

MATLAB tip of the day: Toggling figure visibility

The Problem

Usually I like to see MATLAB figures as they are produced, but if I'm running a long script, visible figures can clutter the screen and hog the available memory. I wanted a way to change visibility quickly, easily, and without having to remember how I did it.

My Solution

I wrote a small script that toggles the DefaultFigureVisible state, and popped that into my Shortcuts bar. Now I can just click the shortcut whenever I want to change the state.

Here's the code:

% Toggle figure visibility
state = get(0, 'DefaultFigureVisible');
switch state
    case 'on'
        set(0, 'DefaultFigureVisible', 'off')
        disp('Figures are off.')
    case 'off'
        set(0, 'DefaultFigureVisible', 'on')
        disp('Figures are on.')
    otherwise %In case something goes completely nuts 
        disp('No change made.')
        disp(state)
end

MATLAB tip of the day: Invisible figures

Problem

MATLAB *.fig files won't open.

Key Symptoms

  • when double-clicking on a *.fig file in a folder, no figure is shown in MATLAB; e.g. on a Mac, after double-clicking the file, you see the opening animation, but no signs in MATLAB that the file actually opened
  • no error message is displayed in the MATLAB Command Window
  • after an unsuccessful attempt to open a figure file, entering figure into the Command Window produces a new figure window labeled Figure 2 (or greater), not Figure 1
  • figures made previously open normally
  • affected figures do not open on other instances of MATLAB

Cause

About the time your figures stopped showing up, you probably turned off figure visibility. Setting figures invisible by default sets the figures invisible, including the files saved. That is, it's not a switch for the display of figures, it's a switch for the figures themselves.

Solution

There are several ways to make those figures visible again, but my favorite solution (to a problem that I don't think should exist in the first place) is to make a copy of the openfig function, and change the line for the default behavior (which is set to respect the visibility status of the figure file) to visible. Save that customized openfig function to your MATLAB directory, and you're all set.

Before I found this answer, I was despairing that I'd have to remake dozens of *.fig files that wouldn't open. When I saw this page, I realized that I had encountered (and corrected) this problem once before. To save myself – and whoever else comes across this post – some heartache, I decided to write it up.