2
$\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$ Commented 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$ Commented 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$ Commented Oct 15, 2018 at 20:08

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.