Match legend and Plot size - wolfram-mathematica

Please Consider :
intense = Reverse[Round[Rationalize /# N[10^Range[0, 3, 1/3]]]];
values = Range[0, 9/10, 1/10];
intensityLegend = Column[Prepend[MapThread[
Function[{intensity, values},
Row[{Graphics[{(Lighter[Blue, values]),
Rectangle[{0, 0}, {4, 1}], Black,
Text[Style[ToString[intensity], 16, Bold], {2, .5}]}]}]],
{intense, values}], Text[Style["Photons Number", Bold, 15]]]];
IntersectionDp1={{1., 588.377}, {2.15443, 580.306}, {4.64159, 573.466}, {10.,560.664},
{21.5443, 552.031}, {46.4159, 547.57}, {100.,545.051},
{215.443, 543.578}, {464.159, 542.281}, {1000., 541.346}}
FindD1=ListLogLinearPlot[Map[List, IntersectionDp1],
Frame -> True,
AxesOrigin -> {-1, 0},
PlotMarkers ->
With[{markerSize = 0.04}, {Graphics[{Lighter[Blue, #], Disk[]}],
markerSize} & /#Range[9/10, 0, -1/10]], Filling -> Axis,
FillingStyle -> Opacity[0.8],
PlotRange -> {{.5, 1100}, {540, 600}},
ImageSize->400];
Grid[{{intensityLegend, FindD1}, {intensityLegend, FindD1}},
ItemSize -> {50, 20}, Frame -> True]
How could I get the legend Column Size to Fit the Height of the Plot Area ?
While Row adjust the size I need to use Grid. This is why I duplicated in grid.

Working with Image Sizes. The (* <- *) marks the important modifications to your code, the rest are mainly font size thingies:
intense = Reverse[Round[Rationalize /# N[10^Range[0, 3, 1/3]]]];
values = Range[0, 9/10, 1/10];
imgSize = 400; (* <- *)
Off[Ticks::ticks]
IntersectionDp1 = {{1., 588.377}, {2.15443, 580.306}, {4.64159, 573.466},
{10., 560.664}, {21.5443, 552.031}, {46.4159, 547.57}, {100., 545.051},
{215.443, 543.578}, {464.159, 542.281}, {1000., 541.346}}
FindD1 = ListLogLinearPlot[Map[List, IntersectionDp1], Frame -> True,
AxesOrigin -> {-1, 0},
PlotMarkers ->
With[{markerSize = 0.04},
{Graphics[{Lighter[Blue, #], Disk[]}], markerSize} &
/# Range[9/10, 0, -1/10]], Filling -> Axis, FillingStyle -> Opacity[0.8],
PlotRange -> {{.5, 1100}, {540, 600}}, ImageSize -> imgSize]; (* <- *)
intensityLegend =
Rasterize[Column[
Prepend[
Reverse#MapThread[ (* <- *)
Function[{intensity, values},
Row[{Graphics[{(Lighter[Blue, values]),
Rectangle[{0, 0}, {4, 1}], Black,
Text[Style[ToString[intensity], 30, Bold], {2, .5}]}]}]],
{intense, values}],
Text[Style["Photons Number", Bold, 25]]]],
ImageSize -> {Automatic, (* <- *)
IntegerPart#
First[imgSize Cases[AbsoluteOptions[FindD1],
HoldPattern[AspectRatio -> x_] -> x]]}];
Grid[{{intensityLegend, FindD1}, {intensityLegend, FindD1}}, Frame -> True]
Where I reversed the intensities column for aesthetic purposes.
Edit
If you don't explicitly specify the ImageSize option for the Plot, you'll disappointingly find that AbsoluteOptions[Plot, "ImageSize"] returns "Automatic" !
Edit Answering the #500's comment bellow
The expression:
ImageSize -> {Automatic, (* <- *)
IntegerPart#
First[imgSize Cases[AbsoluteOptions[FindD1],
HoldPattern[AspectRatio -> x_] -> x]]}];
is really a working replacement for something that should work but doesn't to get the image size of a Plot:
ImageSize -> {Automatic, Last#AbsoluteOptions[FindD1,"ImageSize"]}
So, what the IntegerPart[...] thing is doing is getting the vertical size of the plot image, multiplying imgSize by the AspectRatio of the Plot.
To understand how it works, run the code and then type:
AbsoluteOptions[FindD1]
and you will see the Plot options there. Then the Cases[] function is just extracting the AspectRatio option.
In fact there is a cleaner way to do what the Cases[] does. It is:
AbsoluteOptions[FindD1,"AspectRatio"]
but there is another bug in the AbsoluteOptions function that prevents us to use it this way.

How about making the legend a bit smaller?
intensityLegend =
Column[Prepend[
MapThread[
Function[{intensity, values},
Row[{Graphics[{(Lighter[Blue, values]),
Rectangle[{0, 0}, {4, 1}], Black,
Text[Style[ToString[intensity], 12, Bold], {2, .5}]},
ImageSize -> 50]}]], {intense, values}],
Text[Style["Photons Number", Bold, 15]]]];

Related

Plot error band using functional form

I have a data set with x,y and error(y) values. I write this in mathematica as:
Needs["ErrorBarPlots`"]
data = {{{0, 0.10981309359605919},
ErrorBar[0.05240427422664753`]}, {{0.2145, 0.09146326059113304},
ErrorBar[0.034195343626358385`]}, {{0.4290, 0.08230438177339898},
ErrorBar[0.02533205817067696`]}, {{0.6435, 0.0768141842364532},
ErrorBar[0.020205473852635995`]}, {{0.8580, 0.07223473349753692},
ErrorBar[0.016156209168991867`]}, {{4, 0.056122650246305375},
ErrorBar[0.009288720442961331]}};
ErrorListPlot[data, Frame -> True, FrameStyle -> Directive[Black, 20],
PlotRange -> {{-0.1, 5}, {0.2, 0}}, Axes -> False,
PlotStyle -> {Directive[Red, 12], AbsolutePointSize[10],
AbsoluteThickness[3]} , LabelStyle -> Directive[Green],
BaseStyle -> {Large, FontFamily -> "Courier", FontSize -> 12}]
But what I am trying to obtain is draw a line and get a shaded error band connecting the errorbars which obey a functional form, f(x)= 0.05 + 0.02/(x^2 + 0.425) . I don't want to show the error bars explicitly , rather I want to show the band. I am looking for something like this
I have looked at this link http://reference.wolfram.com/language/howto/GetResultsForFittedModels.html
but couldn't solve the problem. Could anyone please help me? Thanks.
Here is one approach, make two lists, one list for upper range of the erros:
dataPLUS = {{0, 0.10981309359605919 + 0.05240427422664753`}, {0.2145,
0.09146326059113304 + 0.034195343626358385`}, {0.4290,
0.08230438177339898 + 0.02533205817067696`}, {0.6435,
0.0768141842364532 + 0.020205473852635995`}, {0.8580,
0.07223473349753692 + 0.016156209168991867`}, {4,
0.056122650246305375 + 0.009288720442961331}};
another list for the lower range of the errors as:
dataMINUS = {{0, 0.10981309359605919 - 0.05240427422664753`}, {0.2145,
0.09146326059113304 - 0.034195343626358385`}, {0.4290,
0.08230438177339898 - 0.02533205817067696`}, {0.6435,
0.0768141842364532 - 0.020205473852635995`}, {0.8580,
0.07223473349753692 - 0.016156209168991867`}, {4,
0.056122650246305375 - 0.009288720442961331}};
Once you have the two sets you can use the ListPlot option as:
ListPlot[{dataPLUS, dataMINUS}, PlotStyle -> Red, PlotRange -> All]
which will generate a graph like
if you want to join them, instead use ListLinePlot option
ListLinePlot[{dataPLUS, dataMINUS}, PlotStyle -> Red,PlotRange -> All]
and to have a shaded region in between, use the Filling option
ListLinePlot[{dataPLUS, dataMINUS}, PlotStyle -> Red, Filling -> {1 -> {{2}, Gray}}, PlotRange -> All]
To get smooth graph, you need more data points. Hope this will help.
And to include the BestFit line, define a function and add to the previous plots as:
f[x_] = 0.05 + 0.02/(x^2 + 0.425);
plot2 = Plot[f[x], {x, 0, 5}, PlotStyle -> {Red, Thick}];
plot1 = ListLinePlot[{dataPLUS, dataMINUS}, PlotStyle -> LightGray,Filling -> {1 -> {{2}, LightGray}}, PlotRange -> All];
Show[{plot1, plot2}]

Force scientific notation in tick labels of Plot in mathematica

I am trying to scientific-format tick labels on a my Plot which is somehow a frame. By searching Mathgroup archives, it looks like the usual way to mess with tick labels is to extract them using AbsoluteOptions, run a replacement rule with the custom format, and then explicitly feed them to the plotting function with the Ticks->{...} option. However, the following doesn't work for FrameTicks:
makePlotLegend[names_, markers_, origin_, markerSize_, fontSize_,
font_] :=
Join ## Table[{Text[Style[names[[i]], FontSize -> fontSize, font],
Offset[{1.5*markerSize, -(i - 0.5)*
Max[markerSize, fontSize]*1.25}, Scaled[origin]], {-1, 0}],
Inset[Show[markers[[i]], ImageSize -> markerSize],
Offset[{0.5*markerSize, -(i - 0.5)*
Max[markerSize, fontSize]*1.25}, Scaled[origin]], {0, 0},
Background -> Directive[Opacity[0], White]]}, {i, 1,
Length[names]}];
LJ[r_] := 4 e ((phi/r)^12 - (phi/r)^6)
phi = 2.645;
e = 10.97 8.621738 10^-5;
l1 = Plot[LJ[r], {r, 2, 11}, PlotStyle -> {Blue},
PlotRange -> {{2, 6}, {0.001, -0.002}}, Frame -> True,
LabelStyle -> {8},
Epilog ->
makePlotLegend[{"He-He",
"H-H"}, (Graphics[{#, Line[{{-1, 0}, {1, 0}}]}]) & /# {Blue,
Red}, {0.80, 0.35}, 7.5, 7.3, "Times New Roman"]]

Nested Manipulate in Mathematica

Please consider:
Function[subID,
pointSO[subID] = RandomInteger[{1, 4}, {5, 2}]] /# {"subA", "subB"};
Manipulate[
Manipulate[
Graphics[{
Black, Rectangle[{0, 0}, {5, 5}],
White,Point#pointSO[subID][[i]]
},
ImageSize -> {400, 300}],
{i,Range[Length#pointSO[subID]]}],
{subID, {"subA", "subB"}}]
Provided that pointSO[subID] actually yields to lists of different length, is there a way to avoid having 2 Manipulate given that one of the manipulated variable depends on the other?
I am not sure that I got exactly what you are asking for, but I figured what you want is something like the following:
Given a UI with one variable, say an array that can change in size, and another (dependent) variable, which represents say an index into the current array that you want to use from the UI to index into the array.
But you do not want to fix the index variable layout in the UI, since it depends, at run time, on the size of the array, which can change using the second variable.
Here is a one manipulate, which has a UI that has an index control variable, which updates dynamically on the UI as the size of the array changes.
I used SetterBar for the index (the dependent variable) but you can use slider just as well. SetterBar made it more clear on the UI what is changing.
When you change the length of the array, the index control variable automatically updates its maximum allowed index to be used to match the current length of the array.
When you shrink the array, the index will also shrink.
I am not sure if this is what you want, but if it, you can adjust this approach to fit into your problem
Manipulate[
Grid[{
{Style[Row[{"data[[", i, "]]=", data[[i]]}], 12]},
{MatrixForm[data], SpanFromLeft}
},
Alignment -> Left, Spacings -> {0, 1}
],
Dynamic#Grid[{
{Text["select index into the array = "],
SetterBar[Dynamic[i, {i = #} &], Range[1, Length[data]],
ImageSize -> Tiny,
ContinuousAction -> False]
},
{
Text["select how long an array to build = "],
Manipulator[
Dynamic[n, {n = #; If[i > n, i = n];
data = Table[RandomReal[], {n}]} &],
{1, 10, 1}, ImageSize -> Tiny, ContinuousAction -> False]
, Text[Length[data]], SpanFromLeft
}
}, Alignment -> Left
],
{{n, 2}, None},
{{i, 2}, None},
{{data, Table[RandomReal[], {2}]}, None},
TrackedSymbols -> {n, i}
]
update 8:30 PM
fyi, just made a fix to the code above to add a needed extra logic.
To avoid the problem of i being too large when switching lists, you could add an If[] statement at the beginning of the Manipulate, e.g.
Clear[pointSO];
MapThread[(pointSO[#] = RandomInteger[{1, 4}, {#2, 2}]) &,
{{"subA", "subB"}, {5, 7}}];
Manipulate[
If[i > Length[pointSO[subID]], i = Length[pointSO[subID]]];
Graphics[{Black, Rectangle[{0, 0}, {5, 5}], White,
Point#pointSO[subID][[i]]}, ImageSize -> {400, 300}],
{{subID, "subA"}, {"subA", "subB"}, SetterBar},
{{i, {}}, Range[Length#pointSO[subID]], SetterBar}]
Maybe nicer is to reset i when switching between lists. This can be done by doing something like
Manipulate[
Graphics[{Black, Rectangle[{0, 0}, {5, 5}], White,
Point#pointSO[subID][[i]]}, ImageSize -> {400, 300}],
{{subID, "subA"},
SetterBar[Dynamic[subID, (i = {}; subID = #) &], {"subA", "subB"}] &},
{{i, {}}, Range[Length#pointSO[subID]], SetterBar}
]
An alternative implementation that preserves selection settings for each data set:
listlength["subA"] = 5; listlength["subB"] = 9;
Function[subID,
pointSO[subID] =
RandomInteger[{1, 4}, {listlength[subID], 2}]] /# {"subA", "subB"};
Manipulate[
Graphics[{Black, Rectangle[{0, 0}, {5, 5}],
Dynamic[If[subID == "subA", Yellow, Cyan]], PointSize -> .05,
Dynamic#Point#pointSO[subID][[k]]}, ImageSize -> {400, 300}],
Row[{Panel[
SetterBar[
Dynamic[subID,
(subID = #; k = If[subID == "subA", j, i]) &],{"subA", "subB"},
Appearance -> "Button", Background -> GrayLevel[.8]]], " ",
PaneSelector[{"subA" ->
Dynamic#Panel[
SetterBar[Dynamic[j, (k = j; j = #) &],
Range[Length#pointSO["subA"]], Appearance -> "Button",
Background -> Yellow]],
"subB" ->
Dynamic#Panel[
SetterBar[Dynamic[i, (k = i; i = #) &],
Range[Length#pointSO["subB"]], Appearance -> "Button",
Background -> Cyan]]}, Dynamic[subID]]}]]
Output examples:

Specify Point Style in ListPlot in Mathematica

Considering
dacount = {{0, 69}, {1, 122}, {2, 98}, {3, 122}, {4, 69}}
ListPlot[dacount, AxesOrigin -> {-1, 0},
PlotMarkers ->Automatic
PlotStyle-> Lighter[Red, #] & /# Range[0.5, 1, 0.1],
Filling -> Axis, FillingStyle -> Opacity[0.8],
PlotRange -> {{-1, 4.5}, {0, 192}}]
My hope there was for each point to take a different shade of red.
But I can`t understand how to have a style for point which I tried to set as different list.
In your original code, the PlotStyle option won't affect the marker symbols, so you can leave it out. Instead, change your PlotMarkers option to the following:
PlotMarkers -> With[{markerSize = 0.04},
{Graphics[{Lighter[Red, #], Disk[]}], markerSize} & /# Range[0.5, 1, 0.1]]
This will not yet have the desired effect until you replace the list dacount by:
Map[List, dacount]
By increasing the depth of the point list in this way, each point is assigned a marker style of its own from the list in PlotMarkers. So the final code is:
ListPlot[Map[List, dacount], AxesOrigin -> {-1, 0},
PlotMarkers ->
With[{markerSize =
0.04}, {Graphics[{Lighter[Red, #], Disk[]}], markerSize} & /#
Range[0.5, 1, 0.1]], Filling -> Axis,
FillingStyle -> Opacity[0.8], PlotRange -> {{-1, 4.5}, {0, 192}}]
You can also do it the following way:
xMax = Max#dacount[[All, 1]];
Show#(ListPlot[{#}, AxesOrigin -> {-1, 0}, PlotMarkers -> Automatic,
PlotStyle -> (RGBColor[{(#[[1]] + 5)/(xMax + 5), 0, 0}]),
Filling -> Axis, FillingStyle -> Opacity[0.8],
PlotRange -> {{-1, 4.5}, {0, 192}}] & /# dacount)
This plots each point in dacount individually and assigns it a shade of red depending on the x value. The plots are then combined with Show.
I've arbitrarily chosen a scaling and offset for the different shades. You can choose whatever you want, as long as you ensure that the max value is 1.

Mathematica: Rasters in 3D graphics

There are times when exporting to a pdf image is simply troublesome. If the data you are plotting contains many points then your figure will be big in size and the pdf viewer of your choice will spend most of its time rendering this high quality image. We can thus export this image as a jpeg, png or tiff. The picture will be fine from a certain view but when you zoom in it will look all distorted. This is fine to some extent for the figure we are plotting but if your image contains text then this text will look pixelated.
In order to try to get the best of both worlds we can separate this figure into two parts: Axes with labels and the 3D picture. The axes can thus be exported as pdf or eps and the 3D figure as a raster. I wish I knew how later combine the two in Mathematica, so for the moment we can use a vector graphics editor such as Inkscape or Illustrator to combine the two.
I managed to achieve this for a plot I made in a publication but this prompt me to create routines in Mathematica in order to automatize this process. Here is what I have so far:
SetDirectory[NotebookDirectory[]];
SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
I like to start my notebook by setting the working directory to the notebook directory. Since I want my images to be of the size I specify I set the printing style environment to working, check this for more info.
in = 72;
G3D = Graphics3D[
AlignmentPoint -> Center,
AspectRatio -> 0.925,
Axes -> {True, True, True},
AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}},
AxesStyle -> Directive[10, Black],
BaseStyle -> {FontFamily -> "Arial", FontSize -> 12},
Boxed -> False,
BoxRatios -> {3, 3, 1},
LabelStyle -> Directive[Black],
ImagePadding -> All,
ImageSize -> 5 in,
PlotRange -> All,
PlotRangePadding -> None,
TicksStyle -> Directive[10],
ViewPoint -> {2, -2, 2},
ViewVertical -> {0, 0, 1}
]
Here we set the view of the plot we want to make. Now lets create our plot.
g = Show[
Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi},
Mesh -> None,
AxesLabel -> {"x", "y", "z"}
],
Options[G3D]
]
Now we need to find a way of separating. Lets start by drawing the axes.
axes = Graphics3D[{}, AbsoluteOptions[g]]
fig = Show[g,
AxesStyle -> Directive[Opacity[0]],
FaceGrids -> {{-1, 0, 0}, {0, 1, 0}}
]
I included the facegrids so that we can match the figure with the axis in the post editing process. Now we export both images.
Export["Axes.pdf", axes];
Export["Fig.pdf", Rasterize[fig, ImageResolution -> 300]];
You will obtain two pdf files which you can edit in and put together into a pdf or eps. I wish it was that simple but it isn't. If you actually did this you will obtain this:
The two figures are different sizes. I know axes.pdf is correct because when I open it in Inkspace the figure size is 5 inches as I had previously specified.
I mentioned before that I managed to get this with one of my plots. I will clean the file and change the plots to make it more accessible for anyone who wants to see that this is in fact true. In any case, does anyone know why I can't get the two pdf files to be the same size? Also, keep in mind that we want to obtain a pretty plot for the Rasterized figure. Thank you for your time.
PS.
As a bonus, can we avoid the post editing and simply combine the two figures in mathematica? The rasterized version and the vector graphics version that is.
EDIT:
Thanks to rcollyer for his comment. I'm posting the results of his comment.
One thing to mention is that when we export the axes we need to set Background to None so that we can have a transparent picture.
Export["Axes.pdf", axes, Background -> None];
Export["Fig.pdf", Rasterize[fig, ImageResolution -> 300]];
a = Import["Axes.pdf"];
b = Import["Fig.pdf"];
Show[b, a]
And then, exporting the figure gives the desired effect
Export["FinalFig.pdf", Show[b, a]]
The axes preserve the nice components of vector graphics while the figure is now a Rasterized version of the what we plotted. But the main question still remains.
How do you make the two figures match?
UPDATE:
My question has been answered by Alexey Popkov. I would like to thank him for taking the time to look into my problem. The following code is an example for those of you want to use the technique I previously mentioned. Please see Alexey Popkov's answer for useful comments in his code. He managed to make it work in Mathematica 7 and it works even better in Mathematica 8. Here is the result:
SetDirectory[NotebookDirectory[]];
SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
$HistoryLength = 0;
in = 72;
G3D = Graphics3D[
AlignmentPoint -> Center, AspectRatio -> 0.925, Axes -> {True, True, True},
AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}}, AxesStyle -> Directive[10, Black],
BaseStyle -> {FontFamily -> "Arial", FontSize -> 12}, Boxed -> False,
BoxRatios -> {3, 3, 1}, LabelStyle -> Directive[Black], ImagePadding -> 40,
ImageSize -> 5 in, PlotRange -> All, PlotRangePadding -> 0,
TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2}, ViewVertical -> {0, 0, 1}
];
axesLabels = Graphics3D[{
Text[Style["x axis (units)", Black, 12], Scaled[{.5, -.1, 0}], {0, 0}, {1, -.9}],
Text[Style["y axis (units)", Black, 12], Scaled[{1.1, .5, 0}], {0, 0}, {1, .9}],
Text[Style["z axis (units)", Black, 12], Scaled[{0, -.15, .7}], {0, 0}, {-.1, 1.5}]
}];
fig = Show[
Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, Mesh -> None],
ImagePadding -> {{40, 0}, {15, 0}}, Options[G3D]
];
axes = Show[
Graphics3D[{}, FaceGrids -> {{-1, 0, 0}, {0, 1, 0}},
AbsoluteOptions[fig]], axesLabels,
Epilog -> Text[Style["Panel A", Bold, Black, 12], ImageScaled[{0.075, 0.975}]]
];
fig = Show[fig, AxesStyle -> Directive[Opacity[0]]];
Row[{fig, axes}]
At this point you should see this:
The magnification takes care of the resolution of your image. You should try different values to see how this changes your picture.
fig = Magnify[fig, 5];
fig = Rasterize[fig, Background -> None];
Combine the graphics
axes = First#ImportString[ExportString[axes, "PDF"], "PDF"];
result = Show[axes, Epilog -> Inset[fig, {0, 0}, {0, 0}, ImageDimensions[axes]]];
Export them
Export["Result.pdf", result];
Export["Result.eps", result];
The only difference I found between M7 and M8 using the above code is that M7 does not export the eps file correctly. Other than that everything is working fine now. :)
The first column shows the output obtained from M7. Top is the eps version with file size of 614 kb, bottom is the pdf version with file size of 455 kb. The second column shows the output obtained from M8. Top is the eps version with file size of 643 kb, bottom is the pdf version with file size of 463 kb.
I hope you find this useful. Please check Alexey's answer to see the comments in his code, they will help you avoid pitfalls with Mathematica.
The complete solution for Mathematica 7.0.1: fixing bugs
The code with comments:
(*controls the resolution of rasterized graphics*)
magnification = 5;
SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"]
(*Turn off history for saving memory*)
$HistoryLength = 0;
(*Epilog will give us the bounding box of the graphics*)
g1 = Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi},
AlignmentPoint -> Center, AspectRatio -> 0.925,
Axes -> {True, True, True},
AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}},
BaseStyle -> {FontFamily -> "Arial", FontSize -> 12},
Boxed -> False, BoxRatios -> {3, 3, 1},
LabelStyle -> Directive[Black], ImagePadding -> All,
ImageSize -> 5*72, PlotRange -> All, PlotRangePadding -> None,
TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2},
ViewVertical -> {0, 0, 1}, AxesStyle -> Directive[Opacity[0]],
FaceGrids -> {{-1, 0, 0}, {0, 1, 0}}, Mesh -> None,
ImagePadding -> 40,
Epilog -> {Red, AbsoluteThickness[1],
Line[{ImageScaled[{0, 0}], ImageScaled[{0, 1}],
ImageScaled[{1, 1}], ImageScaled[{1, 0}],
ImageScaled[{0, 0}]}]}];
(*The options list should NOT contain ImagePadding->Full.Even it is \
before ImagePadding->40 it is not replaced by the latter-another bug!*)
axes = Graphics3D[{Opacity[0],
Point[PlotRange /. AbsoluteOptions[g1] // Transpose]},
AlignmentPoint -> Center, AspectRatio -> 0.925,
Axes -> {True, True, True},
AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}},
AxesStyle -> Directive[10, Black],
BaseStyle -> {FontFamily -> "Arial", FontSize -> 12},
Boxed -> False, BoxRatios -> {3, 3, 1},
LabelStyle -> Directive[Black], ImageSize -> 5*72,
PlotRange -> All, PlotRangePadding -> None,
TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2},
ViewVertical -> {0, 0, 1}, ImagePadding -> 40,
Epilog -> {Red, AbsoluteThickness[1],
Line[{ImageScaled[{0, 0}], ImageScaled[{0, 1}],
ImageScaled[{1, 1}], ImageScaled[{1, 0}],
ImageScaled[{0, 0}]}]}];
(*fixing bug with ImagePadding loosed when specifyed as option in \
Plot3D*)
g1 = AppendTo[g1, ImagePadding -> 40];
(*Increasing ImageSize without damage.Explicit setting for \
ImagePadding is important (due to a bug in behavior of \
ImagePadding->Full)!*)
g1 = Magnify[g1, magnification];
g2 = Rasterize[g1, Background -> None];
(*Fixing bug with non-working option Background->None when graphics \
is Magnifyed*)
g2 = g2 /. {255, 255, 255, 255} -> {0, 0, 0, 0};
(*Fixing bug with icorrect exporting of Ticks in PDF when Graphics3D \
and 2D Raster are combined*)
axes = First#ImportString[ExportString[axes, "PDF"], "PDF"];
(*Getting explicid ImageSize of graphics imported form PDF*)
imageSize =
Last#Transpose[{First##, Last##} & /#
Sort /# Transpose#
First#Cases[axes,
Style[{Line[x_]}, ___, RGBColor[1.`, 0.`, 0.`, 1.`], ___] :>
x, Infinity]]
(*combining Graphics3D and Graphics*)
result = Show[axes, Epilog -> Inset[g2, {0, 0}, {0, 0}, imageSize]]
Export["C:\\result.pdf", result]
Here is what I see in the Notebook:
And here is what I get in the PDF:
Just checking (Mma8):
SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
in = 72;
G3D = Graphics3D[AlignmentPoint -> Center, AspectRatio -> 0.925,
Axes -> {True, True, True},
AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}},
AxesStyle -> Directive[10, Black],
BaseStyle -> {FontFamily -> "Arial", FontSize -> 12},
Boxed -> False, BoxRatios -> {3, 3, 1},
LabelStyle -> Directive[Black], ImagePadding -> All,
ImageSize -> 5 in, PlotRange -> All, PlotRangePadding -> None,
TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2},
ViewVertical -> {0, 0, 1}];
g = Show[Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, Mesh -> None,
AxesLabel -> {"x", "y", "z"}], Options[G3D]];
axes = Graphics3D[{}, AbsoluteOptions[g]];
fig = Show[g, AxesStyle -> Directive[Opacity[0]],
FaceGrids -> {{-1, 0, 0}, {0, 1, 0}}];
Export["c:\\Axes.pdf", axes, Background -> None];
Export["c:\\Fig.pdf", Rasterize[fig, ImageResolution -> 300]];
a = Import["c:\\Axes.pdf"];
b = Import["c:\\Fig.pdf"];
Export["c:\\FinalFig.pdf", Show[b, a]]
In Mathematica 8 the problem may be solved even simpler using new Overlay function.
Here is the code from the UPDATE section of the question:
SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
$HistoryLength = 0;
in = 72;
G3D = Graphics3D[AlignmentPoint -> Center, AspectRatio -> 0.925,
Axes -> {True, True, True},
AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}},
AxesStyle -> Directive[10, Black],
BaseStyle -> {FontFamily -> "Arial", FontSize -> 12},
Boxed -> False, BoxRatios -> {3, 3, 1},
LabelStyle -> Directive[Black], ImagePadding -> 40,
ImageSize -> 5 in, PlotRange -> All, PlotRangePadding -> 0,
TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2},
ViewVertical -> {0, 0, 1}];
axesLabels =
Graphics3D[{Text[Style["x axis (units)", Black, 12],
Scaled[{.5, -.1, 0}], {0, 0}, {1, -.9}],
Text[Style["y axis (units)", Black, 12],
Scaled[{1.1, .5, 0}], {0, 0}, {1, .9}],
Text[Style["z axis (units)", Black, 12],
Scaled[{0, -.15, .7}], {0, 0}, {-.1, 1.5}]}];
fig = Show[Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, Mesh -> None],
ImagePadding -> {{40, 0}, {15, 0}}, Options[G3D]];
axes = Show[
Graphics3D[{}, FaceGrids -> {{-1, 0, 0}, {0, 1, 0}},
AbsoluteOptions[fig]], axesLabels,
Epilog ->
Text[Style["Panel A", Bold, Black, 12],
ImageScaled[{0.075, 0.975}]]];
fig = Show[fig, AxesStyle -> Directive[Opacity[0]]];
And here is the solution:
gr = Overlay[{axes,
Rasterize[fig, Background -> None, ImageResolution -> 300]}]
Export["Result.pdf", gr]
In this case we need not to convert fonts to outlines.
UPDATE
As jmlopez pointed out in the comments to this answer, the option Background -> None does not work properly under Mac OS X in Mathematica 8.0.1. One workaround is to replace white non-transparent points by transparent:
gr = Overlay[{axes,
Rasterize[fig, Background -> None,
ImageResolution -> 300] /. {255, 255, 255, 255} -> {0, 0, 0, 0}}]
Export["Result.pdf", gr]
Here I present another version of the original solution which uses the second argument of Raster instead of Inset. I think that this way is a little more straightforward.
Here is the code from the UPDATE section of the question (modified a bit):
SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
$HistoryLength = 0;
in = 72;
G3D = Graphics3D[AlignmentPoint -> Center, AspectRatio -> 0.925,
Axes -> {True, True, True},
AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}},
AxesStyle -> Directive[10, Black],
BaseStyle -> {FontFamily -> "Arial", FontSize -> 12},
Boxed -> False, BoxRatios -> {3, 3, 1},
LabelStyle -> Directive[Black], ImagePadding -> 40,
ImageSize -> 5 in, PlotRange -> All, PlotRangePadding -> 0,
TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2},
ViewVertical -> {0, 0, 1}];
axesLabels =
Graphics3D[{Text[Style["x axis (units)", Black, 12],
Scaled[{.5, -.1, 0}], {0, 0}, {1, -.9}],
Text[Style["y axis (units)", Black, 12],
Scaled[{1.1, .5, 0}], {0, 0}, {1, .9}],
Text[Style["z axis (units)", Black, 12],
Scaled[{0, -.15, .7}], {0, 0}, {-.1, 1.5}]}];
fig = Show[Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, Mesh -> None],
ImagePadding -> {{40, 0}, {15, 0}}, Options[G3D]];
axes = Show[
Graphics3D[{}, FaceGrids -> {{-1, 0, 0}, {0, 1, 0}},
AbsoluteOptions[fig]], axesLabels,
Prolog ->
Text[Style["Panel A", Bold, Black, 12],
ImageScaled[{0.075, 0.975}]]];
fig = Show[fig, AxesStyle -> Directive[Opacity[0]]];
fig = Magnify[fig, 5];
fig = Rasterize[fig, Background -> None];
axes2D = First#ImportString[ExportString[axes, "PDF"], "PDF"];
The rest of the answer is the new solution.
At first, we set the second argument of Raster so that it will fill the complete PlotRange of axes2D. The general way to do this is:
fig = fig /.
Raster[data_, rectangle_, opts___] :>
Raster[data, {Scaled[{0, 0}], Scaled[{1, 1}]}, opts];
Another way is to make direct assignment to the corresponding Part of the original expression:
fig[[1, 2]] = {Scaled[{0, 0}], Scaled[{1, 1}]}
Note that this last code is based on the knowledge of internal structure of the expression generated by Rasterize which is potentially version-dependent.
Now we combine two graphical objects in a very straightforward way:
result = Show[axes2D, fig]
And export the result:
Export["C:/Result.pdf", result];
Export["C:/Result.eps", result];
Both .eps and .pdf are exported perfectly with Mathematica 8.0.4 under Windows XP 32 bit and look identical to the files exported with the original code:
result = Show[axes2D,
Epilog -> Inset[fig, Center, Center, ImageScaled[{1, 1}]]]
Export["C:/Result.pdf", result];
Export["C:/Result.eps", result];
Note that we need not necessarily to convert axes to outlines at least when exporting to PDF. The code
result = Show[axes,
Epilog -> Inset[fig, Center, Center, ImageScaled[{1, 1}]]]
Export["C:/Result.pdf", result];
and the code
fig[[1, 2]] = {ImageScaled[{0, 0}], ImageScaled[{1, 1}]};
result = Show[axes, Epilog -> First#fig]
Export["C:/Result.pdf", result];
produce PDF files looking identical to both previous versions.
This looks like much ado about nothing. As I read it, the problem you want to solve is the following:
You want to export in a vector format, so that when printed the optimal resolution is used for fonts, lines and graphics
In your edit program you don't want be bothered by the slowness of rendering a complex vector drawing
These requirements can be met by exporting as .eps and using an embedded rasterized preview image.
Export["file.eps","PreviewFormat"->"TIFF"]
This will work in many applications. Unfortunately, MS Word's eps filter has been changing wildly over the last four versions or so, and whereas it once worked for me in one of the older functions it doesn't anymore in W2010. I've heard rumors that it might work in the mac version, but I can't check right now.
Mathematica 9.0.1.0 / 64-bit Linux:
In general, it seems to be very tricky to place the vectorized axes at the correct position. In most applications it will be sufficient to simply rasterize everything with a high resolution:
fig = Plot3D[Sin[x y], {x, 0, 3}, {y, 0, 3}, Mesh -> None];
Export["export.eps", fig, "AllowRasterization" -> True,
ImageResolution -> 600];
The code exports the graphic to an EPS-file using a high quality rasterization of both the 3D content and the axis. Finally, you can convert the EPS-file to a PDF using for example the Linux command epspdf:
epspdf export.eps
This is probably sufficient for most of the users and it saves you a lot of time. However, if you really want to export the text as vector graphic, you might want to try the following function:
ExportAsSemiRaster[filename_, dpi_, fig_, plotrange_,
plotrangepadding_] := (
range =
Show[fig, PlotRange -> plotrange,
PlotRangePadding -> plotrangepadding];
axes = Show[Graphics3D[{}, AbsoluteOptions[range]]];
noaxes = Show[range, AxesStyle -> Transparent];
raster =
Rasterize[noaxes, Background -> None, ImageResolution -> dpi];
result =
Show[raster,
Epilog -> Inset[axes, Center, Center, ImageDimensions[raster]]];
Export[filename, result];
);
You need to explicitly specify the PlotRange and the PlotRangePadding. Example:
fig = Graphics3D[{Opacity[0.9], Orange,
Polygon[{{0, 0, 0}, {4, 0, 4}, {4, 5, 7}, {0, 5, 5}}],
Opacity[0.05], Gray, CuboidBox[{0, 0, 0}, {4, 5, 7}]},
Axes -> True, AxesStyle -> Darker[Orange],
AxesLabel -> {"x1", "x2", "x3"}, Boxed -> False,
ViewPoint -> {-8.5, -8, 6}];
ExportAsSemiRaster["export.pdf", 600,
fig, {{0, 4}, {0, 5}, {0, 7}}, {.0, .0, .0}];
Print[Import["export.pdf"]];

Resources