# Consistent Plot Styles across multiple MMA files and data sets

I am starting to write a thesis for which I want to use MMA for all my plotting needs, mostly because a lot of the basic analysis has been done there. To ensure that I am applying styles consistently (plot colors, image size, label size, etc.), I need a method which I can use across multiple files.

There are several types of plots that I will need:

1. ListPlot / Plot
2. ListDensityPlot / DensityPlot
3. ListContourPlot / ContourPlot

I can think of several way of doing this:

1. Define my own functions thPlot, thListPlot, etc which have my default styles applied
2. Define my own style options into a variable, and use some combination of FilterRules and Options to make sure that options from that variable are applied to the right type of plot
3. Set default options using Default for the different types of plots.

I am assuming that each of my datasets (which may have one or more plots) will be self-contained mathematica files that I can re-run. So, if I decide to change the style in some central location (via one of the methods above) I can re-run the MMA files and get the plots in the new style.

What have people done in the past?

For an example of plot option customization that I am still rather proud of please see:
How to change the default ColorData used in Mathematica's Plot?

For general customization I think you already outlined some good options. I personally favor the custom function method for maximum control. Another, perhaps cleaner method that I crudely copy from Leonid works well if you can pool options for all plot types in one list ($myoptions): Update: changed withOptions to use the "injector pattern" so as not to disrupt functions if withOptions is used indiscriminately (withOptions[ 1 + 1 ]). $myoptions = {Filling -> {1 -> {{2}, {Red, Purple}}}};

SetAttributes[withOptions, HoldFirst]

withOptions @ Plot[{Sin @ Log @ x, Cos[3 x]}, {x, 0, Pi}]


Here I posted another method in answer to specifying plot ranges, but the method is very general and can be used for any options or parameters. It works by creating an UpValue assignment for the symbol given that applies to any head. This could of course be further restricted to apply to only one head or a list of heads. One could also include FilterRules as shown in the code above, depending on the effect desired. For example:

SetAttributes[setOpts, HoldAllComplete]

Quiet[
setOpts[s_Symbol, pat_: _, spec__?OptionQ] :=
s /: (h : pat)[pre__, s, post___] :=
FilterRules[{spec}, Options[h]] /. {opts___} :> h[pre, opts, post],
Optional::"opdef"
]


Now a single option as used above is assigned to op1:

setOpts[op1, Filling -> {1 -> {{2}, {Red, Purple}}}]


And used in Plot:

 Plot[{Sin @ Log @ x, Cos[3 x]}, {x, 0, Pi}, op1]


Alternatively the options can be restricted to a particular head or head pattern. Here a different set of options, also named op1, is defined only for ParametricPlot:

setOpts[op1, ParametricPlot, Frame -> True, PlotStyle -> Thick, Axes -> None,
MeshShading -> {Red, Blue}, Mesh -> 15]

ParametricPlot[{{2 Cos[t], 2 Sin[t]}, {2 Cos[t], Sin[t]}}, {t, 0, 2 Pi}, op1]


Using op1 in Plot will still produce the result shown earlier.

You could also use Alternatives in the pattern, e.g: Plot | ListPlot | Histogram or more complication patterns with conditions, etc.

• I was just wondering how you implement a function like withOptions that knows what the head of the expression is. Keep forgetting that the function definition is simply a pattern that can be matched... Mar 20 '12 at 17:24
• The link that you said you were proud of has either been taken down or is wrong? Any chance you know of another place to find it? Jun 19 '12 at 8:30
• @Andrew wow that's strange; the question was migrated here but instead of the usual automatic redirect the original is outright deleted. I'll see what I can find out about that; it seems like either a bug or a screw-up. Jun 19 '12 at 15:54

This is more an answer to tkott's comment to Yves than to the entire question.

I have recently implemented a package that does exactly the same sort of thing as what you are looking for. The relevant code (redacted and tweaked so as not to identify my employer) looks like this:

