I am confused by Dynamic. I am trying to slide a tangent line along a curve, without using DynamicModule, so that I can include it in a cdf. I have the sliding point working in the below, but the tangent line is static. How do I get the line moving as well?

 plot1 = Plot[Sin[x], {x, 0, 10},
   Epilog -> {
     Point[Dynamic[{First[pt], Sin[First[pt]]}]]
 TangentAngle = Cos[First[pt]];
 x1 = First[pt] - 0.5*Cos[TangentAngle];
 y1 = pt[[2]] - 0.5*Sin[TangentAngle];
 x2 = First[pt] + Cos[TangentAngle];
 y2 = pt[[2]] + Sin[TangentAngle];

 plot2 = Graphics[Line[{Dynamic[{x1, y1}], Dynamic[{x2, y2}]}]];
 Show[{plot1, plot2}], Appearance -> None

5 Answers 5

LocatorPane[Dynamic[pt, (pt = {#[[1]], Sin[#[[1]]]}) &],
ConditionalExpression[Cos[pt[[1]]]*(x - pt[[1]]) + Sin[pt[[1]]],
 pt[[1]] - 1 <= x <= pt[[1]] + 1]}, {x, 0, 10},
PlotRange -> {{-2, 11}, {-2, 2}},
Epilog -> {PointSize[Large], Point[pt]}],
Appearance -> None]

enter image description here

For arbitrary function func, replace Cos with Derivative[1][func] in the first argument of ConditionalExpression.

Instead of Epilog -> {PointSize[Large], Point[pt]}], one can also use

Mesh -> {{pt[[1]]}}, MeshStyle -> PointSize[Large]]

Update: Using Locator as a graphics primitive, one can get the same result without having to use LocatorPane:

ConditionalExpression[Cos[pt[[1]]]*(x - pt[[1]]) + Sin[pt[[1]]],
pt[[1]] - 1 <= x <= pt[[1]] + 1]}, {x, 0, 10},
PlotRange -> {{-2, 11}, {-2, 2}},
Epilog ->  Dynamic@{Locator[Dynamic[pt, (pt = {#[[1]], Sin[#[[1]]]}) &],
  Graphics[{Black, PointSize[Large], Point[pt]}]]}]
  • $\begingroup$ very elegant. Thanks. $\endgroup$
    – jamie
    Commented Jan 20, 2013 at 13:17
  • $\begingroup$ Thanks for the suggestion of Derivative as well as your other suggestions. The last option using Dynamic@Plot works in a notebook but unfortunately does not work in a CDF. $\endgroup$
    – jamie
    Commented Jan 20, 2013 at 14:07
  • $\begingroup$ You need to use the piece Dynamic@Plot.. as the first argument in Manipulate[..., {dummycontrol, None}] for it to work in a CDF. Thank you for the accept. And welcome to MathematicaSE. $\endgroup$
    – kglr
    Commented Jan 20, 2013 at 14:50

Even if this is already answered... here a short, straightforward, "solution", which might be instructive to people, not so deeply concerned with all that "Dynamic" stuff ;-)

f[x_] := Sin[x]

tangent[f_, x0_, x_] := f'[x0] (x - x0) + f[x0]

   Manipulate[Plot[{f[x], tangent[f, p, x]}, {x, 0, 2 π},PlotRange -> {{0, 2 π}, {-3, 3}},
Epilog -> {Red, PointSize[.015], Point@{p, Sin[p]}}], {p, 0,  2 π}]


(edit by J. M.)

This is a variation of mgamer's proposal; I did not feel it deserved its own answer, but it was too long for a comment. This one eliminates the slider, and uses a Locator instead, so that one can slide the tangent line along the curve:

Manipulate[Plot[f[x], {x, 0, 2 π}, PlotRange -> {{0, 2 π}, {-3, 3}}, 
                Epilog -> {{Directive[ColorData[97, 2], AbsoluteThickness[1]], 
                            InfiniteLine[{p[[1]], f[p[[1]]]}, {1, f'[p[[1]]]}]},
                           {Directive[Red, AbsolutePointSize[6]], 
                            Point[{p[[1]], f[p[[1]]]}]}}],
           {{p, {0, 0}}, Locator, Appearance -> None},
           Initialization :> (f[x_] := Sin[x])]

The only way I could make your code work was to introduce a helper function. I have no experience with CDFs, but I would hope they allow such functions.

tangent[pt_] := Module[{tanAngle, xy1, xy2},
  tanAngle = ArcTan@Cos[pt[[1]]];
  xy1 = pt - 0.5 {Cos[tanAngle], Sin[tanAngle]};
  xy2 = pt + 0.5 {Cos[tanAngle], Sin[tanAngle]};
  Graphics[{Line[{xy1, xy2}]}]]

  Dynamic[pt, (pt = With[{ptx = #[[1]]}, {ptx, Sin@ptx}]) &], 
  plot = Plot[Sin[x], {x, 0, 10}, 
    Epilog -> {PointSize[Large], Dynamic@Point[pt]}];
  Dynamic@Show[{plot, tangent[pt]}], Appearance -> None]

tangent demo

Note the introduction of ArcTan in the calculation of the tangent angle and the use of the second argument of Dynamic in the locator pane.

Note: the second argument of Dynamic provides a way to constrain the movement of the locator. I use it to confine the locator to the curve.


I first thought to make this a comment, but I wanted to give an example for the OP to test: DynamicModule is supported by CDF Player, or at least the code below works on both the v8 and v9 CDF Player. (It's a little more elaborate than what the OP proposed, but I wanted to test a few things and decided to leave them in.)

DynamicModule[{a = 1.5, f = Sin, tangetLine, x1 = 0, x2 = 10}, 
 tangetLine[x_, a0_] := f[a0] + f'[a0] (x - a0);
   Dynamic[{a, f[a]}, (a = Clip[#[[1]], {x1, x2}]) &],
   Dynamic@Plot[f[x], {x, x1, x2}, PlotRange -> 1, PlotRangePadding -> {1, 0.2},
     Epilog -> {Line[{#, tangetLine[#, a]} & /@
                 {a - 1/Sqrt[1 + f'[a]^2], a + 1/Sqrt[1 + f'[a]^2]}]}, 
     AspectRatio -> Automatic],
   Appearance -> Graphics[{PointSize[Large], Point[{0, 0}]}]],
   Dynamic[f], # -> TraditionalForm[#[x]] & /@
    {Sin, Cos, # ((#/π)^2 - 1) (#/(2 π) - 1) (#/(3 π) - 1) (#/(4 π) - 1) &},
   Alignment -> Center],



  1. A tangent line one unit long in each direction seems to be desired. But if the scales on the axes aren't the same, then the tangent line will appear to change length. So I include AspectRatio -> Automatic just in case. (Cos[ArcTan[f'[a]]] simplifies to 1/Sqrt[1+f'[a]^2].)

  2. I clipped the Locator position to the domain {x1, x2} to constrain it to the domain passed to Plot.

  3. The option Alignment turns red in SetterBar, but it seems to get passed to the component Setters without generating errors. (To get rid of the SetterBar, copy the LocatorPane[..] code and paste it over the Labeled[..] code

  4. There is also this Demonstration that moves tangents, as well as secants, whose code could be adapted. CDFs support Manipulate, too.


@m_goldberg: thanks for spotting the 'ArcTan'. Sine was not the best function to do this on. Unfortunately, i did not get your solution to work in a CDF.

However, with your suggestion and reading through the link from @Artes, my messy code has morphed into something that works:

 plot1 = Plot[Sin[x], {x, 0, 10}, PlotRange -> {{-2, 11}, {-2, 2}},
  Epilog -> {
 Point[Dynamic[{First[pt], Sin[First[pt]]}]],
    {First[pt] - Cos[ArcTan[Cos[First[pt]]]],
     Sin[First[pt]] - Sin[ArcTan[Cos[First[pt]]]]
    {First[pt] + Cos[ArcTan[Cos[First[pt]]]],
     Sin[First[pt]] + Sin[ArcTan[Cos[First[pt]]]]
 ], Appearance -> None]




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.