8
$\begingroup$

I would have some functions, for instance Plot, to generate their output using a different Cell's style rather than "Output". The reason is that I'm producing some documents with many images and, for editing reasons, I need to adjust some options of their cell's style.

Unfortunately, I cannot change the "Output" style, because other kind of outputs don't have the same formatting as images. Just to make and example, suppose I want all graphics centered in the cell, while other output left aligned. So, I would assign a custom style to the output generate by Plot. Is there any suggestion?

$\endgroup$
  • $\begingroup$ of course, I don't want to add CellPrint, ExpressionCell, and similar wrapper to the Plot command, I'm looking for something to set at StyleSheet level. $\endgroup$ – bobknight Jan 5 '15 at 13:06
  • $\begingroup$ you could change the cell style of plots post generation. Just click on the cell bracket and select a different style $\endgroup$ – Mike Honeychurch Jan 5 '15 at 21:37
  • $\begingroup$ Thanks Mike for the reply. That's what I actually do, but working with hundreds of notebooks, each one having many graphics, I would be happy to have a programmatic way to achieve this. However, I guess it's not possible. $\endgroup$ – bobknight Jan 6 '15 at 20:24
4
$\begingroup$

For Graphics output specifically there is a nice approach using $DisplayFunction:

(* create a new output style -- overwrites existing custom style sheet *)
SetOptions[EvaluationNotebook[],
 StyleDefinitions -> 
  Notebook[{Cell[StyleData[StyleDefinitions -> "Default.nb"]], 
    Cell[StyleData["altOutput"], TextAlignment -> Center]}, 
   StyleDefinitions -> "PrivateStylesheetFormatting.nb"]
 ]

(* define a display function *)
altOutput[expr_] := CellPrint @ ExpressionCell[expr, "altOutput"]

$DisplayFunction = altOutput;

Graphics output in this Notebook will now be centered. You could also set the DisplayFunction option for individual plot types independently rather than using the global $DisplayFunction parameter.

$\endgroup$
  • $\begingroup$ +1 Nice. Before they changed the default DisplayFunction/graphics typesetting behavior (V5, maybe?), I used the option all the time. Now I've forgotten that it exists. $\endgroup$ – Michael E2 Jan 8 '15 at 16:20
  • 1
    $\begingroup$ @MichaelE2 Thanks. The change came in version 6. You can still load the old graphics subsystem with << Version5`Graphics` and reload the new one with << Version6`Graphics` $\endgroup$ – Mr.Wizard Jan 8 '15 at 16:21
  • $\begingroup$ I'd forgotten about DisplayFunction too! $\endgroup$ – Mike Honeychurch Jan 8 '15 at 22:33
  • $\begingroup$ Thanks Mr.Wizard, both the solutions you provided are useful for me. Indeed, that one using $DisplayFunction is easy and allows to customize each plot function in a different style, whereas the other one, that using "GeneratedCellStyles" allows to manage different kind of outputs and not only Graphics. $\endgroup$ – bobknight Jan 9 '15 at 9:18
  • $\begingroup$ @bobknight You're welcome, and I'm glad I could help. :-) It would be nice if there were a more accessible interface for this kind of thing. $\endgroup$ – Mr.Wizard Jan 9 '15 at 9:19
7
$\begingroup$

It is possible to change the style used for output with this Front End option:

"GeneratedCellStyles" -> {"Output" -> (* style *)}

One can change this style as part of the output formatting routine using $PrePrint, like this:

defaultOut[] := SetOptions[EvaluationNotebook[],
  "GeneratedCellStyles" -> {"Output" -> "Output"}]

altOut[] := SetOptions[EvaluationNotebook[],
  "GeneratedCellStyles" -> {"Output" -> "altOutput"}]

output[gr_Graphics] := (altOut[]; gr)
output[other_] := (defaultOut[]; other)

$PrePrint = output;

Now (bare) Graphics objects will be output with a Cell style of "altOutput" rather than "Output" yet other expressions will be handled normally. One could extend output to handle an arbitrary number of heads as needed. (Graphics is merely an example here.)

$\endgroup$
  • $\begingroup$ Is there any easy way to do this for just one output cell? Right now I'm using SetOptions[EvaluationNotebook[], "GeneratedCellStyles" -> {"Output" -> "Output2"}]; before the output and then SetOptions[EvaluationNotebook[], "GeneratedCellStyles" -> {"Output" -> "Output"}]; after it to restore future outputs back to normal. But this seems too complicated. Any help would be appreciated. $\endgroup$ – RoberRM Apr 27 '18 at 19:49
  • 1
    $\begingroup$ I've asked this question (with more details) here: mathematica.stackexchange.com/questions/172125/… $\endgroup$ – RoberRM Apr 28 '18 at 13:02
  • $\begingroup$ What is especially valuable with "GeneratedCellStyles", it is that this option can be set on the level of individual Cell: an example. Is this option (semi-)documented somewhere? $\endgroup$ – Alexey Popkov Oct 16 '19 at 14:50
