1
$\begingroup$

In a custom Mathematica frontend based on MathLink I try to make use of plots produced in Notebooks. The idea is to write them to files whenever they get produced.

According to C-code snippets I found online the following should store all plots in postscript cells in a Mathematica file "picture_book" if $Display = "stdout" is executed in the beginning:

case DISPLAYPKT:
  if(MLGetString(link, &output_string)){
    if(first_PS_piece){
      first_PS_piece = FALSE;
      if(picture_book){
        fprintf(picture_book, "%s", ps_cellheader);
      }
    }
    if(picture_book){
      fprintf(picture_book, "%s", output_string);
    }
    MLDisownString(link, output_string);
  }
  break;

case DISPLAYENDPKT:
  if(MLGetString(link, &output_string)){
    if(picture_book){
      fprintf(picture_book, "%s", output_string);
    }
    MLDisownString(link, output_string);
  }
  first_PS_piece = TRUE;
  break;

However, when I run $Display = "stdout" at first, I get the error message

Graphics::opset: Option DefaultAxesStyle is not set in Options[Graphics].

twice, each time I try Plot. Trying to set DefaultAxesStyle did not work.

The code above appears in the loop which handles the output after running Mathematica commands with MathLink. I verified that it retrieves other output packets (not shown), but DISPLAYPKT packages are never received.

This code might be outdated and so I wonder if I need to do anything else in order to obtain proper output packets. Note that I am on Linux.

A different (disfavored) approach would be to use the Export["plot.eps",plot] function in order to export each plot to a separate file. How would I achieve this with minimal impact on existing Notebooks? I.e. can I redefine the Plot command such that each is automatically exported to a separate file with automatic naming?

Edit

After some changes my frontend receives textual Output of the following kind when I call Plot or similar (abreviated example output)

Graphics[{{{}, {}, {Hue[0.67, 0.6, 0.6], Line}}}, {AspectRatio -> GoldenRatio^(-1), Axes -> True, AxesLabel -> {None, None},  AxesOrigin -> {1., 0.05}, Method -> {},  PlotRange -> {{1, 3}, {0.04978707039998921, 0.3678794261559552}},  PlotRangeClipping -> True, PlotRangePadding ->   {Scaled[0.02], Scaled[0.02]}}]

If I execute these outputs manually inside a Notebook in the default frontend it seems to produce the plots. Is it a consistent approach to detect this Graphics[] output and to write it to a file (which kind of file) and then execute that file manually (or later automatically) in the Mathematica interface to produce visual plots? Or could this output be missing some information or be more general for different plot commands?

Edit 2

Motivated by the answers and comments below and the Mathematica documentation I tried the command:

Off[FrontEndObject::notavail]; Get["Version5`Graphics`"]; Plot[Sin[t], {t, 0, Pi}]

Together with custom Format definitions for Graphics (and similar) this would re-enable the 'old fashioned' way of retrieving display output described above. However I do not completely understand how to deal with the abbreviate postscript output (shown below in shortened form). Obviously postscript is missing some definitions to render it. How do I convert this to a complete consistent postscript file?

