49
$\begingroup$

For example:

p = Plot[Sin[x], {x, 0, 1}]

Is it possible to write options in Show to change the curve's color for example into red?

Show[p, (* Option?? *)]
$\endgroup$
2
  • 2
    $\begingroup$ p = Plot[Sin[x], {x, 0, 1}]; col = Cases[p, _Hue, Infinity][[1]]; Show[p /. col -> Red] - not sure if this really merits an answer? $\endgroup$
    – Yves Klett
    Jan 4, 2013 at 9:21
  • 2
    $\begingroup$ just to make sure, you wanted the Show way (to work on already existing plots), not simply a Plot[...,PlotStyle->Red] kind of solution ? $\endgroup$
    – Yves Klett
    Jan 4, 2013 at 11:57

3 Answers 3

46
$\begingroup$

I already answered this question on StackOverflow but since old questions can no longer be migrated without undue trouble I shall reproduce my answer here.


There are two different categories of graphical objects in a Plot output.

  1. The plotted lines of the functions (Sin[x], Cos[x]) and their styles are "hard coded" into Line objects, which Graphics can understand.

  2. Auxiliary settings such as Axes -> True, PlotLabel -> "Sine Cosecant Plot" and AxesStyle -> Orange are understood by Graphics directly, without conversion, and therefore remain within the myplot object.

