# How can I use legend in ContourPlot3D and add arrowheads for axis?

I am using ContourPlot3D to show two surfaces. This is my code. Now I want to use Legend to distinguish the two surfaces, and add arrowhead for the three axis.

sf1[x_, y_, z_] := x  (1/(1 + 0.06))^3 + y (1/(1 + 0.06))^2 - z/3;
sf2[x_, y_, z_] := x  (1 + 5 0.06) (1/((1 + 5 0.06) + 0.06))^3 + y (1 + 5 0.06) (1/((1 + 5 0.06) + 0.06))^2 - z/3;
ContourPlot3D[{sf1[x, y, z] == 0, sf2[x, y, z] == 0}, {x, 0, 150}, {y, 0, 100}, {z, 0, 200}, Ticks -> None, AxesLabel -> {"x", "y", "z"}, BoundaryStyle -> Red, Boxed -> False, AxesOrigin -> {0, 0, 0}]


I have try PlotLegends, and AxesStyle in the following code. As you can see, the using of PlotLegends does not distinguish them very well. And the AxesStyle can not add anything for the axis. I recognized the "axis" I mentioned is actually frame in ContourPlot3D, but how can I use axis rather than frame in ContourPlot3D? Thanks in advance!

ContourPlot3D[{sf1[x, y, z] == 0, sf2[x, y, z] == 0}, {x, 0, 150}, {y, 0, 100}, {z, 0, 200}, Ticks -> None, AxesLabel -> {"x", "y", "z"}, BoundaryStyle -> Red, Boxed -> False, AxesOrigin -> {0, 0, 0}, PlotLegends -> {"b=0", "b=5"}, AxesStyle -> Arrowheads[{0.0, 0.03}] ]

• for arrowheads on axes see: traditional axes in 3d mathematica plots
– kglr
Nov 6, 2014 at 8:51
• What don't you like about the legend, exactly? I see the shadows as being a major issue, in that from some angles the contour surfaces are too dark and don't resemble the swaths from the legend. One way to fix this is to add Lighting -> {{"Ambient", White}} to the ContourPlot3D function. Nov 6, 2014 at 9:56

Try this:

    sf1[x_, y_, z_] := x (1/(1 + 0.06))^3 + y (1/(1 + 0.06))^2 - z/3;
sf2[x_, y_, z_] :=
x (1 + 5 0.06) (1/((1 + 5 0.06) + 0.06))^3 +
y (1 + 5 0.06) (1/((1 + 5 0.06) + 0.06))^2 - z/3;

Show[{
ContourPlot3D[{sf1[x, y, z] == 0, sf2[x, y, z] == 0}, {x, 0,
150}, {y, 0, 100}, {z, 0, 200}, Ticks -> None,
BoundaryStyle -> Red, Boxed -> False, AxesOrigin -> {0, 0, 0}],
Arrow[{{0, 0, 0}, {153, 0, 0}}], Arrow[{{0, 0, 0}, {0, 0, 203}}],
Arrow[{{0, 0, 0}, {0, 102, 0}}]}],
Graphics3D[{Text[
Style["x", 18, Italic, Bold,
FontFamily -> "Times New Roman"], {149, 0, 16}],
Text[Style["y", 18, Italic, Bold,
FontFamily -> "Times New Roman"], {0, 96, 22}],
Text[Style["z", 18, Italic, Bold,
FontFamily -> "Times New Roman"], {0, 0, 215}]}]
}]


It should give this:

With another ViewPoint though. I turned a bit to make the y axis visible.

Have fun!

Edit: to address your question. I also did not succeed to use the Epilog->Insetstructure for this purpose. However, you may simply draw the necessary objects "by hand" the same way as the axes and labels were drawn. Try this:

  Show[{ContourPlot3D[{sf1[x, y, z] == 0, sf2[x, y, z] == 0}, {x, 0,
150}, {y, 0, 100}, {z, 0, 200}, Ticks -> None,
BoundaryStyle -> Red, Boxed -> False, AxesOrigin -> {0, 0, 0},
ViewPoint -> {1.54, -2.77, 1.19}],
Arrow[{{0, 0, 0}, {153, 0, 0}}], Arrow[{{0, 0, 0}, {0, 0, 203}}],
Arrow[{{0, 0, 0}, {0, 102, 0}}]}],
Graphics3D[{Text[
Style["x", 18, Italic, Bold,
FontFamily -> "Times New Roman"], {149, 0, 16}],
Text[Style["y", 18, Italic, Bold,
FontFamily -> "Times New Roman"], {0, 96, 22}],
Text[Style["z", 18, Italic, Bold,
FontFamily -> "Times New Roman"], {0, 0, 215}],
Text[Style["b=0", 20, Darker@Brown], {20, 20, 180}],
Text[Style["b=5", 20, Darker@Blue], {83, 47, 128}]
}],
Arrow[{{20, 20, 173}, {25, 25, 129}}],
Arrow[{{83, 47, 132}, {74, 34, 188}}]}]
}]


you should obtain the following:

The advantage is that bot the letters and arrows are 3D objects and you may rotate the image to visualize, say, where the second arrow points to. If the image rotation is not necessary, you may think about playing with the coordinates and placing the text b=5and the corresponding arrow into another position, where the arrow is more visible.

Have fun!

• @ Alexei Boulbitch. Thanks your answer is very helpful! Could you give me some advice on adding some text in the 3D plot to distinguish the two planes? I have tried Epilog -> {Inset["b=0", {10, 50}], Inset["b=5", {50, 50}]}. But it doesn't work in the 3D case. Is there any possible to use Graphics3D or to use different surface mesh to distinguish them? Thanks a lot! Nov 7, 2014 at 3:12
• @ Alexei Boulbitch. Thanks! I have learned the Graphics3D from you :-P Nov 7, 2014 at 10:47

Modifying the function axes in this answer:

axes3D[x_, y_, z_, f_, a_] := With[{min = Min[x, y, z]},
Graphics3D[Join[{Arrowheads[a]}, Arrow[{{0, 0, 0}, #}] & /@ {{x, 0, 0}, {0, y, 0}, {0, 0, z}},
Text[Style[#, FontSize -> Scaled[f]], #2] & @@@
Transpose[{{"x", "y", "z"}, {{x/2, 0, 0}, {0, y/2, 0}, {0, 0, z/2}} /. (0) -> (-.05 min)}]],
Boxed -> False]]

cp = ContourPlot3D[{sf1[x, y, z] == 0, sf2[x, y, z] == 0}, {x, 0, 150}, {y, 0, 100}, {z, 0, 200},
BoundaryStyle -> Red, ContourStyle -> {Directive[Opacity[.8], Yellow],
Directive[Opacity[.8], Green]}, Mesh -> None,
PlotLegends -> SwatchLegend[{Yellow, Green}, {"b=0", "b=5"}]];

Show[axes3D[##&@@(Last/@ PlotRange[cp[[1]]]), .05, .03], cp, BoxRatios -> 1, Lighting -> "Neutral"]


• @ kguler, Thanks for your help! I tried Epilog -> {Inset["b=0", {10, 50}], Inset["b=5", {50, 50}]}. But it doesn't work in the 3D framework. Is there any other method to use Graphics3D or to use different surface mesh to distinguish them? Because I need black-white picture in a report, I prefer to use the text and graphs, i.e. different mesh, to distinguish them. Thanks in advance!! Nov 7, 2014 at 3:20