Proper way to Plot a single function in two different styles?
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} likePiecewise
, 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, {}]}}]
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]]
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, {}]}]
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}
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}}]}}
]
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.