4
$\begingroup$

I've got an expression involving x and y that I want to use as a MeshFunction:

mymesh = x + y
Plot3D[x^2 + y^2, {x, -1, 1}, {y, -1, 1}, MeshFunctions -> {Function[{x, y, z}, mymesh]}]

This works just fine. But now I want to create a plotting function that takes the mesh function as an argument, like so:

myplot[mesh_] := Plot3D[x^2 + y^2, {x, -1, 1}, {y, -1, 1},
                        MeshFunctions -> {Function[{x, y, z}, mesh]}]
myplot[mymesh]

This produces the following error:

MeshFunctions::invmeshf:
  "MeshFunctions->Function[{x$,y$,z$},x+y] must be a pure function or a list of pure functions"

It seems like it's making local variables x$, y$, z$ and then keeping them distinct from the x,y in mymesh.

Any suggestions how to make this work? I'd like to keep mymesh in the symbolic form, because the plot I'm actually interested in doing is much more complicated, and uses the mymesh function a second time as part of the function to plot.

I'm going to add some more to this question, because I have a few answers, all of which suggested not passing mymesh in it's current form to the function. But I explicitly want to pass mymesh as it is.

Here's the actual code I'm using it for. It plots the solutions to c==0 on the unit sphere, where c is a homogeneous polynomial in x,y,z.

elliptic = z y^2 - x^3 + z^2 x
curveSpherePlot[c_] := ContourPlot3D[
  {x^2 + y^2 + z^2 == 1, c == 0},
  {x, -1, 1}, {y, -1, 1}, {z, -1, 1},
  MeshFunctions -> {Function[{x, y, z}, x^2 + y^2 + z^2 - 1 - c]},
  MeshStyle -> {{Thick, Black}},
  Mesh -> {{0}},
  ContourStyle -> {Opacity[0.9], None},
  BoundaryStyle -> None
]
curveSpherePlot[elliptic]

Notice that the argument c appears in the equation as well as in the mesh function. Not only that, but I manipulate the curve symbolically with other functions in the package, so I really don't want to switch it to a different type of object if I can help it.

$\endgroup$
1
  • $\begingroup$ How about , MeshFunctions -> mesh and myplot[Function[{x, y, z}, mymesh]]. $\endgroup$
    – Apple
    Jun 25, 2014 at 16:39

4 Answers 4

1
$\begingroup$

The failure you observe is caused by automatic renaming within nested scoping constructs:

You can use any of the methods described therein to correct the problem. For the first example using the form MeshFunctions -> Function @@ {{x, y}, mymesh} will work. For the second you could use MeshFunctions -> Function @@ {{x, y, z}, x^2 + y^2 + z^2 - 1 - c}:

curveSpherePlot[c_] :=
 ContourPlot3D[{x^2 + y^2 + z^2 == 1, c == 0}, {x, -1, 1}, {y, -1, 1}, {z, -1, 1},
  MeshFunctions -> Function @@ {{x, y, z}, x^2 + y^2 + z^2 - 1 - c},
  MeshStyle -> {{Thick, Black}}, Mesh -> {{0}},
  ContourStyle -> {Opacity[0.9], None},
  BoundaryStyle -> None
 ]

curveSpherePlot[elliptic]

enter image description here

These do not protect against e.g. x or y having a global value assigned and breaking the operation, but then neither does your basic construct. We can manually Block those Symbols and hold elliptic using SetDelayed to prevent unwanted evaluation:

x = y = z = "Fail!";

elliptic := z y^2 - x^3 + z^2 x

SetAttributes[curveSpherePlot, HoldFirst]

curveSpherePlot[c_] := Block[{x, y, z},
  ContourPlot3D[{x^2 + y^2 + z^2 == 1, c == 0}, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}, 
   MeshFunctions -> Function @@ {{x, y, z}, x^2 + y^2 + z^2 - 1 - c}, 
   MeshStyle -> {{Thick, Black}}, Mesh -> {{0}},
   ContourStyle -> {Opacity[0.9], None}, 
   BoundaryStyle -> None]
  ]

curveSpherePlot[elliptic]

enter image description here

There is a variation leveraging the internal evaluation behavior of plotting functions that allows us to eliminate Block. It relies on the fact that elliptic will not be evaluated until after x, y, and z are localized by ContourPlot3D, and the time at which the function is evaluated. This may be viewed as a hack as it relies on undisclosed internal behavior that may change between versions.

x = y = z = "Fail!";

elliptic := z y^2 - x^3 + z^2 x

SetAttributes[curveSpherePlot, HoldFirst]