6
$\begingroup$

If you want to do it all programmatically you could import the notebook containing the cells with graphics and change the cell style for cells containing graphics:

changeStyle[file_String, newStyle_String] := 
  Module[{nb = NotebookOpen[file], nb1},
   nb1 = NotebookGet[nb];
   NotebookClose[nb];
   nb = nb1 /. (p1 : Cell[BoxData[GraphicsBox[_, ___]], "Output", ___] :> (p1 /. 
         "Output" -> newStyle) );
   NotebookSave[nb, file];
   ];

changeStyle["/pathTo/Untitled.nb", "Text"]

To address @MichaelE2 concerns:

changeStyle[file_String, newStyle_String] := 
  Module[{nb = NotebookOpen[file], nb1, newfile},
   nb1 = NotebookGet[nb];
   NotebookClose[nb];
   nb = nb1 /. (p1 : 
        Cell[BoxData[GraphicsBox[_, ___]], "Output", ___] :> (p1 /. 
         "Output" -> newStyle));
   newfile = 
    SystemDialogInput[
     "FileSave", {NotebookDirectory[], {"New File \"*.nb\"" -> {"*.nb"}}}, WindowTitle -> "Saved New Notebook"];
   If[newfile =!= $Canceled && newfile =!= $Failed,
    NotebookSave[nb, newfile]
    ]
   ];
$\endgroup$
  • 1
    $\begingroup$ +1. I might save the restyled notebook in a different file or directory, just because I'm a nervous ninny. $\endgroup$ – Michael E2 Jan 7 '15 at 0:55
  • $\begingroup$ thanks Mike, that seems to be a suitable workaround. I'll try it! $\endgroup$ – bobknight Jan 7 '15 at 9:05
3
$\begingroup$

An alternative is to use $Post to post-process output automatically as it is generated.

For instance, the following outputs anything with the head Graphics in a style "centeredOutput", which could be defined in whatever manner one wants.

centerGraphics[g_Graphics | g_Graphics3D] := CellPrint@ExpressionCell[g, "centeredOutput"];
centerGraphics[x_] := x;

$Post = centerGraphics

One could center the graphics also by wrapping it in Pane:

centerGraphics[g_Graphics | g_Graphics3D] := Pane[g, Alignment -> Center, ImageSize -> Full];

Update: From a suggestion by Mr.Wizard, with this definition, formatting the graphics could be handled more gracefully by setting $PrePrint = centerGraphics and $Post =. (or leave $Post unset). Then the value of Out will be the graphics instead of the Pane.

Notes (updated) --

Any existing graphics would have to be reevaluated.

One should be aware that $Post affects the output value. For example, after executing Plot, the head of % would be Cell, if using the first definition of centerGraphics.

One can circumvent $Post by wrapping the graphics in a head that does not affect typesetting. For instance, Defer@Evaluate@Plot[Sin[x], {x, 0, 10}] would be printed in a normal "Output" cell but the graphics will still be centered.

Because of this, if one wishes to Deploy graphics, one might want to add a rule to centerGraphics to handle Deploy. For example, centerGraphics[g : Deploy[Graphics[__]] | ...] := ...

One need not create a special style. One can set options directly in ExpressionCell, such as with this body for the definition of centerGraphics:

CellPrint@ExpressionCell[g, "Output", TextAlignment -> Center]
$\endgroup$
  • $\begingroup$ Is there a reason you are using $Post rather than $PrePrint? The latter would address your concern regarding % unless I'm not thinking clearly. $\endgroup$ – Mr.Wizard Jan 8 '15 at 15:52
  • $\begingroup$ @Mr.Wizard I'll check it out. I don't use these processors and forgot about $PrePrint -- Thanks! $\endgroup$ – Michael E2 Jan 8 '15 at 15:57
  • 1
    $\begingroup$ @Mr.Wizard The return value of $PrePrint seems to be wrapped in an "Output" cell. So it works for the Pane version of centerGraphics but not for the cell version. For that solution, $PrePrint seems preferable to me. I'm stuck for a workaround for the cell method at this point. $\endgroup$ – Michael E2 Jan 8 '15 at 16:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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