# Passing a function into another function defined with Module and using it there

I'm trying to write a generic module that will take a vector-valued function of a space curve and show the animation of a unit tangent vector traversing the curve. I found a really nice example from Artes in an answer to another question. His answer isn't generic, so I tried to generalize it in the form of a module:

UnitTangentParametricPlot3D[vfunction_, intvl_] :=
Module[{p, v, vu},
p[t_] := vfunction;
v[h_] := D[p[t],t];
vu[g_] := Simplify[v[h]/Norm[v[h]]];
Animate[
Show[
ParametricPlot3D[{p[t]}, intvl, Mesh -> Full],
Graphics3D[
Thick, Darker @ Red, Arrow[{p[s], p[s] + vu[s]}]],
PlotRange -> Full,
ViewPoint -> {4, 8, 0},
ImageSize -> 600],
{s, -1, 1}]]


I'm having trouble working with generic functions in the following ways:

• Take a function as module argument a, find its derivative and evaluate it through the animated value s.
• Animate an arrow graphics object

Sorry for missing anything obvious, I'm new to Mathematica.

Updated working code thanks to Henrick's suggestions :

    SetAttributes[UnitAnimateParametricPlot3D, HoldAll];
UnitAnimateParametricPlot3D[vfunction_, {x_, a_, b_}, scale_, size_] := Module[{p, v, uT},
Block[{t,k},
p[t_] := Evaluate[vfunction /. {x -> t}];
v[k_] := D[p[t],t]/.{x -> k};
uT[t_]:= Simplify[v[t]/Norm[v[t]]];
];
Animate[
Show[
ParametricPlot3D[ {p[t]}, {x, a, b}, PlotRange -> Automatic, AspectRatio-> 1, Mesh -> Full, ImageSize->size],
Graphics3D[
{Thick, Darker @ Red, Arrow[{p[s], (p[s] + scale*uT[s])}]}],
ViewPoint -> Front,
PerformanceGoal -> "Quality",
ImageSize -> size],
{s,a,b}, AnimationRunning->True, AnimationDirection->ForwardBackward, AnimationRepetitions->3]
]


The new scale_ parameter allows for the user to scale the arrow so they can see it traverse the curve.

The new plot-range now only takes the plot-range of the curve, instead of include the animated vector's range.

Try this:

SetAttributes[UnitTangentParametricPlot3D, HoldAll];
UnitTangentParametricPlot3D[vfunction_, {x_, a_, b_}] :=
Module[{p, v, vu, background,plora},
Block[{t},
p[t_] := Evaluate[vfunction /. {x -> t}];
v[t_] := Evaluate[D[p[t], t]];
vu[t_] := Evaluate[Simplify[Normalize[v[t]]]];
];
background = ParametricPlot3D[{p[t]}, {t, a, b}];
plora = (PlotRange /. AbsoluteOptions[background]) + {{-1., 1.}, {-1., 1.}, {-1., 1.}};
Manipulate[
Show[{
background,
Graphics3D[{Thick, Darker@Red, Arrow[{p[s], p[s] + vu[s]}]}]
},
PlotRange -> plora,
ViewPoint -> {4, 8, 0},
ImageSize -> 600
],
{s, a, b}
]
]


For the future remember that Graphics with multiple objects and directives requires a pair of braces {}. Moreover, the arguments in the definitions for p, v and vu did not match the symbol of the argument on the right hand side. In fact, this symbol has to be extracted from the arguments of UnitTangentParametricPlot3D.

The reason to give UnitTangentParametricPlot3D the attribute HoldAll was to make the following work:

t = 4;
UnitTangentParametricPlot3D[{Cos[t], Sin[t], 0.1 t}, {t, 0, 4 Pi}]


The problem is that the symbol t has already a value assigned when we call UnitTangentParametricPlot3D; HoldAll prevents evaluation. Afterwards, we use vfunction /. {x -> t} in the body of UnitTangentParametricPlot3D in order have a controlable variable name.

• Excellent, thank you! I realize now that I didn't read the parameters specifications for Arrow or Graphics3D carefully; thanks for pointing that out. Also, I think I better understand handling variables in modules. Mar 1 '18 at 22:57
• You're welcome! Mar 1 '18 at 22:59
• Do you have an idea on how to make it so the plot range in Show[] is unaffected by my vector graphics3D? I've been looking through the PlotRange[] api for a while now. Actually, I just got it! (See updates). Mar 1 '18 at 23:21
• Have a look at the last edit. I extracted the PlotRange of background and widened it by 1. Mar 1 '18 at 23:28