Margin Control in R: OMA and MAR and the vanishing axis label.

Yesterday, I was perplexed when the X and Y axis labels in my figures generated with R were vanishing or getting truncated. Not good.

I had some difficulty finding help on line for a variety of reasons. One might simply be that many of my difficulties arise because I want to use larger fonts than many people. The specific problem I encountered will tend to happen to R novices who take an existing plotting routine and then try to increase the font size on the title and axis labels. People who like itty-bitty font sizes will rarely encounter this problem.

Two resources helped me understand what was happening. One was Mr. Kelly O’Day’s ppt presentation which gives a good overview of R plotting basics. The other was Stowers Institute which provides a very specific discussion on”par()”, “mar” and “oma” which control margins in R. Today, I’m just going to discuss how inappropriate setting of the “mar” parameter resulted in the disappearance of X and Y axis labels.

What are “par(), mar and oma”?

The “par()” routine in R permits the user to adjust a vast array of features in plots. Documentation can be obtained by typing ?par at the R console. Scrolling down, and/or googling to learn about margin control, it’s easy to discover that you can adjust what one might call “inner” margins on a figure you plan to generate by first executing a statement that read something like this:

>par(mar=c(4,4.5,2,1))

The documentation for mar reads:

mar
A numerical vector of the form c(bottom, left, top, right) which gives the number of lines of margin to be specified on the four sides of the plot. The default is c(5, 4, 4, 2) + 0.1.

