4
$\begingroup$

I want to plot several curves of functions which are hard to calculate on the same plot. I would like to add to the same plot the sum of these functions without recalculating them twice at each point.

So instead of

 Plot[{Sin[x], Sin[2 x], Sin[x] + Sin[2 x]}, {x, 0, 6 Pi}]

I would like somthing like

 Plot[{aa = Sin[x], bb = Sin[2 x], aa + bb}, {x, 0, 6 Pi}]
$\endgroup$
6
  • 3
    $\begingroup$ precalculate points in advance and then use ListPlot? $\endgroup$
    – BlacKow
    Commented May 10, 2016 at 15:06
  • 3
    $\begingroup$ Try Plot[With[{aa = Sin[x], bb = Sin[2 x]}, {aa, bb, aa + bb}], {x, 0, 6 Pi}, Evaluated -> False] (untested). Might give three lines of a single colour. $\endgroup$
    – Szabolcs
    Commented May 10, 2016 at 15:11
  • $\begingroup$ @Szabolcs wouldn't it recalculate aa? how will it choose sample rate? $\endgroup$
    – BlacKow
    Commented May 10, 2016 at 15:14
  • 1
    $\begingroup$ @Szabolcs It works just like you said (all three lines in the same color, though). $\endgroup$
    – Jens
    Commented May 10, 2016 at 15:28
  • 1
    $\begingroup$ "without recalculating them twice at each point." - due to the adaptive sampling, it is quite possible that Plot[] will evaluate the sum at points where neither of the components were evaluated, and vice versa. $\endgroup$ Commented May 10, 2016 at 18:27

2 Answers 2

7
$\begingroup$

How about this:

f[x_] := Sin[x]
Plot[{#1, #2, #1 + #2} &[f[x], f[2 x]], {x, 0, 4}]

Strangely enough, this solution is slower that expected:

f[x_] := NIntegrate[Sin[1/y^2], {y, -x, x}] (*slow function*)

AbsoluteTiming[Plot[{f[x], f[2 x], f[x] + f[2 x]}, {x, 0, 1}]] (*naïve approach*)
AbsoluteTiming[Plot[{#1, #2, #1 + #2} &[f[x], f[2 x]], {x, 0, 1}]] (*my solution*)
AbsoluteTiming[Plot[With[{aa=f[x],bb=f[2x]},{aa,bb,aa+bb}],{x,0,1},Evaluated->False]] (*Szabolcs' comment*)

(*65.7*)
(*106.2*)
(*102.0*)

We do get a substantial improvement with memoization:

f[x_] := f[x] = NIntegrate[Sin[1/y^2], {y, -x, x}]
AbsoluteTiming[Plot[{f[x], f[2 x], f[x] + f[2 x]}, {x, 0, 1}]] (*naïve approach with memoization*)

(*40.5*)

Finally, the best approach so far is to follow BlacKow's suggestion and precalculate the function at discrete points:

f[x_] := NIntegrate[Sin[1/y^2], {y, -x, x}] (*two slow*)
g[x_] := NIntegrate[Cos[1/y^2], {y, -x, x}] (*functions*)

AbsoluteTiming[
  points = Range[0, 1, .01];
  F = f /@ points;
  G = g /@ points;
  ListPlot[{Transpose@{points, F}, Transpose@{points, G}, 
       Transpose@{points, F + G}}, Joined -> True]
]

(*3.4*)

though it can get tricky to choose the appropriate spacing.

$\endgroup$
2
  • $\begingroup$ newbie here any suggestion is very much appreciated :-) $\endgroup$ Commented May 10, 2016 at 16:10
  • $\begingroup$ ListLinePlot[Transpose@{points, #} & /@ {F, G, F + G}] ... maybe? $\endgroup$
    – BlacKow
    Commented May 10, 2016 at 22:52
1
$\begingroup$

A slight variation on AccidentalFourierTransform's version of BlacKow's suggestion.

f[x_] := NIntegrate[Sin[1/y^2], {y, -x, x}]

AbsoluteTiming[
  pts1 = Table[{x, f[x]}, {x, Subdivide[0., 1., 101]}]; 
  pts2 = Table[{x, f[2 x]}, {x, Subdivide[0., 1., 101]}]; 
  pts3 = MapThread[{#1[[1]], #1[[2]] + #2[[2]]} &, {pts1, pts2}]; 
  ListLinePlot[{pts1, pts2, pts3}]]

result

Since I am running on a six year old iMac, I don't think the slightly faster time is due to better processor speed.

$\endgroup$
1
  • $\begingroup$ I get about 10% increase if calculate pts3 = Transpose@{pts1[[All, 1]], pts1[[All, 2]] + pts2[[All, 2]]}; $\endgroup$
    – BlacKow
    Commented May 10, 2016 at 22:42

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.