How to change the default ColorData used in Mathematica's Plot?

44

27

This question leads on from the recent question What are the standard colors for plots in Mathematica?

There it was determined that the default color palette used by Plot is equivalent to ColorData[1] (see the note at the end). This can be changed through the use of the option PlotStyle.

My question is how can we make, e.g., the default color palette be ColorData[3] and have this default survive manual changes to other aspects of the plot styling?


So, for example, let's make a list of monomials and some dashing settings

fns = Table[x^n, {n, 0, 5}];
dash = Table[AbsoluteDashing[i], {i, 1, 6}];

Note that the default plot colors survive other choices to styling:

GraphicsRow[{Plot[fns, {x, -1, 1}], Plot[fns, {x, -1, 1}, PlotStyle -> dash]}]

default

The colors in the plot may be changed by locally setting PlotStyle, such as

Plot[fns, {x, -1, 1}, PlotStyle -> ColorData[3, "ColorList"]]

or by setting the default options. Let's do that and run the GraphicsRow command again:

SetOptions[Plot, PlotStyle -> ColorData[3, "ColorList"]];
GraphicsRow[{Plot[fns, {x, -1, 1}], Plot[fns, {x, -1, 1}, PlotStyle -> dash]}]

ColorList 3

Note that the new colors in the default plot style is overwritten by the use of PlotStyle -> dash. This can be manually fixed, in this case, with Transpose[{dash, ColorData[3, "ColorList"][[1 ;; 6]]}], but you don't want to do that every time.

Changing the default PlotStyle will always have this problem. You'd expect there to be a default ColorData or color scheme setting somewhere, but I have been unable to find it.


Note that running the hack

Unprotect[ColorData];
ColorData[1] := ColorData[3]
ColorData[1, a__] := ColorData[3, a]
Protect[ColorData];

does not fix the default plot colors. Which probably means that the default internals of Plot does not make an explicit call to ColorData...


It's also interesting to note that when running a Trace[Plot[...],TraceInternal -> True] the colors seem to appear out of nowhere! I looked at such a trace in trying to answer this recent SO question related to how Mathematica determines the number of lines and thus colors it needs in a plot.

Simon

Posted 2011-03-22T23:40:04.117

Reputation: 9 867

Answers

28

Update August 2014

The Legacy Solution below has been corrected to work in recent versions (9 and 10).

At the same time however the introduction of PlotTheme functionality makes my solution largely academic as plot themes are designed to combine in the same manner. If no existing theme has the desired style you can create a custom one.

This example demonstrates setting new default plot colors as well a custom thickness and these correctly combining with the dashing directives in PlotStyle:

