# Defining a pure function involving a function argument

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.

• How about , MeshFunctions -> mesh and myplot[Function[{x, y, z}, mymesh]]. – Apple Jun 25 '14 at 16:39

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]


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]


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]


• 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. – Bryan Clair Jun 27 '14 at 2:25
• @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. – Mr.Wizard Jun 27 '14 at 2:36
mymesh[x_, y_] := x*y

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

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


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]


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 :)

• 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. – Bryan Clair Jun 25 '14 at 18:12

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].

 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]

• 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. – Bryan Clair Jun 25 '14 at 18:06
• Beautiful. I had a feeling there was something magical along the lines of :> that would help. – Bryan Clair Jun 25 '14 at 21:06
mymesh = x$+ y$;
myplot[mesh_] :=
Plot3D[x^2 + y^2, {x, -1, 1}, {y, -1, 1},
MeshFunctions -> {Function[{x, y, z}, mesh]}]
myplot[mymesh]


• I strongly advise against this kind of code. You use the specific knowledge about certain implementation details, which makes this error-prone. – Leonid Shifrin Jun 25 '14 at 17:40
• @Leonid Shifrin thanks for the advice. do you think there will be error for this particular problem? – Algohi Jun 25 '14 at 17:49
• 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. – Leonid Shifrin Jun 25 '14 at 20:21