The command I typed above ( i.e. >par(mar=c(4,4.5,2,1) ) will create margins that are 4 lines wide on the bottom, 4.5 lines wide on the left, 2 on the top and 1 on the right of whatever R considers to be “the plot”.

To set the margins at the specified size, you must execute this command before running the plot() command which actually plots some data. Otherwise, you’ll get default margins, which are “c(5, 4, 4, 2) + 0.1”. Those are good for quick and dirty plots, but not useful for learning what ‘mar’ does.

There are no illustrations to teach the naive beginner precisely what the “four sides of the plot” are. But it’s easy enough to find out by creating a plot that uses mar discussed above and ‘oma’ which I’ll discuss later. To test, I entered these two commands at the R consol.

>par(mar=c(0,0,0,0))
>par(oma=c(0,0,0,0))

I then entered the plot() command and a bunch of other commands that I thouhg would create the plot you wanted. These aren’t important– it could be nearly any complicated plot.

Then imitating Stowers Institute, I put a green box around the plot using

>box(“figure”,lty=”solid”, col=”green”).

I’m not going to discuss all the other details of what I did to create this plot. Suffice it to say it’s what I got:

All a y’all probably recognize this graph as defective. Faults include: No axis labels, no axes at all and the title is cropped.

None of this was caused by any of numerous plotting commands I called between the “par” and “box” calls. Now notice the green box that outlines the boundary of “the plot”. Because I called >par(mar=c(0,0,0,0)), R created an inner frame that included what it considers to be “the plot”. I outlined the inner frame with the green box. The axis labels and title are outside the green box and so are not displayed.

The axes, and axis labels were lost because I made the inner frame too small.

Next, I’ll rerun this setting
>par(mar=c(4,4.5,2,1))
>par(oma=c(0,0,0,0) )
{ Run the same plotting commands I ran before.}
>box(“figure”,lty=”solid”, col=”green”).

Wooo hooo! I now have axis labels, a title etc. This may seem painless as presented. But the reason I had been perplexed is that when trying to make my first graph, I’d set inappropriate values in

>par(mar=c(bottom,left,top,right))

Specifically, I’d set
par(mar=c(4,4,2,1)) which budgets 4 lines for the “left” margin, when it turns out I needed 4.5. Choosing 4 lines sliced off the top of the A, and l in “Anomaly”. Ugly! The reason this happened to me is I’d been using Kelly’s script; he’d chosen a smaller font than I. When I switched to a larger font, part of the Y axis label was outside the margins budgeted by “mar”. It turns out when any part of the axis label is outside the margin set by ‘mar’, it disappears.

Now that I have appropriate line widths called by “mar”, my axis labels show.

However, I’m dissatisfied because I know my plotting calls also asked for a time stamp, a citation to NOAA, and a citation to my blog. They are supposed to show in the “outer” margin. Why aren’t they there? Where is the outer margin?

What about oma?
“OMA” specifies the number of lines in the outer margins. I’m going to make a graph doing exactly as in the most recent example, but I’ll change oma. Now, I begin fiddling by entering these two par commands:

>par(oma=c(4,2,0,0) )
>par(mar=c(4,4.5,2,1))

I add the plotting commands and the box command. Here’s the new plot:

Notice that the changing >par(oma=c(0,0,0,0) to >par(oma=c(4,2,0,0) added 4 lines of space to the bottom of the green box and 2 to the left, but 0 to both other sides. You’ll also see that text indicating the data source appear in the lower region.

That text was created by script calls that my plotting routine made in all three examples. It doesn’t appear in the previous two examples because the calls requested it be placed outside the “inner” frame. The inner frame’s edge is the green box. In the previous example, I’d set par(oma=c(0,0,0,0) ); there was no area outside the frame and the “Data Source” and blog credit did not appear.

Setting par(oma=c(4,2,0,0) ) added 4 lines below the inner frame, and provided space. You may wonder why I also added 2 lines to the left? I don’t need them for anything. Well… I added those when I did not yet understand that the axis labels would be cut off if they fell outside the green inner frame. I’d thought that if I just added more frame somewhere the X axis label would no longer be cut off.

Turns out that doesn’t work: If you are loosing your axis labels or cutting off the tops or bottoms of axis labels, you need to adjust “mar”.

In case you are not convinced, I’ll now run the script, but starting with

>par(oma=c(6,2,0,0) )
>par(mar=c(0,0,0,0))

The ‘6’ in the oma command adds 6 lines on the left of the plot margin. This would be more than enough to display the Y axis label. But now I’ve called for 0 line width inner margins on all sizes.

You can see the butt-ugly graph below:

It doesn’t because no matter how wide you make the outer margins, R will not display axis labels if they fall outside the inner margin. If you are losing axis labels, fix “mar”, not “oma”.

I’m sure nothing in the post is revelation to R gurus. You all get to laugh at me wasting time figuring out why my axis labels vanished. 😉

I hope it may help beginners who are trying to make their graphs look both nice and readable in a forum where they plan to display the graph understand how inappropriate margin choices in R can cause axis labels labels and titles to disappear. If you don’t understand the cause of the problem, you can waste endless amounts of time trying to guess when all you really need to do is change the margins using the ‘mar’ option in “par()”.

7 thoughts on “Margin Control in R: OMA and MAR and the vanishing axis label.”

  1. Lucia, maybe your online instructing is just what R needs.

    I think that after you reach a given level of competence with R, some of these things, like you mention here, are easier to corral. It is my image of beginning R users that they either have programming experience with other languages similar to R or they cuss their way to an intermediate competency where you begin to know where to look to find the right commands. The wife has to rush to my office area less frequently to find out what I am yelling at.

    I find the challenge with R more fun than frustrating at this point and rather enjoy finding a way to do something with R without assistance – but then I am retired and have all day.

    I recently had the same problem that you mentioned about the margins of a graph cutting off graphics when I was plotting multiple graphs in one frame. I knew the answer had to be in par and I have much of the R instructions for important R commands already printed out so it was just a matter of persevering. As, I recall, you have to precede the plot command with the par function and some of the par commands can be included in the plot function. Commands like abline, lines and points can be applied after the fact of plotting and I thought that was neat.

    Also please tell me if this is out of line, but I think guys sometimes are hesitant to reveal the problems they might have with an operation like R, while gals are not and particularly in public. I think as I get older that I am more willing to reveal than I used to be. Both my sons tell that is because the testosterone no longer flows as freely as it once did. At my age that is almost a compliment – I think.

  2. Lucia

    Glad to see that my LearnR module helped. Was quartz not the problem, after all?

    BTW, you can drop the Mr. from my name no that we have the he/she situation cleared up.

    Kelly

  3. Kelly– Quartz didn’t seem to be the cause of any problems. It does help me adjust the window, and is convenient.

    Lots of pesky problems come from increasing the font size while not understanding mar and omi. If I’d decreased I might not been a little displeased, but I wouldn’t have lost the axis labels, so I would have plodded along!

    Also please tell me if this is out of line, but I think guys sometimes are hesitant to reveal the problems they might have with an operation like R, while gals are not and particularly in public. I think as I get older that I am more willing to reveal than I used to be

    Oh… I hate revealing problems in public. But, with R, there are ‘issues’ with documentation. Sometimes you can find someone who asked a question on the email group, but the answer will be something like “do ?par(), see “mar”. “. (Other times, the answers are good.)

    Maybe the person who asked read par() and figured it out from the brief comment. Maybe they screamed 8 hours and then figured it out. Maybe they went down the hall and asked a classmate and got a real answer.

    I realize I may be dim about reading these things and immediately understanding what the heck the information at ?par means…. but I figure there are bound to be other dim people whose axis labels disappear too! Now google might find the page.

    As, I recall, you have to precede the plot command with the par function and some of the par commands can be included in the plot function. Commands like abline, lines and points can be applied after the fact of plotting and I thought that was neat.

    Yes. The order matters. But equally important, it turns out that these frames have certain properties.

  4. I use mar, but not oma. Thanks for resolving this small mystery.

    HAve you looked at layout for multipanel figures?

  5. Steve

    I use par(mfrow(?,?)) to generate my multipanel charts, an alternative to layout().

    You can see example multipanel plots and find RClimate scripts here and here .

    Lattice and ggplots 2 are excellent R packages for multipanel charts.

  6. I use the command to generate multi-panel graphs as Ms O’Day suggests. I recently used that command and mar to generate a panel of 25 graphs showing the acf function values for some arima models. What I find convenient here is that I can do a for statement and generate the 25 plots and see them all together immediately in one place. I suspect that given more extensive data that the for statement would be much less efficient than using apply with a function, but for my case those 25 plots flashed up there almost instantly for me to inspect.

    The alternative would be, I think, using a save function in the for loop and save all the separate plots in files to be extracted later.

Comments are closed.