views:

214

answers:

3

My question is: why doesn't the following work, and how do I fix it?

Plot[f[t], {t, 0, 2*Pi}] /. {{f -> Sin}, {f -> Cos}}

The result is two blank graphs. By comparison,

DummyFunction[f[t], {t, 0, 2*Pi}] /. {{f -> Sin}, {f -> Cos}}

gives

{DummyFunction[Sin[t], {t, 0, 2 *Pi}],  DummyFunction[Cos[t], {t, 0, 2 * Pi}]}

as desired.

This is a simplified version of what I was actually doing. I was very annoyed that, even after figuring out the annoying "right way" of putting the curly brackets nothing works.

In the end, I did the following, which works:

p[f_] := Plot[f[t], {t, 0, 2*Pi}]
p[Sin]
p[Cos]
+3  A: 

Mathematica is trying to evaluate Plot before the substitution. You can prevent that with the Hold and ReleaseHold functions:

ReleaseHold[Hold[Plot[f[t],{t,0,2*Pi}]] /. {{f -> Sin},{f -> Cos}}]

Hold[] will force the entire Plot subexpression to remain unsimplified while the substitution is performed, then ReleaseHold[] will let it proceed with the actual plotting.

Peter Milley
Thank you for your answer. Your solution has a typo, you should have /. instead of the first ->. It works. However, it makes little sense to me why substitution wouldn't be at the top of the order of precedence...
Ilya
(The typo is now fixed by Ramasalanka)
Ilya
I can't explain why the order of operations is the way it is, but it's not just Plot. Mathematica will try to evaluate any function on the left-hand side of /. (sorry about the typo earlier) before it performs the substitution. A lot of the time that doesn't matter: the undefined f[t] will just be carried through the function definition until the substitution is performed. For example, myFun[x_, l_] := x /@ l; myFun[f, {1,2,3}] /. {{f->Sin}, {f->Cos}} will work like you expect it to. But Plot[] is one of the examples where having f[t] be undefined will result in an immediate error.
Peter Milley
The reason that `Plot` evaluates before the rule-replacement is because `/.` is just an infix operator for the `ReplaceAll` function. `f[x] /. x-> y` is therefore just the expression `ReplaceAll[f[x], x->y]` and `ReplaceAll` does not have any `Hold*` attributes.See this tutorial for more basics about Mathematica's evaluation semantics: http://reference.wolfram.com/mathematica/tutorial/Evaluation.html
Michael Pilat
+3  A: 

As an alternative to Peter's Hold/ReleaseHold strategy you could do

Plot[Evaluate[ f[t]/. {{f -> Sin}, {f -> Cos}} ], {t, 0, 2*Pi}]

which is a little cleaner to read. This ensures that f is substituted before Plot is evaluated.

rcollyer
You don't even need the `Evaluate[]`, just having moved the substitution inside the `Plot[]` is enough.`Plot[f[t]/. {{f -> Sin}, {f -> Cos}}, {t, 0, 2*Pi}]`
Isaac
@Isaac: Not always. There have been times I have found that it is necessary to `Evaluate` first, otherwise `Plot` doesn't do what you expect.
rcollyer
@rcollyer: Yes, it depends on what's being substituted. In this particular instance, it works as I said, though (at least for me in 7.0.1.0) your code produces the curves in two different colors and my code produces both curves in the same color. Of course, both your code and mine produce two curves on one grid, which may not have been what the original poster intended (perhaps two separate grids).
Isaac
I'm sorry to keep jumping with my accepted answer. I realized that Isaac is right: I did want two separate plots. Your answer is still very interesting, though.
Ilya
@Ilya, truthfully, I'd go with @gdelfino's method then, as it is more transparent, and only go with the `Hold`/`ReleaseHold` method for the more complicated cases.
rcollyer
Using `Evaluate` means the susbtitution is done once and then the result is used by `Plot`; without `Evaluate`, the `ReplaceAll` will be once per plot point. Then `Plot` won't do the analysis that lets it automagically give curves different colors. It's also slower if you aren't doing something simple--stick an `NDSolve` on the right side of that `/.` and you'll probably have time to get a cup of coffee if the `Evaluate` isn't there. 9 times out of 10 `Evaluate` is the right solution: the exception is if the thing you're trying to `Plot` needs a numerical argument to work.
Pillsy
+3  A: 

This one is even shorter:

Plot[#[t], {t, 0, 2*Pi}] & /@ {Sin, Cos}
gdelfino
This is very nice! I'm accepting Peter's answer since it seems less like a puzzle, but this is certainly a cool way to shorten my "solution" to a line.
Ilya
To further lobby for this method (and Peter's can be extended in the same way), this can be extended using `MapIndexed` or `MapThread` to allow you to style each plot differently. Additionally, they can then be combined using `Show` to create rather complex plots. (This is the method I tend to favor in my data analysis.)
rcollyer