2
$\begingroup$

As was discussed in the comments of another question (MathLink Graphical Output (Plots) to File), Graphcis objects produced by commands such as Plot could be used to plot graphics independent of the presence of a connection with the Mathematica kernel which generated it; i.e., it could be displayed in a separate instance of Mathematica. This would be useful to realize the display of plots in custom front ends connected to Mathematica with MathLink. The Graphics objects would in this case serve as exchange format between the kernel and the frond end.

However, as was pointed out to me, Graphics can contain dynamic content which is evaluated by the native front end by calling the kernel. Consider the example

SetOptions["stdout", FormatType -> InputForm];
myf1[min_?NumericQ, max_?NumericQ] := Table[count, {count, min, max}];
Plot[x^2, {x, 1, 5}, Ticks -> myf1]

which generates the output

Graphics[{{{}, {}, {Hue[0.67, 0.6, 0.6], Line[{ ...}]}}}, 
  {AspectRatio -> GoldenRatio^(-1), Axes -> True, 
   AxesLabel -> {None, None}, AxesOrigin -> {1., 0}, Method -> {}, 
   PlotRange -> {{1, 5}, {0., 25.}}, PlotRangeClipping -> True, 
   PlotRangePadding -> {Scaled[0.02], Scaled[0.02]}, Ticks -> myf1}]

Note the final Ticks -> myf1. Is it possible make the kernel evaluate this output such that it is rendered static? In this case the Graphics should be made a static list of tics, however the solution would need to be generic enough to produce static output for all possible commands which generate graphics.

$\endgroup$
1
  • $\begingroup$ The command FullGraphics seems to be the right direction. But is it complete? And, if yes, how can I influence properties such as the aspect ration of the plot? $\endgroup$
    – highsciguy
    Commented Mar 7, 2014 at 16:14

1 Answer 1

2
$\begingroup$

Unfortunately FullGraphics is extremely out-of-date: it seems that it has not changed much since version 5. Currently correct solution may be only FrontEnd-based. FrontEnd has a command Convert Dynamic to Literal under Evaluation menu which helps with Dynamic but not with Ticks.

A workaround for Ticks is Exporting the complete Graphics[...] as a Notebook, then Importing it backward:

myf1[min_?NumericQ, max_?NumericQ] := Table[count, {count, min, max}];
plot = Plot[x^2, {x, 1, 5}, Ticks -> myf1];

