3

I'm trying to plot the gradient field of a function in such a way that is possible to change it easily, only editing the function.

Consider the code:

xmin := -2; xmax := -xmin; ymin := -2; ymax := -ymin;
f[x_, y_] := x^2 + y^2
Plot3D[f[x, y], {x, xmin, xmax}, {y, ymin, ymax}]

enter image description here

So, the following code produces a very fancy result:

VectorPlot[{2 x, 2 y}, {x, xmin, xmax}, {y, ymin, ymax}, 
 StreamPoints -> Coarse, StreamColorFunction -> Hue]

enter image description here

Since {D[f[x, y], x], D[f[x, y], y]} produces {2 x, 2 y} I tried to define

Gradf := {D[f[x, y], x], D[f[x, y], y]}

and use

VectorPlot[Gradf, {x, xmin, xmax}, {y, ymin, ymax}, 
 StreamPoints -> Coarse, StreamColorFunction -> Hue]

but I got a lot of errors as

General::ivar: -1.99971 is not a valid variable. >>

General::stop: Further output of General::ivar will be suppressed during this calculation. >>

I really don't understand why it is not working.

Any idea how to solve this so I could only change the definition of f and plot again?

Sigur
  • 693
  • 5
  • 18
  • 1
    Gradf[x_, y_] = {D[f[x, y], x], D[f[x, y], y]} instead of Gradf := .... Then it works perfectly. See here – Öskå May 22 '14 at 23:46
  • It's basically trying to find the Derivative of your function with the x = some value, instead of the Variable x because of the SetDelayed. So it says "-1.9something is not a valid variable" with which it can find the derivative. It's like saying D[x,0]. – Öskå May 22 '14 at 23:48
  • @Öskå, I'm getting Set::write: Tag List in {2 x,2 y}[x_,y_] is Protected. >>. The same with :=. – Sigur May 22 '14 at 23:49
  • Because you have already said "hey, Gradf is going to be {2 x, 2y}". You need to ClearAll@Gradf so Mathematica forgets it. – Öskå May 22 '14 at 23:51
  • @Öskå, perfect. Nice! It works. If you wish, please, post an answer so I can accept it. Thanks. – Sigur May 22 '14 at 23:54
  • 4
    You can answer your own question if you like, enlightened by these comments :) If not, I will do it tomorrow. It's too late here for me to write a properly written answer :) – Öskå May 22 '14 at 23:56
  • @Öskå, OK, I'll wait. The credit is yours. Thanks. – Sigur May 22 '14 at 23:57
  • My pleasure, I'm glad I could help. And it does look fancy indeed ;o) – Öskå May 22 '14 at 23:58
  • 1
    Why not just the following? With[{gradient = Grad[f[x, y], {x, y}]}, VectorPlot[gradient, {x, xmin, xmax}, {y, ymin, ymax}, StreamPoints -> Coarse, StreamColorFunction -> Hue]] – murray May 24 '14 at 15:01

1 Answers1

3

The problem is that by defining Gradf as fun := D[x^2,x] you are saying "Ok, you will find the Derivative of x^2 in terms of x later on." by using SetDelayed (:=).

Thus, when fun appears in your VerctorPlot or more generally Plot, Mathematica sees it as: "Ok, now I'm going to find the Derivative of fun in terms of x, for each x = {0, 10}":

Plot[fun, {x, 0, 10}]

General::ivar: 0.0002042857142857143` is not a valid variable.

meaning that Mathematica, as you commanded, is trying to find the Derivative of x^2 in terms of x with x equal to 0.0002042857142857143 (case n°1 bellow). Which is obviously not possible since x is not a Variable anymore.

A part of the excellent answer from rm-rf here says:

  • If you're plotting a function, whose definition depends on the output of another possibly expensive computation (such as Integrate, DSolve, Sum, etc. and their numerical equivalents) use = or use an Evaluate with :=. Failure to do so will redo the computation for every plot point! This is the #1 reason for "slow plotting".

Then all you have to do is to follow what has been said above: defining your function with Set (=) so it Evaluates the function to x before plotting it (case n°2 bellow), or Evaluate fun inside Plot so it Evaluates the fun to x before plotting (case n°3 bellow). What is internally happening can be seen with Trace:

Trace@With[{fun := D[x^2, x]}, Plot[fun, {x, 0, 10}]]

Mathematica graphics

Trace@With[{fun = D[x^2, x]}, Plot[fun, {x, 0, 10}]]

Mathematica graphics

Trace@With[{fun := D[x^2, x]}, Plot[Evaluate@fun, {x, 0, 10}]]

Mathematica graphics


Now to answer the question on your specific case you have two possibilities:

xmin := -2; xmax := -xmin; ymin := -2; ymax := -ymin;
f[x_, y_] := x^2 + y^2

With[{Gradf = {D[f[x, y], x], D[f[x, y], y]}}, 
  VectorPlot[Gradf, {x, xmin, xmax}, {y, ymin, ymax}, 
  StreamPoints -> Coarse, StreamColorFunction -> Hue]]

(* or *)

With[{Gradf := {D[f[x, y], x], D[f[x, y], y]}}, 
  VectorPlot[Evaluate@Gradf, {x, xmin, xmax}, {y, ymin, ymax}, 
  StreamPoints -> Coarse, StreamColorFunction -> Hue]]

Mathematica graphics

Öskå
  • 8,587
  • 4
  • 30
  • 49
  • Thanks so much. I didn't know about Trace. Very interesting. – Sigur May 23 '14 at 16:45
  • 1
    @Sigur You are welcome :) I hope it helped you to understand what's really happening inside the box :) – Öskå May 23 '14 at 16:57
  • Do you know how to plot the integral curve of the Grad field and also its image on the surface to show the path of highest grow level? – Sigur May 27 '14 at 00:59
  • @Sigur I'm afraid that I don't really understand what you intend to do.. :) Assuming that the "surface" is the Plot3D, what would you exactly like to do? – Öskå May 27 '14 at 11:00
  • Ow, sorry. I'd like to plot on the 3d surface the path obtained applying the function to the path on domain corresponding to the Grad directions, that is, perpendicular to level curves. So I could see the path on the surface where the function has the faster growth. For some functions, this is easy (for example, $z=x^2+y^2$). – Sigur May 27 '14 at 23:13
  • @Sigur I'm sorry for the lack of answer, I was not active here.. :) I guess that you could simply ask a new question about it since I don't really understand the issue, I guess that my english is not good enough.. :) – Öskå Jun 03 '14 at 10:02