Given Graphics
object, how do I determine the range of coordinates needed to include all of graphics? Basically I need something like what Show
does by default, but I want to specify PlotRange
,PlotRangePadding
and ImagePadding
explicitly.
Example, two Show
s below should render the same
g = Graphics[{Thickness[1], CapForm["Round"], Line[{{0, 0}, {1, 1}}]}];
Show[g]
Show[g, PlotRange -> getPlotRange[g], PlotRangePadding->getPlotRangePadding[g], ImagePadding->getImagePadding[g]]
Motivation: fixing diagrams in this question
Update:
AbsoluteOptions
gives me PlotRange
but not the other two options. Explicitly specifying ImagePadding->Automatic
changes appearance though it's supposedly Automatic
by default.
Two images below show differently and I don't understand why
g = Graphics[{Thickness[1], CapForm["Round"], Line[{{0, 0}, {1, 1}}]}];
Show[g]
Show[g, Sequence @@ AbsoluteOptions[Show[g]]]
Update 2: A similar problem was brought up a year ago, with no solutions proposed, and not fixed as of Mathematica 8.0. To summarize
Show[g]
above with explicit setting of PlotRange
ImagePadding
used by Show[g]
Show[g,PlotRange->Automatic]
looks different from Show[g]
AbsoluteOptions
can give the wrong result for PlotRange
I can suggest the following Ticks
hack:
pl = Plot[Sin[x], {x, 0, 10}];
Reap[Rasterize[Show[pl, Ticks -> {Sow[{##}] &, Sow[{##}] &}, ImageSize -> 0],
ImageResolution -> 1]][[2, 1]]
=> {{-0.208333, 10.2083}, {-1.04167, 1.04167}}
The trick is that real PlotRange
is determined by the FrontEnd, not by the Kernel. So we must force the FrontEnd to render the graphics in order to get tick functions evaluated. This hack gives the complete PlotRange
with explicit value of PlotRangePadding
added.
More general solution taking into account a possibility that pl
has non-standard value of DisplayFinction
option and that it may have Axes
option set to False
:
completePlotRange[plot:(_Graphics|_Graphics3D|_Graph)] :=
Quiet@Last@
Last@Reap[
Rasterize[
Show[plot, Axes -> True, Frame -> False, Ticks -> (Sow[{##}] &),
DisplayFunction -> Identity, ImageSize -> 0], ImageResolution -> 1]]
One can get the exact PlotRange
(without the PlotRangePadding
added) with the following function:
plotRange[plot : (_Graphics | _Graphics3D | _Graph)] :=
Quiet@Last@
Last@Reap[
Rasterize[
Show[plot, PlotRangePadding -> None, Axes -> True, Frame -> False,
Ticks -> (Sow[{##}] &), DisplayFunction -> Identity, ImageSize -> 0],
ImageResolution -> 1]]
P.S. On the Documentation page for PlotRange
under the "More information" one can read: "AbsoluteOptions
gives the actual settings for options used internally by Mathematica when the setting given is Automatic
or All
. " (emphasis mine). So it seems that the Documentation does not even guarantee that AbsoluteOptions
will give correct values for PlotRange
when it is not Automatic
or All
.
I, too, sometimes find it confusing how to get Mathematica to display Graphics
in a consistent way, particularly when insetting graphics.
For the specified graphic g
, it doesn't matter what you provide for the PlotRange
, because Thickness[1]
always draws a line whose thickness is equal to the horizontal plot range. In your example, Show[g, ___]
gives the correct result:
.
Show[g]
, or simply g
, is anomalous.
Why?
I don't know where/if this is documented, but here are a few things that might be relevant to the question.
Obviously DisplayForm[Graphics[___]]
is a raster.
We can get a raster for g using Rasterize[g]. What is the RasterSize? From trial and
error, I found that RasterSize is 10 * screen resolution (reported as 72 pixels per inch on my system). How do I know this? If I rasterize g with resolutions less than 718, I get an image with dimensions {360,361}, whereas the default image size for g is 360 pixels on my system, so I figure to Show[] a graphic, Mathematica Rasterize
's it at 10x the screen resolution. Anybody know if this is true? You can get your screen resolution (at least as Mathematica sees it) from the Options Inspector.
Edit
That the following expression evaluates as True
seems to show that the displayed graphic is rasterized at the ImageSize:
ImportString[ExportString[Show[g,ImageSize->100],"PNG"]]
=== ImportString[ExportString[Rasterize[g,RasterSize->100,ImageSize->100],"PNG"]
To reproduce Show[g]
when using PlotRange
I need to use
Show[g,PlotRange->{{0,1},{0,1}},ImagePadding->90.3]
to get it to crop to the perimeter of the line. So it seems that Mathematica is telling the truth that the PlotRange
is {{0,1},{0,1}}
when using AbsoluteOptions[]
. It is not reporting the actual value of ImagePadding
. Perhaps because ImagePadding->Automatic
is based on a rule that uses the current ImageSize
, PlotRangeClipping
,... settings? The ImagePadding
of 90.3 only works for ImageSize->360
; setting ImageSize->200
makes the ImagePadding
value wrong. For your graphic, ImagePadding->90.3*OptionValue[ImageSize]/360
reproduces Show[g,ImageSize->_]
on my system.
That's all I've found out so far.
You can try adding a recognizable object at a known location and then see where it shows up in the exported version to provide a scale reference. I thought a vector export (SVG or EPS) would be easier to parse, but I think raster is easier after playing around a bit.
For example, add a green rectangle covering the theoretical plot range:
g = Graphics[{Blue, Thickness[1], CapForm["Round"],
Line[{{0, 0}, {1, 1}}], Green, Rectangle[{0, 0}, {1, 1}]}];
im = Rasterize[g, ImageSize -> 360];
xy = Transpose[Position[ImageData[im], {0., 1., 0.}]];
pad = Map[{Min[#1], 360 - Max[#1] } &, xy];
Show[g, ImagePadding -> pad]
The code is basically identifying where all the green pixels are. The padding in this case is {{92, 92}, {92, 92}}, but it need not be symmetrical.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With