1
$\begingroup$

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!

$\endgroup$
2
  • 2
    $\begingroup$ Try using ListPlot3D, instead, i.e. evaluate your points, first, and then feed them to ListPlot3D. $\endgroup$
    – rcollyer
    Oct 15, 2018 at 20:01
  • 2
    $\begingroup$ 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... $\endgroup$ Oct 15, 2018 at 20:03

2 Answers 2

2
$\begingroup$

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[2]; 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]

enter image description here

(* hack to get the right plot style... *)
color = plot[[1, 2, 1, 1, 2]];

Show[DiscretizeGraphics[plot, MeshCellStyle -> {2 -> color}, 
  PlotTheme -> "SmoothShading"], AbsoluteOptions[plot]]

enter image description here

And for comparison, here's the plot with default shading:

Plot3D[Sin[x + y], {x, 0, 3π}, {y, 0, 3π}, Mesh -> None]

enter image description here

$\endgroup$
1
$\begingroup$

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}

{Charting`Private`pvar$3088,Charting`Private`pvar$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}
$\endgroup$
1
  • 2
    $\begingroup$ You could also use EvaluationMonitor. $\endgroup$
    – Greg Hurst
    Oct 15, 2018 at 20:08

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.