12
$\begingroup$

I'm trying to replicate the plot theme of $\LaTeX$'s pgtplots for 3D surfaces in Mathematica's Plot3D Function. The goal is to create something similar to this:

enter image description here

So I played around with the opacity and different color gradients for a bit until i got this:

 Plot3D[Sin[Sqrt[x^2 + y^2]]/Sqrt[x^2 + y^2], {x, -2 Pi, 2 Pi}, {y, -2 Pi, 2 Pi},
 PlotRange -> {-1, 1},
 BoxRatios -> {1, 1, 1},
 Boxed -> False,
 Axes -> False,
 ColorFunction -> (Opacity[#3 + .1, ColorData[{"DeepSeaColors", "Reverse"}][#3]] &),
 Mesh -> None,
 PlotPoints -> 100
 ]

However, I want the ColorFunction directives to be applied to the mesh rather than the surface. My approach was to simply do something like this:

 Plot3D[Sin[Sqrt[x^2 + y^2]]/Sqrt[x^2 + y^2], {x, -2 Pi, 2 Pi}, {y, -2 Pi, 2 Pi},
 PlotRange -> {-1, 1},
 BoxRatios -> {1, 1, 1},
 Boxed -> False,
 Axes -> False,
 PlotStyle -> Opacity[0],
 MeshStyle -> ColorFunction -> (Opacity[#3 + .1, ColorData[{"DeepSeaColors", "Reverse"}][#3]] &),
 PlotPoints -> 100
 ]

But apparently, this idea is completely wrong. It seems to me that MeshStyle will not accept values that depend on the plotted function. Is there any way to make this work within the Plot3D function? Any help would be greatly appreciated.

$\endgroup$
3
  • $\begingroup$ Yes, there is. Read this question. With[{plot=Plot3D[Sin[Sqrt[x^2 + y^2]]/Sqrt[x^2 + y^2], {x, -2 Pi, 2 Pi}, {y, -2 Pi, 2 Pi}, BoxRatios -> {1, 1, 1}, PlotRange -> {-1, 1}, Boxed -> False, Axes -> False, PlotStyle -> None, PlotPoints -> 100]}, With[{cf = ColorData["RedBlueTones"][#3] &}, plot /. GraphicsComplex[pts_, g_, opts___] :> GraphicsComplex[pts, g /. Line[p_] :> Line[p, VertexColors -> MapThread[cf, Part[Rescale /@ Transpose[pts], All, p]]], opts]]] $\endgroup$
    – Domen
    Commented Dec 20, 2021 at 16:10
  • $\begingroup$ @Domen - your version that keeps the GraphicsComplex intact is much more responsive. I will borrow from it if you don't mind. $\endgroup$
    – Jason B.
    Commented Dec 20, 2021 at 17:33
  • $\begingroup$ @JasonB., not mine, of course, just changed the function in Michael E2's answer :-) $\endgroup$
    – Domen
    Commented Dec 20, 2021 at 17:38

2 Answers 2

14
$\begingroup$

I noticed that for plots like this you get a significantly better performance when rotating the Graphics3D if you keep the answer inside a GraphicsComplex and avoid calling Normal. Borrowing from this comment and this answer, and wrapping it in a function you get

ClearAll @ MeshPlot3D;
Options[MeshPlot3D] = Options @ Plot3D;
SetOptions[MeshPlot3D,
    {
        ColorFunction -> (ColorData[{"DeepSeaColors", "Reverse"}][#3]&),
        Mesh -> Full, PlotPoints -> 50,PlotStyle->None
    }
];
MeshPlot3D[args__, opts:OptionsPattern[]] := Module[{plot},
    plot = With[
        {options = FilterRules[{opts}, Except[ColorFunction | ColorFunctionScaling]]},
        Plot3D[args,
            options, Mesh -> OptionValue[Mesh],PlotStyle -> OptionValue[PlotStyle],
            PlotPoints -> OptionValue[PlotPoints]
        ]
    ];
    ReplaceAll[plot,
        gc_GraphicsComplex :> addColorFunction[
            gc, OptionValue[ColorFunction], OptionValue @ ColorFunctionScaling
        ]
    ]
];
Attributes[MeshPlot3D] = {HoldAll}

addColorFunction[GraphicsComplex[pts_, g_, opts___], cf_, scaling_] := With[
    {rescale = If[TrueQ[scaling], Rescale, Identity]},
    GraphicsComplex[pts,
        ReplaceAll[g,
            Line[p_] :> Line[p,
                VertexColors -> MapThread[cf, Part[Map[rescale, Transpose[pts]], All, p]]
            ]
        ],
        opts
    ]
]

Called via

MeshPlot3D[Sin[Sqrt[(x ^ 2) + y ^ 2]] / Sqrt[(x ^ 2) + y ^ 2],
    {x, -2 * Pi, 2 * Pi},
    {y, -2 * Pi, 2 * Pi},
    PlotRange -> {-1, 1},
    BoxRatios -> {1, 1, 1}, PlotPoints -> 100,
    Boxed -> False, Axes -> False
]

enter image description here

or

MeshPlot3D[x / Exp[(x ^ 2) + y ^ 2],
    {x, -2, 2},
    {y, -2, 2},
    ColorFunction -> Function[{x, y, z}, Hue[0.65 * (1 + -z)]],
    PlotStyle -> Directive[Opacity[0.5], Blue]
]

enter image description here

$\endgroup$
2
  • 2
    $\begingroup$ (+1) The OP's figure seems to be using the so-called "cool" colormap from MATLAB, so to emulate that, one can use ColorFunction -> (RGBColor[#3, 1 - #3, 1] &). $\endgroup$ Commented Dec 20, 2021 at 18:45
  • $\begingroup$ Great job. Thanks. How to export it as a high-quality .eps figure? Export["highquality.eps", %] doesn't give high-quality figure? (Mathematica 13 on Windows 11) $\endgroup$
    – HD239
    Commented Dec 22, 2021 at 18:49
9
$\begingroup$

We can use the simple trick from this answer: Define

f = ReplaceAll[Rule[VertexColors, None] -> Rule[VertexColors, Automatic]];

and simply add the option DisplayFunction -> f to Plot3D:

Plot3D[Sin[Sqrt[(x^2) + y^2]]/Sqrt[(x^2) + y^2], {x, -2*Pi, 
      2*Pi}, {y, -2*Pi, 2*Pi}, PlotRange -> {-1, 1}, 
  Mesh -> 50, 
  DisplayFunction -> f,
  PlotStyle -> FaceForm[],
  ColorFunction -> (RGBColor[#3, 1 - #3, 1] &),
  BoxRatios -> {1, 1, 1}, 
  PlotPoints -> 100, 
  Boxed -> False, 
  Axes -> False, 
  ImageSize -> Large] 

![enter image description here

where I used the color function suggested by J.M. in comments. If we use the color function in OP

 ColorFunction -> (Opacity[#3 + .1, ColorData[{"DeepSeaColors", "Reverse"}][#3]] &)

we get

enter image description here

A function that applies ColorFunction to mesh lines and PlotStyle to polygon faces:

ClearAll[meshPlot3D]

SetAttributes[meshPlot3D, HoldAll];

meshPlot3D[args__, opts : OptionsPattern[Plot3D]] := Module[
  {df = ReplaceAll[Rule[VertexColors, None] -> Rule[VertexColors, Automatic]]}, 
  Show[Plot3D[args, Mesh -> None, BoundaryStyle -> None, ColorFunction -> None, opts],
   Plot3D[args, DisplayFunction -> df, PlotStyle -> FaceForm[], opts]]]

Examples:

meshPlot3D[Sin[Sqrt[x^2 + y^2]]/Sqrt[x^2 + y^2], {x, -2 Pi, 2 Pi}, {y, -2 Pi, 2 Pi},
 Mesh -> 50,
 PlotStyle -> FaceForm[],
 ColorFunction -> (Opacity[#3 + .1, RGBColor[#3, 1 - #3, 1]] &),
 PlotPoints -> 100, 
 PlotRange -> {-1, 1},
 BoxRatios -> {1, 1, 1},
 Boxed -> False, Axes -> False, ImageSize -> Large]
same picture as above

Using the second example from Jason B.'s answer:

meshPlot3D[x/Exp[(x^2) + y^2], {x, -2, 2}, {y, -2, 2}, 
 Mesh -> 50, 
 PlotPoints -> 100, 
 PlotStyle -> FaceForm[{Opacity[.5], Blue}], 
 ColorFunction -> Function[{x, y, z}, Hue[0.65*(1 + -z)]], 
 ImageSize -> Large, Boxed -> False, Axes -> False]

enter image description here

$\endgroup$
1
  • $\begingroup$ Great job. Thanks. How to export it as a high-quality .eps figure? Export["highquality.eps", %] doesn't give high-quality figure? (Mathematica 13 on Windows 11) $\endgroup$
    – HD239
    Commented Dec 22, 2021 at 18:48

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.