12
$\begingroup$

This is my first question on any stack-exchange site and I'm also very new to using Mathematica software so please excuse/correct me if I mess up.

I would like to take a list of functions of a single variable {$f_1, f_2, f_3, \ldots, f_n$}, and plot the minimum value that each of these functions takes on at any point over an interval $[x_0, x_f]$.

So far this much is not so difficult (or has not been the difficult part for me to figure out). However, I would like for each of the intervals over which any function $f_i$ is the minimum to correspond to it's own color (like how Plot usually attributes different colors to different curves when you plot multiple functions) and further I'd like to include a legend that clearly denotes which function from the list corresponds to which color.

I can do the first part fairly easily using the following:

Z[x_] = Min[x, x^2, x^3, x^4, x^5]
Plot[Z[x], {x, 0, 2}, PlotLegends -> "Expressions"]

Plotting the minimum value of a list of multiple functions

I would like something that would color the segment of the curve where $x^5$ is the minimum function in the list one color and the segment where $x$ is the minimum function in another color and denote the color representations on the legend on the right.

I can plot each of the functions separately with the color-coding system like so:

Plot[{x, x^2, x^3, x^4, x^5}, {x, 0, 2}, PlotLegends -> "Expressions"]

Plotting multiple functions with color-coding and legend

And in both cases the " PlotLegends -> "Expressions" " flag/option (not sure what the terminology is for Mathematica functions) does nicely generate a legend as I'd like it.

But I don't really have a sense of how to combine the two.

Thanks in advance for the help, and while I didn't find any other questions that might help answer (or partially answer) this question please correct me if I missed any.

$\endgroup$
1
  • $\begingroup$ An idea for a solution I would want to use but don't know how to implement is generating a list of {g1, g2, ..., gn} defined so that g_i = f_i when f_i is the minimum of all the functions and is undefined otherwise. Then plotting all these functions would be (I suspect) sufficient by the means as the second attempt above. $\endgroup$
    – Moodragonx
    Commented May 16, 2014 at 15:48

4 Answers 4

9
$\begingroup$

New method

Inspired by your self-answer we can automate things as follows:

