Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I've got this code

Plot[{(V^2/360)/0.4,  ConditionalExpression[(V^2/860)/0.4, V < 12], 
  ConditionalExpression[(V^2/860)/0.4, V > 12]}, {V, 8, 18},  
 PlotRange -> {0, 1.5}, 
 PlotStyle -> {{AbsoluteThickness[3]}, {AbsoluteThickness[3], 
    Dashed}, { AbsoluteThickness[3], ColorData[1, 2]}}, 
 GridLines -> Automatic, 
 Epilog -> {{Thick, Dashed, Black, Line[{{12, 0}, {12, 2}}]}, {Thick, 
    Dashed, Black, Line[{{8, 1}, {18, 1}}]}}] 

to plot a function in two pieces, each in a different style:

enter image description here

This works OK for me, though I didn't like it that I had to use ColorData[1, 2] to get the second part in the same color. Are there better ways to do this (possibly something with Piecewise)?

share|improve this question
    
Related: mathematica.stackexchange.com/q/1128/121 –  Mr.Wizard Apr 27 '13 at 20:10

6 Answers 6

up vote 17 down vote accepted

Here's something a little better than my previous minimal-effort answer. I've taken Mr. Wizard's clever trick of using Sequence and I to get both sections of the plot assigned to the same element of PlotStyle, and also used the ability of PlotStyle to take functions as well as graphics directives.

First define the functions splitplot and splitstyle:

