20
$\begingroup$

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)?

$\endgroup$
1

5 Answers 5

22
$\begingroup$

Note - this does not work since version 10

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

$\endgroup$
10
  • $\begingroup$ We've got a good thing going. I see some room for code reduction here; may I make the edits? $\endgroup$
    – Mr.Wizard
    Commented Jul 14, 2012 at 18:48
  • $\begingroup$ @Mr.Wizard, please go right ahead! $\endgroup$ Commented Jul 14, 2012 at 20:14
  • 1
    $\begingroup$ 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. $\endgroup$
    – Mr.Wizard
    Commented Jul 15, 2012 at 1:17
  • 3
    $\begingroup$ 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] $\endgroup$ Commented Jul 15, 2012 at 12:20
  • 2
    $\begingroup$ @Simon Woods Your useful splitplot and splitsyle functions don't work anymore with MMA V10. Can it be easily updated ? Thanks $\endgroup$
    – Sigis K
    Commented Apr 1, 2015 at 12:41
9
$\begingroup$

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

$\endgroup$
0
6
$\begingroup$

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.

$\endgroup$
3
  • $\begingroup$ As you can see your first method gives a different output, I can't use that. Thanks for answering, anyway. $\endgroup$
    – stevenvh
    Commented Jul 11, 2012 at 10:41
  • $\begingroup$ 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. $\endgroup$
    – Malte Lenz
    Commented Jul 11, 2012 at 10:45
  • $\begingroup$ 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. $\endgroup$
    – stevenvh
    Commented Jul 11, 2012 at 10:51
4
$\begingroup$

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

$\endgroup$
4
$\begingroup$

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}}}
    }
  ]
]
$\endgroup$

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.