curveSpherePlot[c_] := 
 ContourPlot3D[{x^2 + y^2 + z^2 == 1, c == 0}, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}, 
  MeshFunctions -> Function @@ Hold[{x, y, z}, x^2 + y^2 + z^2 - 1 - c], 
  MeshStyle -> {{Thick, Black}}, Mesh -> {{0}},
  ContourStyle -> {Opacity[0.9], None}, 
  BoundaryStyle -> None
 ]

curveSpherePlot[elliptic]

enter image description here

$\endgroup$
2
  • $\begingroup$ This answer is very satisfying, and explains the issue deeply. I switched my official 'answer' tag to this one even though Wouter's answer did solve the problem. I hope that's accepted etiquette. $\endgroup$ Jun 27, 2014 at 2:25
  • $\begingroup$ @Bryan I am glad this answer is satisfying, and thank you for the Accept. Yes, it is normal practice to change the Accept as you see fit. Some people choose the first answer that works, some choose the one they end up using, some choose the one they feel is most correct, and some I frankly have no idea. :^) While I will sometimes advocate the Accept for a specific answer (mine or not) one should never fear anger or retribution for Accepting whatever answer pleases most. $\endgroup$
    – Mr.Wizard
    Jun 27, 2014 at 2:36
4
$\begingroup$
mymesh[x_, y_] := x*y

myplot[mesh_] := Plot3D[x^2 + y^2, {x, -1, 1}, {y, -1, 1}, MeshFunctions -> mesh]

myplot[mymesh[#1, #2] &]

enter image description here

ADDENDUM

f1 = x^2 + y^2 + z^2 - 1;

f2 = z y^2 - x^3 + z^2 x;

curveSpherePlot[c_] := ContourPlot3D[
  x^2 + y^2 + z^2 == 1.0001, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}, 
  MeshFunctions -> c, PlotPoints -> 50]

curveSpherePlot@Function[{x, y, z}, f1 - f2]

enter image description here

The problem is that I haven't found a way to combine two pure functions in the way you suggested:

Function[{x, y, z}, x^2 + y^2 + z^2 - 1 - c]

So let's hope a better solution comes forth :)

$\endgroup$
1
  • $\begingroup$ Thanks for the suggestion. This would work, but essentially changes the question by redefining mymesh. I've posted a less simplified example to make the challenge a bit more clear. $\endgroup$ Jun 25, 2014 at 18:12
3
$\begingroup$

Your original was ok, apart from the incorporation of the Function[{x,y,z}, body]inside the Plot function. You should pass it as an argument instead:

mymesh=Function[{x,y,z},x y];
myplot[mesh_]:=Plot3D[x^2+y^2,{x,-1,1},{y,-1,1},MeshFunctions->mesh];

and then myplot[{mymesh}] or even myplot[mymesh].

Taking into account your ammendment:

 elliptic=z y^2-x^3+z^2 x;
curveSpherePlot[c_]:=Block[{temp=x^2+y^2+z^2-1-c},ContourPlot3D[{x^2+y^2+z^2==1,c==0},{x,-1,1},{y,-1,1},{z,-1,1},MeshFunctions:>{Function[{x,y,z},temp]},MeshStyle->{{Thick,Black}},Mesh->{{0}},ContourStyle->{Opacity[0.9],None},BoundaryStyle->None]];
curveSpherePlot[elliptic]
$\endgroup$
2
  • $\begingroup$ This would work, but for external reasons I can't change the definition of mymesh. I've posted a less simplified example to make the challenge a bit more clear. $\endgroup$ Jun 25, 2014 at 18:06
  • $\begingroup$ Beautiful. I had a feeling there was something magical along the lines of :> that would help. $\endgroup$ Jun 25, 2014 at 21:06
0
$\begingroup$
mymesh = x$ + y$;
myplot[mesh_] := 
 Plot3D[x^2 + y^2, {x, -1, 1}, {y, -1, 1}, 
  MeshFunctions -> {Function[{x, y, z}, mesh]}]
myplot[mymesh]

enter image description here

$\endgroup$
3
  • 1
    $\begingroup$ I strongly advise against this kind of code. You use the specific knowledge about certain implementation details, which makes this error-prone. $\endgroup$ Jun 25, 2014 at 17:40
  • $\begingroup$ @Leonid Shifrin thanks for the advice. do you think there will be error for this particular problem? $\endgroup$ Jun 25, 2014 at 17:49
  • $\begingroup$ I don't know. Perhaps one can come up with some example, where the renaming will work differently. But I am opposed to this approach in principle. It's just not a robust code. If the renaming mechanism is, for example, changed in later versions, even slightly, this will stop working. $\endgroup$ Jun 25, 2014 at 20:21

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.