SetAttributes[splitplot, HoldAll];
splitplot[pieces__] := Piecewise[{#}, I] & /@ Unevaluated @ pieces
splitplot[{v_, c_}] := splitplot[{v, c}, {v, ! c}]

splitstyle[styles__] := Module[{st = Directive /@ {styles}},
{{Last[st = RotateLeft @ st], #}} & ]

Usage:

  • splitplot takes pairs of {value, condition} like Piecewise, and is used as the function to be plotted.
  • There can be any number of "pieces" to the plot.
  • If only a single piece is specified, a second piece {value, Not[condition]} will be automatically added.
  • splitstyle takes style directives, which are applied to those pieces. The styles are used cyclically.
  • Each style directive can be a list like {Red, Thick}
  • The splitstyle function can itself be a member of a list, for example {Thick, splitstyle[Red, Blue]} will split the plot into red and blue parts, both of which are thick.
  • An empty list {} can be given to apply the default style with no alterations.

Simple example - apply dashing for x<0.5

Plot[{x, splitplot[{x^2, x < 0.5}]}, {x, 0, 1},
 PlotStyle -> {Thick, {Thick, splitstyle[Dashed, {}]}}]

enter image description here

Note that if the condition describes multiple unconnected regions this will generate multiple "pieces". In the plot below the condition x<2||x>4 produces two pieces, which are assigned to the first two style directives in splitstyle.

Plot[splitplot[{x, x < 2 || x > 4}, {13 x - 2 x^2 - 16, 2 < x < 4}], {x, 0, 6},
 PlotStyle -> splitstyle[Dashed, Green, Red]]

enter image description here

Multiple splitplot and splitstyle can be used in a single Plot

Plot[{splitplot[{6 - 2 x, x < 2}, {2 x - 2, x > 2}], 
  splitplot[{2 x, x < 3}, {12 - 2 x, x > 3}]}, {x, 0, 5}, 
 PlotStyle -> {splitstyle[{}, Dashed], splitstyle[Dashed, {}]}]

enter image description here

share|improve this answer
    
We've got a good thing going. I see some room for code reduction here; may I make the edits? –  Mr.Wizard Jul 14 '12 at 18:48
    
@Mr.Wizard, please go right ahead! –  Simon Woods Jul 14 '12 at 20:14
1  
Edits made; please tell me what you think. There is something unfinished: Piecewise normally does not evaluate all value expressions, e.g.: x = 7; Piecewise[{{Print[1], x < 5}, {Print[2], x > 10}}, Print[3]] does not print 1 or 2. If you think there is value in preserving this behavior we could write: Replace[Unevaluated@pieces, x_ :> Piecewise[{x}, I], {1}] -- I'm not sure if this is needed given the application however. –  Mr.Wizard Jul 15 '12 at 1:17
    
BTW, I restrained myself from using ~infix~ notation as not everyone likes that, but there are a couple of binary operators that are amenable to that here. :-) –  Mr.Wizard Jul 15 '12 at 1:18
3  
Regarding infix, I'm not convinced that it would improve readability in this case :-) BTW (and off topic) my favourite infix function is opt_~of~obj_ := opt /. AbsoluteOptions[obj, opt] –  Simon Woods Jul 15 '12 at 12:20

Your method already looks pretty good to me. However, since you are looking for alternatives, here is one, though honestly I'd do it the way you started for clarity and robustness.

This uses the behavior shown in this answer, then /. (ReplaceAll) to style the separate Line expressions afterward.

Piecewise is used with a default argument of I (imaginary number) which does not plot.

The replacement works on the internal format of the Graphics expression produced by Plot as described here.

Plot[
  {V^2/144`,
   Sequence[
    Piecewise[{{V^2/344`, V < 12}}, I],
    Piecewise[{{V^2/344`, V > 12}}, I]
   ]
  },
  {V, 8, 18},
  PlotRange -> {0, 1.5},
  PlotStyle -> AbsoluteThickness[3],
  GridLines -> Automatic,
  Epilog -> {Thick, Dashed, Black, Line[{{{12, 0}, {12, 2}}, {{8, 1}, {18, 1}}}]}
] /. {sty__, x_Line, y_Line} :> {sty, y, Dashed, x}

Mathematica graphics

share|improve this answer

You can use a Piecewise to combine your curve, and then use Mesh and MeshShading to specify different styles for different ranges. In the example below there is only a split at 12, so Mesh -> {{12}}.

MeshShading is then used to style the different ranges.

Plot[{(V^2/360)/0.4, 
     Piecewise[{{(V^2/860)/0.4, V < 12}, {(V^2/860)/0.4, V > 12}}]
   },
   {V, 8, 18},
   PlotRange -> {0, 1.5},
   GridLines -> Automatic, 
   Mesh -> {{12}},
   MeshShading -> {Dashed, Automatic}, 
   PlotStyle -> AbsoluteThickness[3], 
   Epilog -> {{Thick, Dashed, Black, Line[{{12, 0}, {12, 2}}]}, {Thick, 
      Dashed, Black, Line[{{8, 1}, {18, 1}}]}}
]

Exported plot

I did not manage to only make one of the curves dashed with one call.

A hackery way to do it is to create two plots, the first with a Transparent curve. I don't recommend this though, as your version is cleaner.

p1 = Plot[{1, Piecewise[{{(V^2/860)/0.4, V < 12}, {(V^2/860)/0.4, V > 12}}]},
  {V, 8, 18}, PlotRange -> {0, 1.5}, 
  PlotStyle -> {Transparent, {AbsoluteThickness[3]}}, 
  GridLines -> Automatic, Mesh -> {{12}}, 
  MeshShading -> {Dashed, Automatic}, 
  Epilog -> {{Thick, Dashed, Black, Line[{{12, 0}, {12, 2}}]}, {Thick,
      Dashed, Black, Line[{{8, 1}, {18, 1}}]}}]

p2 = Plot[(V^2/360)/0.4, {V, 8, 18}, PlotRange -> {0, 1.5}, 
  PlotStyle -> AbsoluteThickness[3]]

Show[p1, p2]

The result is the same as your output.

share|improve this answer
    
As you can see your first method gives a different output, I can't use that. Thanks for answering, anyway. –  stevenvh Jul 11 '12 at 10:41
    
Yes, I know. The answer is to the more general question how to plot a single function in two different styles, which can be done with Mesh and MeshShading. I hope someone comes up with a clean answer for your case where there are multiple curves, and only one of them is styled in two ways. –  Malte Lenz Jul 11 '12 at 10:45
    
I'm rather new to MMA, and realize that I still do lots of things in a less than optimal way. But I have already experienced that MMA is quite powerful and flexible, not only its strictly analytic engine, so I wouldn't be surprised if there's a better way here too. –  stevenvh Jul 11 '12 at 10:51

Something else for your consideration:

p1 = Plot[V^2 / 144`, {V, 8, 18}, PlotRange -> {0, 1.5}];
p2 = Plot[V^2 / 344`, {V, #, #2}, PlotStyle -> #3] & @@@
       {{8, 12, {{Red, Dashed}}}, {12, 18, Red}};

Show[
  {p1, p2},
  BaseStyle -> {14, AbsoluteThickness[3]},
  GridLines -> Automatic,
  Epilog -> {Thick, Dashed, Black, 
              Line[{{{12, 0}, {12, 2}}, {{8, 1}, {18, 1}}}]}
]

Mathematica graphics

share|improve this answer

While I think splitplot and splitstyle is a very cool answer, here is my usual, very simplistic way to construct plots like this. Show is your friend, and there is little need for Epilog and Prolog anymore.

With[{a = 0.4, b1 = 360, b2 = 860},
  Show[{
    Plot[v^2/(a b1), {v, 8, 18}, PlotRange -> {0, 1.5}, 
     GridLines -> Automatic, GridLinesStyle -> LightGray, 
     PlotStyle -> Thick],
    Plot[v^2/(a b2), {v, 8, 12}, 
     PlotStyle -> {Thick, Dashed, ColorData[1][2]}],
    Plot[v^2/(a b2), {v, 12, 18}, 
     PlotStyle -> {Thick, ColorData[1][2]}],
    Graphics@{Thick, Opacity[0.4], Line@{{8, 1}, {18, 1}}, 
      Line@{{12, 0}, {12, 1.5}}}
    }
  ]
]
share|improve this answer

Another hack is to change the colour directives.

recolour[plot_, rules__] := Module[{colourpos},
  colourpos = Position[plot, Hue[__]];
  ReplacePart[plot, rules /. {Rule[a_, b_] :>
      Rule[colourpos[[a]], Extract[plot, colourpos[[b]]]]}]]

In this case, to change the 3rd line to have the colour of the 2nd:

Plot[...] ~ recolour ~ {3->2}
share|improve this answer
    
Could you post a working usage of this? I'm not seeing how it addresses both the color and the dashing. –  Mr.Wizard Jul 11 '12 at 14:08
    
@Mr.Wizard, it doesn't address the dashing, it still requires the dashed and undashed parts to be separate curves as in the question. It's just an alternative to putting the ColorData[1,2] into the PlotStyle. –  Simon Woods Jul 11 '12 at 16:18

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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