Preamble
First let me explain the why. You can skip this and go directly to the question if want to answer it right away. We had more than one discussion about how to produce nice looking 3d plots which can be exported to pdf or some other vector format. Some details why this is not really possible are explained in a post of mine in the question Exporting graphics to PDF - huge file.
To solve this issue, there is in my opinion a lot of work to do, since to make it really fancy one would have to reimplement the rendering and 2d-projection process which is done by Mathematica when it displays a Graphics3D
.
A simple solution, which is maybe OK in a lot of cases, would be to separate the surface of a 3d plot from its box, labels and axes. Then one could create a high-resolution image of the surface and combine this again with the (still in vector format and infinitely high resolved) axes and labels. I showed in the linked post how to do this.
To make this working reliable one has to ensure, that it is possible to place the surface which is now a raster image at the exact same position where the original surface was before. To place the image Wolfram gave us Inset
at hand which kind of does a good job, but when you look at it closely, there is some behavior I don't understand.
Question
Please consider the following two Plot3D
where I tried to deny any padding, margin or whatsoever. One plot is rasterized and I fixed the ImageSize
so that the outcome should be completely equal
s = {300, 300};
opts = {ImageSize -> s,
PlotStyle -> None,
PlotRangePadding -> None,
ImagePadding -> None,
ImageMargins -> None,
Axes -> False,
Boxed -> False};
gr1 = Plot3D[Sin[x + y^2], {x, -3, 3}, {y, -2, 2},
PlotStyle -> None,
Evaluate[Sequence @@ opts]
];
img1 =
Rasterize[
Plot3D[Sin[x + y^2], {x, -3, 3}, {y, -2, 2},
PlotStyle -> Opacity[0.4],
Evaluate[Sequence @@ opts]
],
"Image",
Background -> None,
ImageSize -> s,
RasterSize -> s
];
If you like, use Framed
to put a frame around both graphics and try to see differences in placement or size. I could not find any. Creating now a combined Graphics3D
with Inset
where I used the AbsoluteOptions
of gr1
for the graphics does show, that the inset graphics is not correctly placed. I could have used Show
for the joining, the outcome would have been the same. Please note, that I initialized the variables {dx,dy,dz}
to values which give a nice match on my machine. The image shows the zero position.
Manipulate[
Graphics3D[{Inset[img1, {dx, dy, dz}], First[gr1]},
AbsoluteOptions[gr1]],
{{dx, -0.13`}, -.4, .4},
{{dy, -0.14`}, -.4, .4},
{{dz, -0.375`}, -.4, .4}
]
Can someone explain or solve this problem? Maybe someone has an idea where exactly these offsets come from.
Solution
It's worth looking at every answer below, because there are many valuable information, but the key point to the solution of my question was given by Heike who noticed, that the explicit setting of SphericalRegion
influences the correct placement.
Nevertheless, working with Rasterize
, ImageSize
, ImageResolution
, RasterSize
and all the options influencing margins and paddings around graphics often leads to surprising results. So be warned.
With SphericalRegion->True
in the plot commands, I could quite reliable create nice pdf's from various Graphics3D
. Here the creation of a high-resolution pdf which has a filesize of 860Kb.
I have not included an image, because the png image comes not even close to how brilliant this looks in the pdf. Try it!
RasterizedGraphics3D[gr_Graphics3D, rastersize_Integer] :=
Module[{dim = ImageDimensions[gr], factor},
factor = rastersize/First[dim];
Graphics3D[{Inset[
GaussianFilter[
Rasterize[Show[gr,
Boxed -> False, Axes -> False, AbsoluteOptions[gr]],
"Image", Background -> None, RasterSize -> factor*dim],
.5 factor
],
{0, 0, 0}, {Center, Center}, dim]},
AbsoluteOptions[gr]]
];
grout = RasterizedGraphics3D[
Plot3D[Im[ArcSin[(x + I y)^4]], {x, -2, 2}, {y, -2, 2},
Mesh -> None,
PlotStyle ->
Directive[Yellow, Specularity[White, 20], Opacity[0.8]],
ExclusionsStyle -> {None, Red}, SphericalRegion -> True], 2400]
Export["tmp/tmp.pdf", grout, "AllowRasterization" -> False]
The GaussianFilter
does basically antialiasing because it smooths the high-res raster-image version of the surface a bit. Thank's for all the answers and comments.
Answer
It seems that if you use Options[gr1]
instead of AbsoluteOptions[gr1]
and an offset of {dx, dy, dz} == {0,0,0}
the two graphs align perfectly:
s = {300, 300};
opts = {ImageSize -> s, PlotStyle -> None, PlotRangePadding -> None,
ImagePadding -> None, ImageMargins -> None, Axes -> False, Boxed -> False};
gr1 = Plot3D[Sin[x + y^2], {x, -3, 3}, {y, -2, 2}, PlotStyle -> None,
Mesh -> None, Boxed -> True, ##] & @@ opts;
img1 = Rasterize[Plot3D[Sin[x + y^2], {x, -3, 3}, {y, -2, 2},
PlotStyle -> Opacity[.5], ##] & @@ opts, "Image",
Background -> None, ImageSize -> s, RasterSize -> s];
Graphics3D[{Inset[img1, {0, 0, 0}], First[gr1]}, Options[gr1]]
The next question is then what setting in AbsoluteOptions[gr1]
causes the two graphs to misalign. After a bit of experimentation it turns out that the culprit is SphericalRegion
. If this option is not set explicitly AbsoluteOptions[gr1, SphericalRegion]
returns False
by default but the actual setting used is the value of SphericalRegion
in the $FrontEnd
option Graphics3DBoxOptions
. You can check this setting with
CurrentValue[$FrontEnd, {Graphics3DBoxOptions, SphericalRegion}]
Comments
Post a Comment