%!
%%Creator: Mathematica
%%AspectRatio: .61803 
MathPictureStart
/Mabs {
Mgmatrix idtransform
Mtmatrix dtransform
} bind def
/Mabsadd { Mabs
3 -1 roll add
3 1 roll add
exch } bind def
%% Graphics
%%IncludeResource: font Courier
%%IncludeFont: Courier
/Courier findfont 10  scalefont  setfont
% Scaling calculations
0 0.31831 0 0.618034 [
[.15915 -0.0125 -9 -9 ]
Mfstroke
% End of Graphics
MathPictureEnd
:[font = postscript; PostScript; formatAsPostScript; output; inactive; pictureLeft = 100; pictureWidth = 300; pictureHeight = 300;]

It is probably not feasible without the official front end, is it?

Edit 3

Following advice given below in comments I tried the following definitions to print all plots to files. Is this consistent or is there a better way to do it? (First I had tried to redefine Graphics and Graphics3D directly, because it seems more elegant to me. However this resulted in recursions or it would have no effect whatsoever.)

useMyGraphics[vars__] := 
 Block[{Graphics = myGraphics, Graphics3D = myGraphics3D}, vars]
Format[myGraphics[vars__]] := 
 Export["picture.png", Graphics[vars], ImageResolution -> 300]
Format[myGraphics3D[vars__]] := 
 Export["picture3D.png", Graphics3D[vars], ImageResolution -> 300]
Protect[myGraphics];
Protect[myGraphics3D];
Protect[useMyGraphics];
$Pre = useMyGraphics
$\endgroup$

2 Answers 2

2
$\begingroup$

Since Mathematica version 6 you always need the native Mathematica FrontEnd for Exporting graphics because starting from this version all graphical Export-related functionality is moved into the FrontEnd.

But you probably still can use the old kernel-based graphical functionality from version 5 by evaluating:

<< Version5`Graphics`

Old graphical functions are also directly accessible via the Graphics`Legacy`* context:

Names["Graphics`Legacy`*"]
{"ContourPlot", "DensityPlot", "Graphics", "ListContourPlot", \
"ListDensityPlot", "ListPlot", "ListPlot3D", "ParametricPlot", \
"ParametricPlot3D", "Plot", "Plot3D"}

These old-fashioned graphical functions by default generate Mathematica abbreviated PostScript ("MPS") code without using the FrontEnd by

Display["stdout", #, "MPS"] &

You can generate EPS code via

DisplayString[#, "EPS"]&

but there may be some difficulties.

$\endgroup$
2
  • $\begingroup$ Ok, this helps a lot for clarification already. However I am not entirely sure if I should 'implement' this mechanism in my frontend as it seems to be outdated already. I suspect that the computation of the plot data itself still happens inside the Kernel, so it should report Objects of some kind to the interface. In fact after a few changes I receive now (I am not sure which change caused it) Graphics[] output in my fronted (see my edit to the question). Is it maybe a better (consistent) solution to use this to produce visual plots? $\endgroup$
    – highsciguy
    Commented Mar 1, 2014 at 15:40
  • $\begingroup$ It is bad idea to rely on outdated and unsupported part of software which is subject for (possible) removing in future versions. Strictly speaking, Graphics expression is not always self-consistent and independent from the kernel, it can contain Dynamic elements, for example Ticks->{f1,f2} where f1 and f2 are functions defined in the kernel and dynamically called by the FrontEnd when rendering Graphics on screen. This is how CustomTicks package works. $\endgroup$ Commented Mar 2, 2014 at 2:42
2
$\begingroup$

This is to answer:

Can I redefine the Plot command such that each is automatically exported to a separate file with automatic naming?


First, a little history (in addition to what Alexey said):

In Mathematica versions earlier than 6, graphics were shown (displayed) as a side effect of Show. Show was essentially the "print" command for graphics, much like how Print will display expressions as a side effect while returning Null. Unlike Print, Show returned the Graphics expression in addition to displaying it.

Graphics expressions were formatted specially as --Graphics-- in OutputForm, in order to prevent printing their guts in InputForm on screen every time some graphics were returned (similarly to how e.g. InterpolatingFunctions don't show their insides when formatted on screen).

Working with graphics looked like this:

The graphics were shown as a side effect and also returned. The returned graphics was displayed as --Graphics-- in output form. (As Alexey said, you can restore the old behaviour by loading << Version5`Graphics`, but note that there are many graphics primitives that the old rendering method doesn't support, so many things will be broken.)

If you did not use the function Show, the graphics were not rendered on screen.

Most plotting function (such as Plot) automatically invoked Show.

It was possible to customize how precisely Show rendered graphics by using the DisplayFunction Graphics option, which was by default set to $DisplayFunction which in turn was set to Display[$Display, #1, "MPS"] &, as Alexey notes.

In version 6 the big change was that now Graphics objects were formatted as a rendered picture when output into notebooks. This meant that Show was not necessary any more. Graphics were not rendered as a side effect any more. Now instead of formatting them as the string --Graphics-- they were formatted as the image they represented. It also made sense to move the rendering (formerly done by an external PostScript renderer) into the Front End to allow for rotatable 3D graphics.

To prevent Show (and the plotting functions that invoked Show) from doing something as a side effect, $DisplayFunction was set to Identity in version 6.

The Show function lost its significance as a printing function for graphics, and it's now solely used for it's formerly secondary function: combining graphics. (This explains why it's called Show when it doesn't actually show anything any more!)


So how does knowing this help you? First, it makes it clear why $Display doesn't do anything any more. It was used in the old default setting of $DisplayFunction. Second, it gives a convenient way to answer the quoted question above. You could define your own displaying function, possibly based on Export, and set the value of $DisplayFunction to it.

Be prepared for weird behaviour though. Show is the function invoking the $DisplayFunction and Show is used differently today. For example, in version 5 we needed to to Show[a, b, DisplayFunction -> Identity] to combine two Graphics objects without displaying them. Today people will omit setting this option when all they want to do is combine graphics, so you might get extra invocations for $DisplayFunction. Also, when implementing a custom plotting functions, people won't explicitly include Show to render the graphics, because this is not necessary. So some newer plotting functions might not invoke the custom display function.


If you are writing a custom front end, you'll get the most reliable result if you do what the official front end does: render graphics only when the kernel returns a Graphics object to you. Your front end would send this graphics object back to the kernel for rendering (using Export or Rasterize). (And in turn the kernel will invoke the official front end in the background to do the actual rendering for it.)


Additional reading:

$\endgroup$
20
  • $\begingroup$ That's interesting. I think I would try to go for your last solution. But this means that I must reliably parse output in search for Graphics[]. It is not quite obvious to me how I can do this reliably as it seems to be returned as regular output. I have seen that there may also be Graphics3D. Do these always appear on separate lines at least? Otherwise I would need to search the closing bracket ] which matches Graphics[ or Graphics3D[. This would be hard because the square brackets could obviously appear in labels too. I.e. not all opening square brackets must have a closing match. $\endgroup$
    – highsciguy
    Commented Mar 1, 2014 at 17:26
  • $\begingroup$ @highsciguy I'm venturing into increasingly unfamiliar territory here (for me), but instead of trying to figure out if you got Graphics or Graphics3D by parsing strings, you should figure it out by looking at expressions. Retrieve an expression from the kernel, check what it is, then send it back for formatting: either as graphics, or as OutputForm/InputForm text. Alternatively, use something like $PrePrint to process everything in the kernel and send some structured information to your front end, either containing graphics or text. $\endgroup$
    – Szabolcs
    Commented Mar 1, 2014 at 18:16
  • $\begingroup$ @highsciguy Actually my first idea (send to front end, figure out what it is, send back for formatting) is a very bad one. The expression might be huge. Instead, before it gets sent to your front end, the expression should be processed on the kernel side. You can generate some structures expression specifically meant for consumption by your front end (i.e. not a simple string, but a Mathematica expression that contains the string an some annotation: is it a file name of graphics or is it a string to be printed?) $\endgroup$
    – Szabolcs
    Commented Mar 1, 2014 at 18:28
  • $\begingroup$ Actually it is worse. Part of the purpose of the custom front end is that it runs through a internet connection on a separate machine. Sending forth and back would indeed not make sense. However retrieving Graphics once might. This output could still be more compact than an exported graphics file. In principle the nicest solution would be if I could tell Mathematica to identify the packet as a DISPLAYPKT as it used to do with the compressed postscript output in old version. If the user is interested to see the graphics output he could translate these (if there is a local copy of Mathem). $\endgroup$
    – highsciguy
    Commented Mar 1, 2014 at 18:56
  • $\begingroup$ @highsciguy I think that Format function is the way for you. You should define custom formatting functions for outputting different kinds of expressions to your custom front which cannot render graphics. Probably it is not needed to send complete Graphics[...] expression to your custom front end without specific requirement from the user. $\endgroup$ Commented Mar 2, 2014 at 3:44

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