How to determine PlotRange to include all of graphics?

前端 未结 3 699
后悔当初
后悔当初 2020-12-13 09:25

Given Graphics object, how do I determine the range of coordinates needed to include all of graphics? Basically I need something like what Show doe

相关标签:
3条回答
  • 2020-12-13 10:15

    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:

    automatic image padding.

    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.

    1. Obviously DisplayForm[Graphics[___]] is a raster.

    2. 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"]

    3. To reproduce Show[g] when using PlotRange I need to use Show[g,PlotRange->{{0,1},{0,1}},ImagePadding->90.3]

    specific image padding

    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.

    0 讨论(0)
  • 2020-12-13 10:16

    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.

    0 讨论(0)
  • 2020-12-13 10:30

    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}]}];
    

    enter image description here

    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.

    0 讨论(0)
提交回复
热议问题