Shallow[ImportString[ExportString[plot, "NB"], "NB"][[1, 1, 1, 1, -1]], 7]
Ticks->FrontEndValueCache[$CellContext`myf1,{{{0.916667,FormBox[<<2>>]},{1.91667,FormBox[<<2>>]},{2.91667,FormBox[<<2>>]},{3.91667,FormBox[<<2>>]},{4.91667,FormBox[<<2>>]}},{{-0.520833,FormBox[<<2>>]},{0.479167,FormBox[<<2>>]},{1.47917,FormBox[<<2>>]},{2.47917,FormBox[<<2>>]},{3.47917,FormBox[<<2>>]},{4.47917,FormBox[<<2>>]},{5.47917,FormBox[<<2>>]},{6.47917,FormBox[<<2>>]},{7.47917,FormBox[<<2>>]},{8.47917,FormBox[<<2>>]},{9.47917,FormBox[<<2>>]},{10.4792,FormBox[<<2>>]},{11.4792,FormBox[<<2>>]},{12.4792,FormBox[<<2>>]},{13.4792,FormBox[<<2>>]},{14.4792,FormBox[<<2>>]},{15.4792,FormBox[<<2>>]},{16.4792,FormBox[<<2>>]},{17.4792,FormBox[<<2>>]},{18.4792,FormBox[<<2>>]},{19.4792,FormBox[<<2>>]},{20.4792,FormBox[<<2>>]},{21.4792,FormBox[<<2>>]},{22.4792,FormBox[<<2>>]},{23.4792,FormBox[<<2>>]},{24.4792,FormBox[<<2>>]},{25.4792,FormBox[<<2>>]}}}]

As you can see the Imported expression contains explicit Ticks specification as a cache for the value of $CellContext`myf1 variable wrapped by FrontEndValueCache. To get standalone Ticks specification you should replace FrontEndValueCache with its second argument:

Shallow[ImportString[ExportString[plot, "NB"], "NB"][[1, 1, 1]] /. 
     FrontEndValueCache[var_, val_] :> val // ToExpression // InputForm, 7]
Graphics[{{}, {}, {Hue[0.67, 0.6, 0.6], Line[{<<77>>}]}}, AspectRatio -> GoldenRatio^(-1), 
Axes -> True, AxesOrigin -> {1., 0}, PlotRange -> {{1, 5}, {0., 24.99999918367348}}, 
PlotRangeClipping -> True, PlotRangePadding -> {Scaled[0.02], Scaled[0.02]}, 
Ticks -> {{{<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}}, {{<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, >     >     {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}, {<<2>>}}}]

Now you have got the complete standalone Graphics expression. Note that this workaround is for Ticks only and works only in the absence of Dynamic constructs. So before applying this you need to get rid of Dynamic using the Convert Dynamic to Literal command. This can be automatized:

myf1[min_?NumericQ, max_?NumericQ] := Table[count, {count, min, max}];
a = 8;
dynamicPlot = Dynamic[Plot[x^2, {x, 1, a}, Ticks -> myf1]];
nb = CreateDocument[dynamicPlot];
SelectionMove[nb, All, Notebook];
FrontEndExecute[{FrontEnd`NotebookDynamicToLiteral[
    FrontEnd`NotebookSelection[FrontEnd`InputNotebook[]]]}];
Shallow[NotebookGet[nb], 8]
Notebook[{Cell[
   BoxData[GraphicsBox[{{}, {}, {<<2>>}}, 
     AspectRatio -> NCache[<<2>>], Axes -> True, 
     AxesOrigin -> {<<2>>}, PlotRange -> {<<2>>}, 
     PlotRangeClipping -> True, PlotRangePadding -> {<<2>>}, 
     Ticks -> FrontEndValueCache[<<2>>]]], 
   CellChangeTimes -> {3.60323*10^9}]}, WindowSize -> {701, 766}, 
 WindowMargins -> {{480, Automatic}, {Automatic, 57}}, 
 FrontEndVersion -> 
  "8.0 for Microsoft Windows (64-bit) (October 6, 2011)", 
 StyleDefinitions -> "Default.nb"]

Note that in this case we able to kill two birds with one stone! We both have got rid of Dynamic and got complete Ticks specification without Exporting. What we need now is just to apply the replacement rule

FrontEndValueCache[var_, val_] :> val

and extract the BoxData expression from the Notebook expression, then convert box data into ordinary Mathematica graphics by applying ToExpression. Done!

P.S. In principle it is not necessary to convert BoxData to ordinary Mathematica graphics for transferring standalone Graphics to another computer. You can transfer the complete Notebook expression which can be stored in a textual file with .nb extension and opened by FrontEnd as ordinary Notebook. Even more, this way is more safe and gives much lesser possibility to corrupt anything.


UPDATE

I just have found that the automatized way with the above method of calling Convert Dynamic to Literal command can lead to FrontEnd crash. More safe solution would be to get values of Dynamic variables directly from the kernel, so just stripping out Dynamic in the kernel. Here is the complete code which accounts only for simplest literal Dynamic and Ticks but not to other Dynamic constructs like DynamicModule etc.:

makeStandalone[expr_] := Module[{nb, nbExpr},
   nb = CreateDocument[dynamicPlot /. Dynamic[x___] :> x]; 
   FinishDynamic[]; Pause[.1];
   nbExpr = NotebookGet[nb] /. FrontEndValueCache[var_, val_] :> val; 
   NotebookClose[nb]; nbExpr];

I have added FinishDynamic[] and Pause[.1] because in some cases Ticks were not resolved even with FinishDynamic[].

$\endgroup$
5
  • $\begingroup$ Do you have an example for the crash? Does it occur when the result is displayed, or when it is build? $\endgroup$
    – highsciguy
    Commented Mar 8, 2014 at 16:35
  • $\begingroup$ @highsciguy In version 8.0.4 I get the crash every time with my original "automatized" code (under Windows 7 x64). $\endgroup$ Commented Mar 8, 2014 at 17:16
  • $\begingroup$ So far I did not see any crashes (I use Mathematica 9 on Linux). However I am not yet sure about the last part in your conversion. Everything seems to work if I use the native front end, but with MathLink I get A front end is not available; certain operations require a front end.. Which is not too surprising, because the linked MathKernel will a priori not even know about an X-Window to display anything. $\endgroup$
    – highsciguy
    Commented Mar 8, 2014 at 18:12
  • $\begingroup$ @highsciguy This message just states that FrontEnd is not connected to the kernel (the $FrontEnd variable is undefined). $\endgroup$ Commented Mar 8, 2014 at 22:54
  • $\begingroup$ Yes, I understand this. What I meant was that the FrontEnd on linux requires an X-Window (the piece of software in charge of displaying any graphical user interface). A X-Display is however not necessarily available if the login is on the command line (e.g. if I want to run Mathematica on a cluster). However I realized now that even Export[Plot[..]] requires a FrontEnd and thus a X-Display. It seems that the only way to circumvent it is to use a X-Display on a remote computer in general. This would however make it slow again. $\endgroup$
    – highsciguy
    Commented Mar 14, 2014 at 19:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.