System`PlotThemeDump`resolvePlotTheme["Thick5", "Plot"] := 
 Themes`SetWeight[{"DefaultThickness" -> {AbsoluteThickness[5]}}, 
  System`PlotThemeDump`$ComponentWeight]

SetOptions[Plot, PlotTheme -> {"DarkColor", "Thick5"}];

fns = Table[x^n, {n, 0, 5}];
dash = Table[AbsoluteDashing[i], {i, 1, 6}];

Plot[fns, {x, -1, 1}, PlotStyle -> dash]

enter image description here


Legacy Solution

The following updated solution is based on the existing solutions from Janus and belisarius with considerable extension and enhancement.

Supporting functions

ClearAll[toDirective, styleJoin]

toDirective[{ps__} | ps__] := 
  Flatten[Directive @@ Flatten[{#}]] & /@ {ps}

styleJoin[style_, base_] :=
  Module[{ps, n},
    ps = toDirective /@ {PlotStyle /. Options[base], style};
    ps = ps /. Automatic :> Sequence[];
    n = LCM @@ Length /@ ps;
    MapThread[Join, PadRight[#, n, #] & /@ ps]
  ]

Main function

pp is the list of Plot functions you want to affect.

sh is needed to handle pass-through plots like LogPlot, LogLinearPlot, DateListLogPlot, etc.

pp = {Plot, ListPlot, ParametricPlot, ParametricPlot3D};

Unprotect /@ pp;

(#[a__, b : OptionsPattern[]] :=
   Block[{$alsoPS = True, sh},
     sh = Cases[{b}, ("MessagesHead" -> hd_) :> hd, {-2}, 1] /. {{z_} :> z, {} -> #};
     With[{new = styleJoin[OptionValue[PlotStyle], sh]}, #[a, PlotStyle -> new, b]]
   ] /; ! TrueQ[$alsoPS];
 DownValues[#] = RotateRight[DownValues@#]; (* fix for versions 9 and 10 *)
) & /@ pp;

Usage

Now different plot types may be individually styled as follows:

SetOptions[Plot, PlotStyle -> ColorData[3, "ColorList"]];

Or in groups (here using pp defined above):

SetOptions[pp, PlotStyle -> ColorData[3, "ColorList"]];

Examples

PlotStyle options are then automatically added:

fns = Table[x^n, {n, 0, 5}];
dash = Table[AbsoluteDashing[i], {i, 1, 6}];

Plot[fns, {x, -1, 1}, PlotStyle -> dash]

enter image description here


Plot[...] and Plot[..., PlotStyle -> Automatic] are consistent:

Plot[fns, {x, -1, 1}]
Plot[fns, {x, -1, 1}, PlotStyle -> Automatic]

enter image description here enter image description here


Pass-through plots (those that call Plot, ListPlot or ParametricPlot) can be given their own style:

SetOptions[LogPlot, PlotStyle -> ColorData[2, "ColorList"]];

LogPlot[{Tanh[x], Erf[x]}, {x, 1, 5}]
LogPlot[{Tanh[x], Erf[x]}, {x, 1, 5}, PlotStyle -> {{Dashed, Thick}}]

enter image description here enter image description here


PlotStyle handling can be extended to different Plot types.

I included ParametricPlot3D above as an example:

fns = {1.16^v Cos[v](1 + Cos[u]), -1.16^v Sin[v](1 + Cos[u]), -2 1.16^v (1 + Sin[u])};

ParametricPlot3D[fns, {u, 0, 2 Pi}, {v, -15, 6},
  Mesh -> None, PlotStyle -> Opacity[0.6], PlotRange -> All, PlotPoints -> 25]

enter image description here


Implementation note

As it stands, resetting SetOptions[..., PlotStyle -> Automatic] will revert the colors to the original defaults. If this behavior is undesirable, the code can be modified to give a different default color, in the manner of Janus' also function, upon which my styleJoin is clearly based.

Mr.Wizard

Posted 2011-03-22T23:40:04.117

Reputation: 259 163

That's really good - it works well/smoothly. How did you find out about the "MessagesHead" thing -- that looks pretty obscure. I was really hoping that you'd found some way to use System`Private`$PlotStyleFunction, but never mind. I have two small problems with the code. (1) As you pointed out in @belisarius' answer, changing the colors of the Plot does not effect the colours of the filling. It would be possible to hack this with FillingStyle - but not really necessary. – Simon – 2011-04-14T12:02:48.737

(2) I find associating a plotting rule with a UpValue on Rule a bit perverse. It also leads to the problem that @Sasha pointed out, since Rule is too deep for a pattern match to his example. This can be fixed by making a loop that produces a normal DownValue for each h in pp. This can also be designed to fix the problem that Sasha pointed out. Fix this issue and you get the bounty - since it is probably the best "simple" solution that is possible. – Simon – 2011-04-14T12:05:29.733

@Simon, re: "MessagesHead", while you had me digging around in the bowels of Plot I found something useful. I don't know what I was looking at when I commented on belisarius' answer, as Janus' method doesn't handle FillingStyle either from what I can tell. I don't know why I thought it did. If you would like that to change as well I'd be happy to try. – Mr.Wizard – 2011-04-14T12:10:02.397

1@Simon, by the way, I may have to add "I code perverse Mathematica" to my profile. ;-p – Mr.Wizard – 2011-04-14T12:14:16.010

@Mr.Wizard: Nah, the FillingStyle thing is minor. It probably would be the proper default behaviour for it to copy the Plot colors, but if it was really important, then that would already be the default behaviour in Mathematica (ie Plot[x^2, {x, 0, 1}, PlotStyle -> Red, Filling -> Axis] would have a red fill). -- So, just fix point (2) and the money is yours! – Simon – 2011-04-14T12:14:41.307

3@Mr.Wizard: It looks fine (+125)! A lot more solid than the previous version. I'm sure that this was some of the hardest 100pts that you've earned. And since your solution built off that of @Janus and @Belisarius, I feel like they should share in the bounty. So everyone who has voted up Mr.Wizards answer, go and vote up Janus' and Belisarius' answers!! – Simon – 2011-04-14T23:17:46.170

2@Simon, thank you! The rep points are nice, but the real reward is knowing I helped. :-) – Mr.Wizard – 2011-04-15T09:31:34.857

It seems (?) this does not work anymore in v9. Can you now confirm? @Janus's answer works but requires active use of also, which is somewhat less elegant? – chris – 2014-04-05T09:53:44.317

@Will I have corrected my (legacy) method to work in version 10. It should also work in version 9. For version 10 there is now a better solution however; see the section at the top. – Mr.Wizard – 2014-08-19T07:12:32.257

@chris Please see the comment directly above. – Mr.Wizard – 2014-08-19T07:12:39.943

@Mr.Wizard: Does this still work in v9? Overriding the Plot function(s) doesn't seem to work for me (the default behaviour is not modified). – Will Vousden – 2013-08-15T09:34:34.673

22

Here is one take on it -- the hard part was estimating how the PlotStyle option is turned into a list of directives. I think this works as the internal implementation:

canonicalPlotStyle::usage = 
  "Turn a PlotStyle option into the canonical form {_Directive...}";
canonicalPlotStyle[ps_] := Replace[ps, {
   a_List :> (Flatten[Directive @@ Flatten[{#}]] &) /@ a,
   a_ :> {Flatten@Directive[a]}}]

Building on canonicalPlotStyle it's now just a matter of combining two lists of unequal length:

also::usage = 
  "Combines a specified plotstyle with the current defaults as \
  specified by Options.";
also[plotstyle_] := Module[{ps, n},
  ps = canonicalPlotStyle /@ {
     (PlotStyle /. Options[Plot]) /. Automatic :> ColorData[1, "ColorList"],
     plotstyle};
  n = LCM @@ (Length /@ ps);
  Join @@@ Transpose[Flatten[Table[#, {n/Length[#]}], 1] & /@ ps ]]

This does require you to call the function when you plot, but I couldn't see any way around that part:

SetOptions[Plot, PlotStyle -> ColorData[3, "ColorList"]];
GraphicsRow[{Plot[fns, {x, -1, 1}], 
  Plot[fns, {x, -1, 1}, PlotStyle -> also@dash]}]

output from above code

HTH

Janus

Posted 2011-03-22T23:40:04.117

Reputation: 411

As you can see, I'm using the defaults from Plot no matter where also is used. It might actually be nicer to use Options associated with also. This would also remove any need to fiddle with Options for Plot... – None – 2011-03-23T03:24:43.153

Nice! +1. I think I prefer keeping the options associated with Plot (or which ever plotting function you want to use also with) so that it behaves as close to normal as possible. Obviously, it's not quite the answer I'm hoping for (ie a simple setting for a default color scheme), but it's still useful. – Simon – 2011-03-23T04:10:18.040

Two small problems. 1) also overrides any manually set colors in the plot. This is simply fixed by reversing the order of terms in ps putting the locally supplied options last. 2) You need also every time you make a plot using a manual PlotStyle setting -- a little annoying, but not a deal breaker! – Simon – 2011-03-23T04:13:09.473

@Simon -- Thanks for catching the ordering bug. I actually thought it had to be the way I did it, maybe inspired by rules. Will edit above. – None – 2011-03-23T05:01:42.130

10

This is work in progress, I'm posting it because I'm not sure to be able to finish it, and perhaps someone wants to.

The idea is to combine the wonderful Janus's solution with this nice trick to redefine the Plot[ ] standard behavior.

The program below works for a large subset of the help page for Plot[ ], but fails for two or three. The code is not tidied up, just a draft with leftovers.

Unprotect[Plot];
Plot[argsANDopts___] :=
  Block[
    {$inMsg = True, result, also, canonicalPlotStyle, opts, args, 
     optPstyle},

    If[(opts = 
        FilterRules[Cases[{argsANDopts}, _Rule], Options[Plot]]) == {},
     opts = {Axes -> (Axes /. Options[Plot])}];(*Anything not null*)
    args = Cases[{argsANDopts}, Except@_Rule];

    If[(optPstyle = Cases[opts, Rule[PlotStyle, y__] :> y]) == {}, 
     optPstyle = (PlotStyle /. Options[Plot])];

    canonicalPlotStyle[ps_] := 
     Replace[ps, {a_List :> (Flatten[Directive @@ Flatten[{#}]] &) /@ 
         a, a_ :> {Flatten@Directive[a]}}];

    also[plotstyle_] := 
     Module[{ps, n}, 
      ps = canonicalPlotStyle /@ {(PlotStyle /. Options[Plot]) /. 
          Automatic :> ColorData[1, "ColorList"], plotstyle};
      n = LCM @@ (Length /@ ps);
      Join @@@ Transpose[Flatten[Table[#, {n/Length[#]}], 1] & /@ ps]];

    (*Print@opts;
    Print@args;
    Print@optPstyle;
    Print@Evaluate@also[opts];*)
    result = Plot[
      Evaluate@Sequence@@args,
      PlotStyle -> also[optPstyle],
      Evaluate@Sequene@@opts
      ];
    result

    ] /; ! TrueQ[$inMsg];
SetOptions[Plot, PlotStyle -> ColorData[3, "ColorList"]];
Protect[Plot];

samples:

enter image description here

Does not work for:

Plot[{Sin[x], Sin[2 x], Sin[3 x]}, {x, 0, 2 Pi}, 
 PlotStyle -> {Red, Green, Blue}]

Dr. belisarius

Posted 2011-03-22T23:40:04.117

Reputation: 112 848

+1 for still using the magic variable $inMsg! I'm overrun at the moment, so will look more carefully at the code on the weekend... – Simon – 2011-03-24T01:27:52.103

4

The most likely source of style data, in my opinion, is:

System`Private`$PlotStyleFunction[5]
{{Hue[0.67, 0.6, 0.6]},
 {Hue[0.906068, 0.6, 0.6]},
 {Hue[0.142136, 0.6, 0.6]},
 {Hue[0.378204, 0.6, 0.6]},
 {Hue[0.614272, 0.6, 0.6]}}

However, using Unprotect and changing this function does not effect the desired change in Plot. Perhaps the call is out of reach to normal methods.

Mr.Wizard

Posted 2011-03-22T23:40:04.117

Reputation: 259 163

Mr.W: It did look promising - but doesn't actually seem do do anything. Have you looked at Trace with TraceInteral->True? I discovered GraphicsPerformanceTuningDumpcolors that way... but it also seems to be/do nothing. Another interesting thing to look at is the output of DeleteCases[Table[{x, Names[x <> "Color*", IgnoreCase -> True]}, {x, Contexts[]}], {_, {}}] // Column... There might be something useful there, but I haven't found it yet (or figured out the right way of using it). – Simon – 2011-04-09T09:05:20.527

Mma 7 does not appear to have "GraphicsPerformanceTuningDumpcolors" unless I am doing it wrong. When you say$PlotStyleFunctiondoesn't do anything, do you mean with regard toPlot`? Because it certainly does give the right output on my system. (editing post to include that...) – Mr.Wizard – 2011-04-09T09:22:55.560

