Skip to main content

plotting - Using Inset[..] to overlay a Graphics3D with its raster version


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

enter image description here


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


Mathematica graphics


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

Popular posts from this blog

plotting - Filling between two spheres in SphericalPlot3D

Manipulate[ SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, Mesh -> None, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], {n, 0, 1}] I cant' seem to be able to make a filling between two spheres. I've already tried the obvious Filling -> {1 -> {2}} but Mathematica doesn't seem to like that option. Is there any easy way around this or ... Answer There is no built-in filling in SphericalPlot3D . One option is to use ParametricPlot3D to draw the surfaces between the two shells: Manipulate[ Show[SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], ParametricPlot3D[{ r {Sin[t] Cos[1.5 Pi], Sin[t] Sin[1.5 Pi], Cos[t]}, r {Sin[t] Cos[0 Pi], Sin[t] Sin[0 Pi], Cos[t]}}, {r, 1, 2 - n}, {t, 0, Pi}, PlotStyle -> Yellow, Mesh -> {2, 15}]], {n, 0, 1}]

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]

plotting - Mathematica: 3D plot based on combined 2D graphs

I have several sigmoidal fits to 3 different datasets, with mean fit predictions plus the 95% confidence limits (not symmetrical around the mean) and the actual data. I would now like to show these different 2D plots projected in 3D as in but then using proper perspective. In the link here they give some solutions to combine the plots using isometric perspective, but I would like to use proper 3 point perspective. Any thoughts? Also any way to show the mean points per time point for each series plus or minus the standard error on the mean would be cool too, either using points+vertical bars, or using spheres plus tubes. Below are some test data and the fit function I am using. Note that I am working on a logit(proportion) scale and that the final vertical scale is Log10(percentage). (* some test data *) data = Table[Null, {i, 4}]; data[[1]] = {{1, -5.8}, {2, -5.4}, {3, -0.8}, {4, -0.2}, {5, 4.6}, {1, -6.4}, {2, -5.6}, {3, -0.7}, {4, 0.04}, {5, 1.0}, {1, -6.8}, {2, -4.7}, {3, -1.