5

I have this code to produce an interactive visualization of a tangent plane to a function:

Clear[f]
f[x_, y_] := x^3 + 2*y^3
Manipulate[
 Show[
  Plot3D[f[x, y], {x, -1, 1}, {y, -1, 1}, PlotStyle -> Opacity[0.8]],
  Plot3D[f[point[[1]], point[[2]]] +
    Limit[(f[point[[1]] + h, point[[2]]] - f[point[[1]], point[[2]]])/
       h, h -> 0]*(x - point[[1]]) +
    Limit[(f[point[[1]], point[[2]] + h] - f[point[[1]], point[[2]]])/
       h, h -> 0]*(y - point[[2]]), {x, -1, 1}, {y, -1, 1}, 
   PlotStyle -> Opacity[0.8], MeshStyle -> Gray]],
 {{point, {0, 0}}, {-1, -1}, {1, 1}}, 
 SaveDefinitions -> True]

It is, however, extremely slow. I suspect that the reason is that I unnecessarily compute the partial derivatives over and over again inside the second Plot3D, so my question is: how to change it?

Note: I am using the above code also for other functions as discussed here, and that is the reason for the Limit in computation of partial derivatives.

mbork
  • 949
  • 9
  • 16

2 Answers2

5

Simply move the derivative computation outside the scope of the Manipulate, using either D or Limit.

f[x_, y_] = x^3 + 2 y^3;
fx[x_, y_] = D[f[x, y], x];
fx[x_, y_] = Limit[(f[x + h, y] - f[x, y])/h, h -> 0];
fy[x_, y_] = D[f[x, y], y];
fy[x_, y_] = Limit[(f[x, y + h] - f[x, y])/h, h -> 0]
Manipulate[
 x0 = p[[1]]; y0 = p[[2]];
 Show[{
   Plot3D[{f[x, y], 
     f[x0, y0] + fx[x0, y0] (x - x0) + fy[x0, y0] (y - y0)},
    {x, -2, 2}, {y, -2, 2}, BoxRatios -> {1, 1, 1}, 
    PlotRange -> {{-2, 2}, {-2, 2}, {-25, 25}},
    PlotStyle -> {Directive[Opacity[0.6]], 
      Directive[Orange, Opacity[0.6]]},
    ViewPoint -> {2.5, -2, 1}, ClippingStyle -> None],
   Graphics3D[{PointSize[Large], 
     Point[{p[[1]], p[[2]], f[p[[1]], p[[2]]]}]}]
   }],
 {{p, {1, 1}}, {-1, -1}, {2, 2}}]
Mark McClure
  • 32,469
  • 3
  • 103
  • 161
  • Interesting. Why do you provide two rules for fx[x_,y_]? – mbork Sep 29 '12 at 19:36
  • 1
    @mbork Either definition works, although the second clearly overwrites the first. I was simply trying to emphasize the fact that you can use either the built in D operator or the Limit definition, as you indicated that you might need to. – Mark McClure Sep 29 '12 at 19:40
  • 1
    OK, thanks. For the moment I thought that somehow the Limit one is chosen if the D doesn't work (e.g., when the function is given by a separate rule for one point). And thanks for the nicety - the large point! (I did it using a one-element list in ListPointPlot3D, definitely less elegant.) – mbork Sep 29 '12 at 19:42
  • @mbork you could also show the Points using Epilog – Simon Sep 30 '12 at 02:07
  • 1
    @Simon Epilog is really for 2D graphics. From the documentation: "In three-dimensional graphics, two-dimensional graphics primitives can be specified by the Epilog option. The graphics primitives are rendered in a 0,1 coordinate system." - Hence, the Show[{Plot3D[__], Graphics3D[__]}] construct. – Mark McClure Sep 30 '12 at 02:38
  • @Mark Oops, my bad! I wasn't paying enough attention. – Simon Sep 30 '12 at 02:50
  • @Simon I've fallen for that one myself! – Mark McClure Sep 30 '12 at 02:56
4

The limits can be calculated analytically one time and then used inside your Manipulate. You can use With to place the final expression where you need them:

f[x_, y_] := x^3 + 2*y^3;
With[{l1 = Limit[(f[px + h, py] - f[px, py])/h, h -> 0], 
  l2 = Limit[(f[px, py + h] - f[px, py])/h, h -> 0]},
 Manipulate[
  {px, py} = point;
  Show[Plot3D[f[x, y], {x, -1, 1}, {y, -1, 1}, 
    PlotStyle -> Opacity[0.8]], 
   Plot3D[f[point[[1]], point[[2]]] + l1*(x - point[[1]]) + 
     l2*(y - point[[2]]), {x, -1, 1}, {y, -1, 1}, 
    PlotStyle -> Opacity[0.8], 
    MeshStyle -> Gray]], {{point, {0, 0}}, {-1, -1}, {1, 1}}, 
  SaveDefinitions -> True]
 ]
halirutan
  • 112,764
  • 7
  • 263
  • 474
  • Thanks! I just discovered With myself, too, but I've put it inside Show; I guess this doesn't make much difference. – mbork Sep 29 '12 at 19:36