prep[fn_][a__] := If[# == fn[a], #] & /@ {a}

Now:

Plot[prep[Min][x, x^2, x^3, x^4, x^5], {x, 0, 2},
 BaseStyle -> {14, Thick},
 Frame -> True,
 PlotStyle -> {Red, Orange, Yellow, Green, Blue},
 Evaluated -> True
]

enter image description here

Although untested I presume this will work with PlotLegends. Note:

  • prep is somewhat generalized so that it can work with other functions
  • Evaluated -> True is used rather than Evaluate to keep x localized to the Plot
  • This method doesn't work in version 9.0.0 due to a bug. (47981)

Old methods

It may surprise you to learn that Mathematica internally splits the Line on discontinuities (when using the default value Automatic for the Exclusions option), which allows you do use the post-processing method shown here (bottom), e.g.:

f[x_] := Min[x, x^2, x^3, x^4, x^5]

Module[{i = 1},
 Plot[f[x], {x, 0, 2}, PlotStyle -> Thick]
  /. x_Line :> {ColorData[1][i++], x}
]

enter image description here

Or Simon Woods's splitstyle:

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

Plot[f[x], {x, 0, 2}, PlotStyle -> splitstyle[Red, Green], BaseStyle -> Thick]

enter image description here

Notes

I don't have the PlotLegends option in version 7, which I use, therefore I cannot test that aspect of the question. Pardon me for not mentioning that directly.

You asked for an explanation of these methods. They are similar, yet work different. Both rely on the operation of the Exclusions mechanism of Plot. When a discontinuity is found a new Line primitive is created within the Graphics expression that is produced by Plot. The first method works by replacing (see ReplaceAll) each Line expression with a {style, Line} pair. (style is drawn from an arbitrarily selected ColorData scheme.)

The second method relies on a clever construction and the behavior of the PlotStyle option when it is given a function as its value. The function generated by splitstyle uses this method to cycle between given styles (not used in this example, but useful elsewhere). It also produces a {style, Line[ . . . ]} pair, and this expression is inserted by Plot itself rather than with post-processing.

$\endgroup$
23
  • $\begingroup$ Thank you for the prompt response. This doesn't seem to address the generation of a legend request here, however. Will the PlotLegends option used in my question still work to handle this? Further, being new to mathematica the syntax or methods used here are a little lost on me. I'll read up on this but further explanation of how this works would be awesome and whether I should have a reason to choose one method over the other would be appreciated as well. $\endgroup$
    – Moodragonx
    Commented May 16, 2014 at 15:27
  • $\begingroup$ @Moodragonx You're welcome. $\endgroup$
    – Mr.Wizard
    Commented May 16, 2014 at 15:28
  • $\begingroup$ @Moodragonx More notes added. Sorry I can't help with the PlotLegends option, at least not directly. $\endgroup$
    – Mr.Wizard
    Commented May 16, 2014 at 15:41
  • $\begingroup$ Thanks for the clarification. Just thought I'd confirm that PlotLegends -> "Expressions" doesn't provide a separate legend entry for each section of the curve (which I expected since it is still only a single function f[x] being plotted). $\endgroup$
    – Moodragonx
    Commented May 16, 2014 at 15:45
  • 1
    $\begingroup$ Interesting news: Both definitions work fine on Mathematica 9.0.1.0 on Linux. My previous comments were on Mathematica 9.0.0.0 on Mac. $\endgroup$
    – user484
    Commented May 16, 2014 at 17:23
7
$\begingroup$

Simple solution using RegionFunction:

f[x_] := {x, x^2, x^3, x^4, x^5};
Plot[Evaluate@f[x], {x, 0, 2}, PlotLegends -> "Expressions", 
 RegionFunction -> Function[{x, y}, y == Min[f[x]]], PlotPoints -> 20, 
 PlotRange -> All, PlotStyle -> ColorData[35, "ColorList"]]

enter image description here

One limitation is that you get overshooting unless you fiddle with the number of PlotPoints.

The only reason I changed the PlotStyle is because the first and fifth colours are hard to tell apart in the default colour scheme.

$\endgroup$
3
  • $\begingroup$ Great idea! I suggest using Evaluated -> True here to localize x, assuming that doesn't break anything. $\endgroup$
    – Mr.Wizard
    Commented May 16, 2014 at 16:11
  • $\begingroup$ I'm a little wary of using undocumented options... $\endgroup$
    – user484
    Commented May 16, 2014 at 16:24
  • $\begingroup$ Awesome. This seems to do exactly what I want. I feel silly for not knowing how RegionFunction worked but that's essentially exactly what I was looking for. Thanks! $\endgroup$
    – Moodragonx
    Commented May 16, 2014 at 16:24
6
$\begingroup$
flist = Table[BesselJ[n, x], {n, 4}];
pieces = Table[ConditionalExpression[f, f == Min[flist]], {f, flist}]; (* thanks Rahul *)
pltstyls = Join[#, Directive[{#, Thickness[.01], Dashed}] & /@ #] &[
            ColorData[1, "ColorList"][[;; Length@flist]]];
lgndlbls = Join[#, StringJoin["piece ", #] &/@ (ToString /@ #)]&[TraditionalForm /@ flist];


Plot[Evaluate@Join[flist, pieces], {x, 0, 10},
     Filling -> Thread[Range[Length@flist] -> Axis], ImageSize -> 500,
     PlotStyle -> pltstyls, PlotLegends -> lgndlbls]

enter image description here

Update: Generalizing to arbitrary list of functions flist and functionals on flist:

 foo = Module[{pieces =Table[ConditionalExpression[f, f == #[#2]], {f, #2}], 
        styles = Join[#, Directive[{#, Thickness[.01], Dashed}] & /@ #] &[
                    #3[[;; Length@#2]]],
       lgndlbls =  Join[#, StringJoin["piece ", #] & /@ (ToString /@ #)] &[
                    TraditionalForm /@ #2]},
 Plot[Evaluate@Join[#2, pieces], {x, 0, 10}, 
        Filling -> Thread[Range[Length@#2] -> Axis], ImageSize -> 500, 
        PlotStyle -> styles, PlotLegends -> lgndlbls]] &;

 foo[RankedMin[#, 2] &, flist, ColorData[1, "ColorList"]]

enter image description here

$\endgroup$
3
  • $\begingroup$ This is an interesting solution. If you get the chance, some explanation of what's at work here would be nice. I've also been having some trouble generalizing this to other functions I might use (different lists with different numbers of functions) some help using this solution would be appreciated :). $\endgroup$
    – Moodragonx
    Commented May 16, 2014 at 17:15
  • 1
    $\begingroup$ Suggestion: define pieces simply as Table[ConditionalExpression[f, f == Min[flist]], {f, flist}] :) Also note that this approach suffers from the same problems that plague Mr.Wizard's "New Method" on Mathematica 9. $\endgroup$
    – user484
    Commented May 16, 2014 at 17:20
  • $\begingroup$ @RahulNarain, thank you. Updated with your suggestion. Re the version/OS related issues, this seems to work ok on MMA version 9.0.1 on Windows 7. $\endgroup$
    – kglr
    Commented May 16, 2014 at 20:48
5
$\begingroup$

I have somewhat devised a solution that does what I'm looking for but requires manually generating a list of functions that I'd like to avoid.

Z[x_] = Min[x, x^2, x^3, x^4, x^5]
g1[x_] = Piecewise[{{x, x == Z[x]}}]
g2[x_] = Piecewise[{{x^2, x^2 == Z[x]}}]
g3[x_] = Piecewise[{{x^3, x^3 == Z[x]}}]
g4[x_] = Piecewise[{{x^4, x^4 == Z[x]}}]
g5[x_] = Piecewise[{{x^5, x^5 == Z[x]}}]
Plot[{g1[x], g2[x], g3[x], g4[x], g5[x]}, {x, 0, 2}, PlotRange -> All, PlotLegends -> "Expressions"]

Produces the following output

Somewhat Desired Result

Some way to automate this would be much more preferred. In general I might want to err on the side of using Mr.Wizard's solution for my use case as I intend to do this repeated for lists of many functions at a time.

Further it might be nice for the expressions in the legend to include the original definitions of the functions $f$, but this is something that can be adjust manually fairly easily.

$\endgroup$
3
  • 1
    $\begingroup$ Does the problem you just reported also affect my "New method" on your system? You can try adding the option PlotRange -> All to yours to see if that corrects it. $\endgroup$
    – Mr.Wizard
    Commented May 16, 2014 at 16:25
  • $\begingroup$ Okay I submit to having completely novice knowledge of how to plot in Mathematica. PlotRange -> All does in fact fix my "error". $\endgroup$
    – Moodragonx
    Commented May 16, 2014 at 16:29
  • $\begingroup$ Please review the present version of my answer. I included three different definitions for prep; could you try each of them and report which, if any, work for you? $\endgroup$
    – Mr.Wizard
    Commented May 16, 2014 at 16:36

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.