mystyles = {Background->None,
BaseStyle -> {12, AbsoluteThickness[2], AbsolutePointSize[7]},
Frame -> True,  FrameTicksStyle -> {{Directive[20, 20], 20}, {20, 20}}, FrameStyle ->
Directive[AbsoluteThickness[0.9], FontFamily -> "Arial", Black],
AspectRatio -> 14./19., PlotRangePadding -> 0,
ImageSize -> 600, ImageMargins -> {{0, 0}, {0, 3}},
GridLinesStyle->Directive[GrayLevel[0.7],AbsoluteThickness[0.9]],
FormatType :> (Style[TraditionalForm[##],SingleLetterItalics -> False] &)};

(* special non-framed case for pie charts *)
mypiestyles = {Background->None, BaseStyle ->{12,AbsoluteThickness[2],AbsolutePointSize[7]},
Frame -> False, AspectRatio -> 14./19., PlotRangePadding -> 0,
ImageSize -> 600, ImageMargins -> {{0, 0}, {0, 3}},
FormatType :> (Style[TraditionalForm[##],SingleLetterItalics -> False] &)};

(* These are the options that are specific Graphics or DateListPlot options  or whatever*)

myLineGraphDefaults = {Sequence @@ mystyles, Filling -> None,
FillingStyle -> Directive[GrayLevel[0.5], Opacity[0.3]]};
myUndatedLineGraphDefaults = {Sequence @@ mystyles, Filling -> None,
FillingStyle -> Directive[GrayLevel[0.5], Opacity[0.3]]};
myScatterGraphDefaults = {Joined->False,Sequence @@ mystyles, Filling -> None,
FillingStyle -> Directive[GrayLevel[0.5], Opacity[0.3]]};
myBarGraphDefaults =
{Sequence @@ mystyles, Ticks -> None, ChartBaseStyle -> EdgeForm[None]  };


And then within the package, use SetOptions to enforce these types on the built-in plotting functions.

SetOptions[Histogram, Sequence @@ myBarGraphDefaults];

SetOptions[Plot, Sequence @@ mystyles];

SetOptions[ListPlot, Joined -> True,Sequence @@ myLineGraphDefaults];


Of course this is a very long list to catch all the possible plot types, but it is a simple copy and paste job, and you can get the names of all the relative plotting and charting functions (with a few exceptions like Histogram and SmoothHistogram) by evaluating ?*Chart and ?*Plot.

• First: +1 ; now: you can remove Sequence @@ from most places. SetOptions[Plot, Sequence @@ mystyles] can be SetOptions[Plot, mystyles] because SetOptions accepts a list of options. Internally it may be cleaner to use Join: myLineGraphDefaults = mystyles ~Join~ {Filling -> None, . . .}. The final line of code could be written with either Join or Prepend: SetOptions[ListPlot, {Joined -> True} ~Join~ myLineGraphDefaults] Jun 30 '12 at 6:34
• EdgeForm[None] is more compactly done as EdgeForm[], FWIW. :) Jun 30 '12 at 6:44
• I should have posted bits of my code ages ago :) I can't remember why I used Sequence @@ but it was probably a reaction to a code tangle a year ago when I first started working on this project. Jun 30 '12 at 6:50

Usually, I maintain some kind of boilerplate notebook and paste relevant contents into place. If you want to keep it central, you can use a package (.m) file that contains your option settings (e.g. with SetOptions).

On the topic of using/generating packages, see Programmatically generate packages from notebook files?.

You can then load the package with Get or Needs. In your case, you probably don´t need a "proper" package but simply some code you can load conveniently (which works just fine with a .m file).

• Thanks Yves for that link. Perhaps a package is also an option; at that point would you recommend redefining the plot functions (option 1) or setting defaults (option 2)? What I want to avoid is copy-pasting the options. I just did a rundown of plots I would need, and I'm looking at a good 50 at least. Mar 20 '12 at 16:29
• Probably depends on the degree of your customization. Let's see what others recommend... Mar 20 '12 at 16:48