AspectRatio option works unpredictably?

Let us examine the agreement between specified value for the AspectRatio option and the actual aspect ratio of generated plot. For this purpose I define a function which uses the Rasterize trick for determination of the actual aspect ratio:

realAspectRatio = #2/#1 & @@ (#2 - #1) & @@
Rasterize[
Show[#, Epilog -> {Annotation[
Rectangle[ImageScaled[{0, 0}], ImageScaled[{1, 1}]], "Two",
"Region"]}], "Regions"][[-1, 2]] &;

(Instead of realAspectRatio@ one can use much more basic but lesser precise function #2/#1 & @@ ImageDimensions@ what gives the same results.)

At first, we check the agreement for simple graphics Graphics[{Point[{{0, 0}, {1, 1}}]}]:

table = Table[{10^p, realAspectRatio@
Graphics[{Point[{{0, 0}, {1, 1}}]}, AspectRatio -> 10^p]}, {p, -2, 2, .1}];
lm = LinearModelFit[table, x, x];
lm["BestFit"]
ListPlot[lm["FitResiduals"], Frame -> True,
FrameLabel -> {"AspectRatio", "fit residual"}]

1.26421 + 0.603143 x One can see that actual aspect ratio substantially differs from the requested via the AspectRatio option and the dependence between them is nonlinear!

In this case the situation becomes MUCH better if we provide at least horizontal PlotRange specification PlotRange -> {{0, 1}, Automatic}:

table = Table[{10^p,
realAspectRatio@
Graphics[{Point[{{0, 0}, {1, 10}}]}, AspectRatio -> 10^p,
PlotRange -> {{0, 1}, Automatic}]}, {p, -2, 2, .1}];
lm = LinearModelFit[table, x, x];
lm["BestFit"]
ListPlot[lm["FitResiduals"], Frame -> True,
FrameLabel -> {"AspectRatio", "fit residual"}]

0.00391481 + 1.00225 x But for a little more complex graphics ListPlot[Prime[Range]] this remedy does not help even if we vary AspectRatio in much lesser diapason from 1/5 to 5:

table = Table[{ar, realAspectRatio@
ListPlot[Prime[Range], PlotRange -> {{0, 25}, {0, 100}},
AspectRatio -> ar]}, {ar, 1/5, 5, .1}];
lm = LinearModelFit[table, x, x];
lm["BestFit"]
ListPlot[lm["FitResiduals"], Frame -> True,
FrameLabel -> {"AspectRatio", "fit residual"}]

0.248369 + 0.768459 x How this behavior can be explained? Is it intended behavior? And more importantly: is there a way to make the actual aspect ratio predictable?

Summary of the discussion and the conclusion

The source of confusion was the first sentence under the "Details" section on the Documentation page for AspectRatio: "AspectRatio determines the scaling for the final image shape." This statement is clearly wrong and more correct statement can be found as the first point under the "Properties and Relations" subsection in the "Examples" section on the same page: "AspectRatio determines the ratio of PlotRange, not ImageSize." But as it is clearly demonstrated in dedicated answer, even this statement is not precise because actually AspectRatio determines the aspect ratio of the plotting area which is specified by both PlotRange and PlotRangePadding.

• In 10.1 it seems that neither Scaled not ImageScaled correctly place a Rectangle aligned with the range of the plot therefore any calculations based on these are inaccurate. Edit: I forgot about PlotRangePadding. With that set to zero the rectangle aligns. – Mr.Wizard May 18 '15 at 16:05
• @Mr.Wizard With #2/#1 & @@ ImageDimensions@ instead of realAspectRatio@ I get roughly the same picture. I'm surprised that ImageScaled works incorrectly because my little experimentation with plots in the question showed correct behavior of realAspectRatio. – Alexey Popkov May 18 '15 at 16:09
• Alexey, Have you tried removing any ImagePadding from your graphic? – MarcoB May 18 '15 at 16:24
• @MarcoB We seem to be thinking alike. Please see my answer. – Mr.Wizard May 18 '15 at 16:25

It seems to me that there is little point in making the image size so small that the image cannot possibly have a close to accurate aspect ratio. If I also get rid of the superfluous parts outside of the plot range by setting PlotRangePadding, ImagePadding, and ImageMargins all to zero, I can use simple ImageDimensions to check aspect ratio. Doing all this I find that it is quite precise in 10.1 under Windows:

table = Table[{10^p,
N[#2/#] & @@
ImageDimensions@
Image@Graphics[{Disk[]}, AspectRatio -> 10^p, PlotRangePadding -> 0,
ImagePadding -> 0, ImageMargins -> 0, ImageSize -> {2000}]}, {p, -2, 2, .1}];

lm = LinearModelFit[table, x, x];
lm["BestFit"]
ListPlot[lm["FitResiduals"], Frame -> True, FrameLabel -> {"AspectRatio", "fit residual"},
DataRange -> {10^-2, 10^2}, PlotRange -> All]
-0.00279057 + 1.00046 x Likewise your ListPlot example:

table = Table[{ar,
N[#2/#] & @@
ImageDimensions@
Image@ListPlot[Prime[Range], PlotRange -> {{0, 25}, {0, 100}},
AspectRatio -> ar, PlotRangePadding -> 0, ImagePadding -> 0, ImageMargins -> 0,
ImageSize -> {2000}]}, {ar, 1/5, 5, .1}];

lm = LinearModelFit[table, x, x];
lm["BestFit"]
ListPlot[lm["FitResiduals"], Frame -> True, FrameLabel -> {"AspectRatio", "fit residual"},
DataRange -> {1/5, 5}]
0.000344083 + 0.999798 x • @Alexey Why would that be unexpected? Surely the aspect ratio of the plotted data itself is most important? – Mr.Wizard May 18 '15 at 16:33
• @Alexey You certainly have a point, yet it wouldn't make sense for AspectRatio to work that way; if it did when using Automatic circles would vary from round with every tick mark and label added to a plot. – Mr.Wizard May 18 '15 at 16:47
• Did I state that AspectRatio -> 1 is equivalent to Automatic? I hope not as that would be incorrect. Automatic scales the graphic such that primitives are non-distorted, i.e. circles are circles. This isn't the first time the documentation has been unclear or flat out wrong, but I still think this is the logical way for AspectRatio to work. I guess I never read the documentation that carefully; I just experimented and observed. Actually that's probably how I learned most of what I knew about Mathematica before joining Stack Exchange. – Mr.Wizard May 18 '15 at 17:03
• I see that learning by trial and error method is more efficient than mine: I read at least a few first lines in the Documentation and then I proceeded as if these were the true. Now I see that even the first few lines may be false during many versions and (!) for a basic function. It is frustrating for me. – Alexey Popkov May 18 '15 at 17:15
• @AlexeyPopkov to be fair, the documentation does say that "AspectRatio determines the ratio of PlotRange, not ImageSize" (see the first point under "Properties and Relations"). To me, that does seem to describe the observed (and most desirable) behavior. Do I misunderstand? – MarcoB May 18 '15 at 20:55