# Reduce Plot3D evaluation time?

I have a large function func[a,b] and I need its Plot3D. Since the command Plot3D[func[a,b],{a,a0,a1},{b,b0,b1}] didn't evaluate even after 10 minutes, I tried the following:

In:  Timing[func[aValue,bValue]]
Out: {2.02, someValue}


So it takes ~2 seconds for the function at a single point. Then, I tried the following, expecting it to evaluate func no more than 2 times (~ 4 seconds)

In:  Timing[Plot3D[func[a,b], {a,a0,a1}, {b,b0,b1}, PlotPoints->2, Mesh->All, MaxRecursion->0]]
Out: {24.48, somePlot}


I do not see why it takes such a huge amount of time in spite of specifying only two plot-points.

Question:(1) What can I do in this case to make the plotting faster? (2) What is done in general to make plotting faster?

Thank you!

• Try using ListPlot3D, instead, i.e. evaluate your points, first, and then feed them to ListPlot3D. Oct 15, 2018 at 20:01
• Hard to say without the function. It could be simplified symbolically first, or compiled (with Compile), or vectorize, or replaced by a more efficiet algorithm... Oct 15, 2018 at 20:03

Note that PlotPoints -> 2 means 2 plot points in each direction, so I'd expect 4 evaluations for your input (8 seconds total).

We can use EvaluationMonitor to see how many times the function is being evaluated:

cnt = 0;
Plot3D[a + b, {a, 0, 1}, {b, 0, 1}, PlotPoints -> 2,
Mesh -> All, MaxRecursion -> 0, EvaluationMonitor :> (cnt++)
];
cnt

16


Plot3D does post processing to make the plot better looking. One part of this is figuring out surface normals to give the plot a smoother appearance, and this involves evaluating your function. Luckily we can turn this off with NormalsFunction:

cnt = 0;
Plot3D[a + b, {a, 0, 1}, {b, 0, 1}, PlotPoints -> 2,
Mesh -> All, MaxRecursion -> 0, NormalsFunction -> None,
EvaluationMonitor :> (cnt++)
];
cnt

6


I don't know where the extra 2 evaluations are coming from, but let's at least profile a function that takes 2 seconds to evaluate and see if we're at 12 seconds. Perhaps there are more options we can turn off.

Plot3D[Pause; a + b,
{a, 0, 1}, {b, 0, 1},
PlotPoints -> 2, Mesh -> All,
MaxRecursion -> 0, NormalsFunction -> None
]; // AbsoluteTiming

{12.2104, Null}


If you'd like to have smooth shading, you could manually postprocess by estimating the surface normals from the triangular faces.

An example:

plot = Plot3D[Sin[x + y], {x, 0, 3π}, {y, 0, 3π},
NormalsFunction -> None, Mesh -> None] (* hack to get the right plot style... *)
color = plot[[1, 2, 1, 1, 2]];

Show[DiscretizeGraphics[plot, MeshCellStyle -> {2 -> color}, And for comparison, here's the plot with default shading:

Plot3D[Sin[x + y], {x, 0, 3π}, {y, 0, 3π}, Mesh -> None] You can find out what values a function is being evaluated at by making a definition such as

func[x_, y_] := (Print[{x, y}]; Sin[x y])

Timing[Plot3D[func[a, b], {a, 0, 1}, {b, 0, 1}, PlotPoints -> 2,
Mesh -> All, MaxRecursion -> 0]]

{0,0}

{0.001001,0.001001}

{ChartingPrivatepvar$$3088,ChartingPrivatepvar$$3089}

{1.*10^-6,1.*10^-6}

{0.999999,1.*10^-6}

{1.*10^-6,0.999999}

{0.999999,0.999999}

{1.*10^-6,1.*10^-6}

{1.0149*10^-6,1.*10^-6}

{1.*10^-6,1.0149*10^-6}

{0.999999,1.*10^-6}

{0.999999,1.*10^-6}

{0.999999,1.0149*10^-6}

{1.*10^-6,0.999999}

{1.0149*10^-6,0.999999}

{1.*10^-6,0.999999}

{0.999999,0.999999}

{0.999999,0.999999}

{0.999999,0.999999}

• You could also use EvaluationMonitor. Oct 15, 2018 at 20:08