I'm new to Mathematica (although I have substantial experience programming). I am trying to run the following code but I am getting mixed resutls:

cylDescr := x^2 + z^2  - 1;
ContourPlot3D[cylDescr == 0, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}];
coneDescr := x^2 + y^2 - ((z - 1)/b)^2;
ContourPlot3D[coneDescr == 0 /. b -> 1, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}];

The first contour plot works, but second doesn't, and the values value of x is 1.0.

I'm a little baffled by this. I assume that Mathematica assignments are acting differently than typical programming languages and even other symbolic languages (ie maple). But I can't make heads or tails of what is going on here.

Could I get a little help? Thanks in advance.



coneDescr := x^2 + y^2 - ((z - 1)/b)^2;
  Evaluate[coneDescr == 0 /. b -> 1], {x, -1, 1}, {y, -1, 1}, {z, -1, 1}]


ContourPlot3D like most (maybe all) plot functions has the attribute HoldAll, which means its arguments are not evaluated before the function is called (it doesn't use what is called standard evaluation). Instead it evaluates the arguments when it wants to in the function body. For most calls this works well, as in your cylinder case. But for your cone case, it messes up the substitution of 1. for b.

Look up Attributes and HoldAll in the docs for more detail.


Let me attempt an explanation that goes beyond blaming the HoldAll attribute.

Consider this:

coneDescr := x^2 + y^2 - ((z - 1)/b)^2;
ContourPlot3D[(coneDescr /. b -> 1) == 0, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}]


Clearly, this works even though I didn't use Evaluate, and we shouldn't be too surprised because obviously a plot function has to evaluate the first argument eventually (otherwise there'd be nothing to plot). The HoldAll attribute appears in all those Plot and Plot3D related functions where we need to vary one or more local variables in some interval. The purpose of this attribute is to make sure that all those local variables can be properly localized even if variables by the same name have already been assigned values globally.

Effectively, ContourPlot3D in this example temporarily clears x, y and z, as is also done in Block. Then we can sweep out the required intervals and evaluate the first argument as we go.

The first argument has to be held unevaluated, too, so that the local variables contained in it don't get replaced by any potentially existing global values. For a regular Plot, this Hold can be Released once the blocking of local variables has been arranged.

But for ContourPlot3D, there is a complication because it first has to be decided if we're plotting an implicit equation defined with Equal, or just a function of the independent variables that evaluates to a real number, for which the Contours option will then be used. These are different uses of the ContourPlot3D, distinguished by the Head of the first argument in its held form. But the head is not the desired Equal in your original input, as you can see in the FullForm:

ContourPlot3D[coneDescr == 0 /. b -> 1, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}]

ContourPlot3D[ReplaceAll[Equal[coneDescr,0],Rule[b,1]],List[x,-1,1], List[y,-1,1],List[z,-1,1]]

Instead, the first argument has the head ReplaceAll (which is the FullForm of the /. operator). This isn't recognized as an implicit equation, but likewise it's not recognized as a function that evaluates to a real number, and that's why the entire ContourPlot3D expression is returned unevaluated. This behavior is different from the empty plot that gets returned if the first argument isn't a real number (e.g.). Remaining unevaluated here comes from the fact that the argument, when wrapped in a ReplaceAll, doesn't fit either of the two distinct allowed argument types.

In my plot code at the beginning, what I do is simply move this ReplaceAll inside the Equal, so that the ContourPlot3D can find the Equal symbol when it's deciding what type of plot to make.

  • $\begingroup$ Thank you for this very thorough explanation. Now I understand exactly what is happening. Nonetheless, this seems like a bug more than a behavior. There is nothing in the documentation that specifies that the head of the plotted expression must be an equality. It seems like mathematica needs to add an Evaluate[] call prior to checking for that equality operator, similar to what m_goldberg suggested. That would have no effect in most cases, and would fix this issue. Anyway, thanks so much for your help, I would have never figured that out. $\endgroup$ – James S Sep 26 '15 at 21:16
  • $\begingroup$ It's true, one could make these plot functions smarter in the way of recognizing what is meant to be plotted. I've complained about this before, too: e.g., when using Plot with a Table of functions to get several curves at once, the curves all have the same color - whereas they get colored individually if one wraps the Table in Evaluate. This isn't obvious to most new users, and it could be improved. $\endgroup$ – Jens Sep 26 '15 at 21:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.