Reputation: 10607
I'm trying to create three separate graphs, this code will give you the idea:
f[t_] := Sin[10 t] + Cos[15 t];
Slider[Dynamic[dx], {0.01, 1}]
var = Dynamic[Fourier[Table[f[t], {t, 0, 100, dx}]]];
ListLinePlot[Abs[var]]
ListLinePlot[Re[var]]
ListLinePlot[Im[var]]
This won't work because var hasn't been evaluated an so ListLinePlot/Abs/Re/Im does not recognize it as a list of numbers. Dynamic has to wrap ListLinePlot.
Wrapping ListLinePlot and everything else with Dynamic works. But then I would have to calculate Fourier[Table[... once for each graph. Per principle, I don't want to have this duplication of code.
This is a way that avoids duplication of code but is not as semantic as my proposed not working example above, plus it puts all series in one graph and not in three separate:
Dynamic[
ListLinePlot[
(#[Fourier[
Table[f[t], {t, 0, 100, dx}]
]]) & /@ {Abs,Re,Min}, DataRange -> {0, 100}
]
]
Hopefully you can see now what I am trying to achieve. Something like my first piece of code except it should work. How can I do that?
Upvotes: 2
Views: 294
Reputation: 25703
In most cases you only need to wrap Dynamic
around the expression that needs to be recomputed. As you noticed, if you wrap Dynamic
around the contents of var
, it will not work because ListPlot
will see a Dynamic
head, not the list, when you pass var
to it. What needs to be recomputed in this case is the complete ListPlot
.
The correct solution is to use a delayed definition for var
(i.e. :=
instead of =
) and wrap Dynamic
around ListPlot
:
f[t_] := Sin[10 t] + Cos[15 t];
Slider[Dynamic[dx], {0.01, 1}]
var := Fourier[Table[f[t], {t, 0, 100, dx}]];
Dynamic@ListLinePlot[Abs[var]]
Dynamic@ListLinePlot[Re[var]]
Dynamic@ListLinePlot[Im[var]]
People often get confused with Dynamic
because it sometimes shows up deep within in expression, e.g. in your Slider
example. But there Dynamic
has a different function: setting a value.
Generally, unless used to set a value, Dynamic
always needs to be the outermost head in an expression. (There are some exceptions, notably when we're handling expressions that directly correspond to what is shown on screen, and are handled by the front end, such as graphics primitives: Slider[Dynamic[x], {0, 5}]
, Graphics[{Disk[], Dynamic@Disk[{x, 0}]}]
will work.)
Dynamic
affects only the way expressions are displayed in the front end, not how the kernel sees them. Here's an example:
x=1
arr = {Dynamic[x], 2, 3}
The Front End will display arr
as {1, 2, 3}
, but the kernel still sees it as {Dynamic[x], 2, 3}
. So if we calculate Total[arr]
, the front end will display it as 1 + 5
but the kernel will see if as Dynamic[x] + 5
. I hope this clarifies the situation a bit.
Note: I did not want to use Manipulate
in this solution because the OP didn't use it either. Manipulate
is just a high level convenience function and everything it does can be achieved with Dynamic
and some controls such as Slider
.
Upvotes: 4
Reputation: 24336
You probably want something like this:
f[t_] := Sin[10 t] + Cos[15 t]
DynamicModule[{var},
Manipulate[
var = Fourier[Table[f[t], {t, 0, 100, dx}]];
{ListLinePlot[Abs[var]],
ListLinePlot[Re[var]],
ListLinePlot[Im[var]]},
{dx, 0.01, 1}
]]
Upvotes: 2
Reputation: 19731
Untested:
f[t_] := Sin[10 t] + Cos[15 t];
Slider[Dynamic[dx], {0.01, 1}]
Dynamic[var = Fourier[Table[f[t], {t, 0, 100, dx}]]];
Dynamic[ListLinePlot[Abs[var]]]
Dynamic[ListLinePlot[Re[var]]]
Dynamic[ListLinePlot[Im[var]]]
I think this should calculate Fourier
just once. From my understanding, the ListLinePlot
s should be triggered by the change of var after evaluating Fourier
(note that the assignment of var
is inside the Dynamic
).
Upvotes: 0