The second kind of settings can be easily changed after the fact because they are soft settings. (e.g. Show[p, (* options *)]

The first kind much be processed in some way. This is complicated by the fact that different *Plot functions output different patterns of Graphics and Plot itself may give different patterns of output depending on the input it is given.

I am not aware of any global way to restyle all plot types, and if you do such restyling often, it probably makes more sense to retain the data that is required and simply regenerate the graphic with Plot. Nevertheless, for basic uses, your method can be improved. Each function plotted creates a Line object, in the given order. Therefore, you can use something like this to completely restyle a plot:

myplot = Plot[{Cos[x], Sin[x]}, {x, 0, 2 Pi}, 
  PlotStyle -> {{Red, Dashing[None]}, {Green, Dashing[None]}}]

Mathematica graphics

newstyles = Directive @@@ {
    {Green, Thickness[.02], Dashing[Tiny]},
    {Thickness[Large], Red}
  };

i = 1;
MapAt[# /. {__, ln__Line} :> {newstyles[[i++]], ln} &, myplot, {1, 1}]

enter image description here

Please note the part {1, 1} in the last line of code above. This is the part specification for the location of the Line objects within myplot. It is specified so as not to accidentally style Lines that might appear in other parts of the Graphics object. This part may need to be changed; for example when using Filling the Lines end up in {1, 2}. For this reason in the function below I simply used 1 which will be more flexible but could conceivably conflict with something.

Restyle function

The method above can be made into a self-contained function.
I will use this method to cycle the styles given.

restylePlot[plot_Graphics, styles_List, op : OptionsPattern[Graphics]] :=
 Module[{x = styles}, Show[
   MapAt[# /. {__, ln__Line} :> {Directive @ Last[x = RotateLeft@x], ln} &, plot, 1],
   op
 ]]

Example:

myplot2 = Plot[Evaluate[Table[BesselJ[n, x], {n, 4}]], {x, 0, 10}, Filling -> Axis]

Mathematica graphics

restylePlot[myplot2,
 {
  {Green, Thickness[.02], Dashing[Tiny]},
  {Thickness[Large], Red},
  Blue
 },
 Axes -> False,
 Frame -> True,
 FrameStyle -> Directive[20, FontColor -> Orange]
]

Mathematica graphics

You will notice that the filling styles have not changed. While it is possible to change these by using GraphicsGroup in place of Line in the replacement rule the structure is considerably more complex to the point of being inconvenient. (It would probably be better to use the Graphics Inspector, or preferably to regenerate the graphic.)


Graphics Inspector

While I personally tend to avoid extensive after-Plot restyling because I like to keep everything in one place (the Plot command), and I prefer to make what changes I do with code so that there is a record of my settings without having to dig into the Graphics object, the Graphics Inspector is directly applicable.

  • Double click the plot. The border should change from orange to thick gray.
  • Single click one of the plot lines. (the pointed should change when you hover over an element)
  • Press Ctrl+g to open the Graphics Inspector.
  • Make the changes you desire, and close the Graphics Inspector.

You can now copy and paste the entire graphic, or directly assign it to a symbol: p = <graphic>

Also see: https://reference.wolfram.com/language/howto/EditWolframLanguageGraphics.html


Tangentially related:

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

Filling Styles using a single Plot in Mathematica

$\endgroup$
11
  • $\begingroup$ btw, I like this one too... You should find a place for this here. $\endgroup$
    – rm -rf
    Jan 4, 2013 at 17:56
  • $\begingroup$ Yes, it works, but you need to fix a typo in the definition – MapAt[..., plot, 1]. Also, my dashings look very different (like thick solid green). Do you have custom settings? $\endgroup$
    – rm -rf
    Jan 4, 2013 at 17:59
  • $\begingroup$ @Hypnotoad thanks! hm... I don't think I've got custom dashing. I better look at that. $\endgroup$
    – Mr.Wizard
    Jan 4, 2013 at 18:04
  • $\begingroup$ @Hypnotoad how does Thickness[.02], Dashing[Tiny] look in other plots? $\endgroup$
    – Mr.Wizard
    Jan 4, 2013 at 18:22
  • $\begingroup$ It looks same as in the above plot. I'm not surprised though, because I always run into trouble with Thickness (since it's based on the plot size and possibly other things). I always use AbsoluteThickness for these. $\endgroup$
    – rm -rf
    Jan 4, 2013 at 19:00
33
$\begingroup$

Ah well... this is not robust, but probably of educational value and useful as a starting point for other post-processing needs on Graphics or Graphics3D expressions:

p = Plot[Sin[x], {x, 0, 1}]
col = Cases[p, _Hue, Infinity][[1]];
Show[p /. col -> Red]

Mathematica graphics

Update: As pointed out by matheorem, Version 10 switched from Hue to RGBColor, so the Casesstatement has to be changed accordingly, preferably (thanks to @rcollyer) using ColorQ to cover all future bases. (e.g. Show[p /. _?ColorQ -> Red])

$\endgroup$
13
  • 5
    $\begingroup$ Thank you very much! You're so clever! But I found an easier way inspired by your idea. A single line Show[p/._Hue->Red] will be enough! $\endgroup$
    – matheorem
    Jan 4, 2013 at 14:17
  • 1
    $\begingroup$ @user15964 thanks for the unexpected praise =). It is very good to see you managed an even simpler solution (mine may still be of use for plots with multiple colors). $\endgroup$
    – Yves Klett
    Jan 4, 2013 at 14:38
  • 2
    $\begingroup$ @YvesKlett Oh, I just found that in Mathematica 10, Hue is not working any more. They have changed Hue into RBGColor. So now in M10, we have to use p/._RGBColor->Red. Since your answer is most popular, you may add a note to it. $\endgroup$
    – matheorem
    Nov 5, 2014 at 13:35
  • 6
    $\begingroup$ @YvesKlett use _?ColorQ instead for v10 as it covers all your bases. $\endgroup$
    – rcollyer
    Nov 5, 2014 at 15:36
  • 3
    $\begingroup$ For fun: Animate[Plot[Evaluate[Table[1/(x - 2 n), {n, 4}]], {x, 0, 10}, Filling -> Axis] /. c_?ColorQ :> Function[{h, s, b}, Hue[h + a, s, b]] @@ ColorConvert[c, "HSB"], {a, 0, 1}] $\endgroup$
    – Michael E2
    Nov 5, 2014 at 17:11
16
$\begingroup$

As Mr.Wizard indicated, you can also reconstruct the plot using the data. Here is an example:

restylePlot2[p_, op : OptionsPattern[ListLinePlot]] := 
    ListLinePlot[Cases[Normal@p, Line[x__] :> x, ∞], op, Options[p]]

then we can set the style as we do in plot. For example

restylePlot2[myplot2, 
 PlotStyle -> {{Green, Thick, Dashed}, {Thickness[Large], Red}, Blue},
  Filling -> Axis, FrameStyle -> Directive[20, FontColor -> Orange], 
 PlotLegends -> LineLegend[{"1", "2", "3", "4"}]]

enter image description here

I found it useful when sometime I want to combine several plots:

pls = Table[Plot[Sin[n x], {x, 0, 2 π}], {n, 1, 3}];

enter image description here

restylePlot2[pls, Joined -> True, Axes -> False, Frame -> True, PlotLegends -> {"1", "2", "3"}] 

enter image description here

$\endgroup$
3
  • 1
    $\begingroup$ Nice idea. I think you are missing Joined -> True in the first example; I recommend using ListLinePlot rather than Joined -> True anyway. Also this loses any options from the original including any Prolog and Epilog that may exist. I think it would be better to filter the old options and use them as the defaults, allowing them to be overridden by any new ones that are given. $\endgroup$
    – Mr.Wizard
    Sep 16, 2014 at 1:22
  • $\begingroup$ @Mr.Wizard Thanks for pointing out, I was setting Joined->True to be the default setting in my Mathematica so I didn't notice. But for the old options, I did attach them to the end so I think Epilog, Prolog etc. should be alright. $\endgroup$ Sep 16, 2014 at 14:00
  • $\begingroup$ I somehow either missed or misread that. One refinement you might make: use OptionsPattern[ListLinePlot] as that is the function that will be receiving the options. $\endgroup$
    – Mr.Wizard
    Sep 16, 2014 at 14:58

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.