1I see, nice! That matches exactly the colors used by Plot -- unlike ColorData[1,"ColorList"] which is out by 10^-16 in some cases. System`Private`$PlotStyleFunction[n, lst] gives a list of styles n long where extra styles in lst are "Riffled" into it. This behaviour can be easily emulated, but changing $PlotStyleFunction (either as a DownValue or a pure function OwnValue) doesn't seem to make any difference to Plot... :( – Simon – 2011-04-10T00:08:43.207

@Simon, you see why I was excited, and then disappointed. I wonder if that actually is the right function, but if it is called at a level lower than DownValues/OwnValues and thereby out of reach. Do you know if this is possible? – Mr.Wizard – 2011-04-10T02:25:45.400

@Mr.Wizard: Yep, I see it. Were you able to get Mma to give you any info about System`Private`$PlotStyleFunction? Although it evaluates as in your edit, I couldn't find any *values for it and nothing shows up in any trace that I tried -- I think this means that it might be a "kernel function" i.e. built in and compiled into the kernel. This is probably the lower level that you were asking about (although I don't know much about it and could be wrong!!) – Simon – 2011-04-10T02:52:03.380

I just tried this type of trick to see if System`Private`$PlotStyleFunction is called when Ploting... it looks like it might not be. Maybe it's just a copy of or a reference to a more basic function that is used by Plot?

– Simon – 2011-04-10T03:00:12.827

@Simon @Mr. Sherlock would be proud of you both :) – Dr. belisarius – 2011-04-10T20:49:52.940

@Simon the text "$PlotStyleFunction" does appear within mathdll.dll. I don't know where to go from here. – Mr.Wizard – 2011-04-11T10:56:09.707

2@Mr.Wizard When searching the string $PlotStyleFunction in the Mathematica's directory by Total Commander I have found four files in the "C:\Program Files\Wolfram Research\Mathematica\7.0\SystemFiles\Kernel" subdirectories: {Binaries\Windows-x86-64\mathdll.dll,Binaries\Windows\mathdll.dll,SystemResources\Windows-x86-64\Explore\PlotExplorer.mx,SystemResources\Windows\Explore\PlotExplorer.mx}. HTH. – Alexey Popkov – 2011-04-11T12:18:37.550