1

I'm trying to get a plot of different order Fourier series of the function x-1, why does Mathematica give me an empty plot?

f[x_, N_] := FourierSinSeries[x-1, x, N]
Plot[{f[x, 1], f[x, 5]}, {x, 0, 3}]

Executing f[x,1] and f[x,5] do give me valid functions. A workaround is:

f1=f[x,1]
f5=f[x,5]
Plot[{f1,f5},{x,0,3}]

Why does it only work that way?

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
Jeroen
  • 11
  • 1

2 Answers2

2

That's because Plot is a numerical function which evaluates its first argument with numerical values of x while FourierSinSeries requires symbolic variable. What happens is that Plot internally makes an assignment like

 x = 0;

and then evaluates

 f[x, 1]
 FourierSinSeries[-1, 0, 1]

The obtained expression isn't numeric, and Plot simply ignores it without warning.

Your workaround works because you preliminarily evaluate FourierSinSeries with unassigned x what results in an expression suitable for plotting:

 x =.;
 f[x, 1]

(2 - 4/π) Sin[x]


This behavior (except the absence of a warning message) is documented under "Details and Options" on the Docs page for Plot :

Plot has attribute HoldAll and evaluates f only after assigning specific numerical values to x.

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
  • 1
    Another work around is to curry f. Define f[n_] := f[n] = Function[x, Evaluate@FourierSinSeries[x - 1, x, n]]. Then Plot[{f[1][x], f[5][x]}, {x,0,3}]. – evanb Mar 16 '17 at 07:09
  • @evanb Good demonstration of currying with memoization. But for safety it is better to use \[FormalX] instead of x in the definition for f. – Alexey Popkov Mar 16 '17 at 07:16
  • Can you demonstrate? I frankly never understood the use of the Formal parameters. Maybe this deserves its own question? – evanb Mar 16 '17 at 07:40
  • @evanb In your function definition your Evaluate breaks the scope of Function and if x has a value, it will be substituted into the FourierSinSeries[x - 1, x, n] expression before evaluation of FourierSinSeries. The safety of formal parameters comes from the fact that they are Protected and you can't assign values to them. More lengthy explanation can be found in this answer. – Alexey Popkov Mar 16 '17 at 07:47
  • I see. It's to protect you from picking up state. Thanks for the pointer / link! – evanb Mar 16 '17 at 07:52
  • I tried x = 3; f[n_] := f[n] = Function[x, Evaluate@FourierSinSeries[x - 1, x, n]] (after quitting the kernel) and it works fine. So in this case there doesn't seem to be any danger---Evaluate must understand that it is inside a Function. – evanb Mar 16 '17 at 08:00
  • @evanb The reason why it works in this case is not that Evaluate "understands" something: evaluating f[n] returns Function[x, FourierSinSeries[2, 3, n]] what demonstrates that the scope is indeed broken. What happend here is that the lexical replacement (which comes from the delayed definition :=) is performed inside of the body of Function before the Evaluate fires, i.e. when the scope is not broken yet. [continued in the next comment] – Alexey Popkov Mar 16 '17 at 09:09
  • @evanb As a result Function renames its local variable x to x$ what in effect protects it from being replaced by the value of x when Evaluate fires. This behavior is (a bit vaguely) documented: "In general, the Wolfram Language renames the formal parameters in an object like Function[vars,body] whenever body is modified in any way by the action of another pure function." In this answer I give extended explanation of this behavior. – Alexey Popkov Mar 16 '17 at 09:09
  • @evanb But your point is correct: in this case we won't get additional safety by using a formal symbol as a parameter because we already have subtle and very limited additional scoping due to the combination of RuleDelayed and Function (I forgot about this possibility when wrote the first comment). Such scoping isn't very reliable though (as I showed above). – Alexey Popkov Mar 16 '17 at 09:26
  • Gotcha. So here it's more of a best-practices thing, but in other examples it can really save you. – evanb Mar 16 '17 at 09:47
  • 1
    @evanb A detailed explanation of the variable renaming mechanics can be found in this answer (and after reading it I realized that my formulation above wasn't quite correct: actually it is namely RuleDelayed who renames x to x$ inside of Function, because the latter is inert on that stage). – Alexey Popkov Mar 16 '17 at 09:48
  • @evanb Yes, it is a best-practice rule: when you use Evaluate always remember that it can break scoping and hence you (possibly) have to introduce additional scoping/protection in order to avoid bugs. – Alexey Popkov Mar 16 '17 at 09:52
0

Expressions don't get automatically evaluated inside the Plot function.

This is because Plot is HoldAll

Workaround: use Evaluate

Including an Evaluate function:

f[x_, n_] := FourierSinSeries[x - 1, x, n];

Plot[{Evaluate@f[x, 1], Evaluate@f[x, 5]}, {x, 0, 3}]

Conor
  • 7,449
  • 1
  • 22
  • 46