22
$\begingroup$

Is it possible to increase the performance of the DensityPlot?

For example, let's try to plot the following "flower"

f[x_, y_] := (x^2 + y^2) Exp[-x^2 - y^2] Sin[10 Sqrt[x^2 + y^2] + 10 ArcTan[x, y]]^4;

DensityPlot[f[x, y], {x, -3, 3}, {y, -3, 3}, PlotPoints -> 200, 
 MaxRecursion -> 3, ColorFunction -> Hue, PlotRange -> All, 
 ColorFunctionScaling -> False, ImageSize -> 600]

enter image description here

This toy example takes about 12 seconds on my laptop, eats about 1GB of RAM while plotting, and the 34MB result slows down the notebook.

The questions are:

  1. How to increase the speed?

  2. How to decrease the MaxMemoryUsed?

  3. How to decrease the size of the output?

$\endgroup$
21
$\begingroup$

Edit: tested with MMA 11.1, option Exclusions -> None added to recover the previous behavior.

I have found that my approach with textures has different applications:

Now I want to use it for the enhancement of the DensityPlot:

Options[fastDensityPlot] = Append[Options[DensityPlot], Subpoints -> 30];
SyntaxInformation[fastDensityPlot] = SyntaxInformation[DensityPlot];

fastDensityPlot[f_, {x_, xmin_, xmax_}, {y_, ymin_, ymax_}, opts : OptionsPattern[]] :=
 DensityPlot[f, {x, xmin, xmax}, {y, ymin, ymax},
       Evaluate@FilterRules[{opts}, Except@Subpoints]] // Normal // toTriangles // 
   texturize[Function[{#1, #2}, #3] & @@ {x, y, f},
        OptionValue[Subpoints], OptionValue[ColorFunction]]

Here Normal converts GraphicsComplex to separate polygons, toTriangles splits polygons to triangles, and texturize puts textures on every triangle (defined below), f is assumed to be Listable.

f[x_, y_] := (x^2 + y^2) Exp[-x^2 - y^2] Sin[10 Sqrt[x^2 + y^2] + 10 ArcTan[x, y]]^4;

fastDensityPlot[f[x, y], {x, -3, 3}, {y, -3, 3}, PlotPoints -> 10, 
 MaxRecursion -> 2, ColorFunction -> Hue, Subpoints -> 20, 
 PlotRange -> All, ImageSize -> 600, Exclusions -> None]

enter image description here

This image looks a bit better. At the same time fastDensityPlot is ~10 times faster then the regular DensityPlot, MaxMemoryUsed is only 64MB and ByteCount is 10MB.

One can see that fastDensityPlot uses the advantage of the non-equidistant mesh:

fastDensityPlot[f[x, y], {x, -3, 3}, {y, -3, 3}, PlotPoints -> 10, 
 MaxRecursion -> 2, ColorFunction -> Hue, Subpoints -> 20, 
 PlotRange -> All, ImageSize -> 600, Mesh -> All, Exclusions -> None]

enter image description here

Definitions of the above functions:

toTriangles = # /. Polygon[v_ /; Length[v] > 3, ___] :> (Polygon@Append[#, Mean[v]] & /@ 
       Partition[v, 2, 1, 1]) &;

texturize[f_, n_, colf_] := # /. Polygon[{v1_, v2_, v3_}, ___] :> {Texture@
       ImageData@Colorize[
         Image@f[v3[[1]] + (v1[[1]] - v3[[1]]) #1 + (v2[[1]] - v3[[1]]) #2, 
                v3[[2]] + (v1[[2]] - v3[[2]]) #1 + (v2[[2]] - v3[[2]]) #2] 
          &[#, Transpose[#]] &@ConstantArray[Range[-1./n, 1 + 1./n, 1./n], n + 3], 
         ColorFunction -> colf, ColorFunctionScaling -> False], 
      Polygon[{v1, v2, v3}, 
       VertexTextureCoordinates -> {{1 - 1.5/(n + 3), 
          1 - 1.5/(n + 3)}, {1.5/(n + 3), 1.5/(n + 3)}, {1.5/(n + 3), 
          1 - 1.5/(n + 3)}}]} &;

As in the linked answer, I add textures to every triangle with an appropriate rectangular grid. This method is fast because it uses packed arrays.

$\endgroup$
  • $\begingroup$ As I understand, you subdivide each triangle into Subpoints^2 regions and calculate values of f in the nodes. Is it correct? $\endgroup$ – Alexey Popkov Jan 5 '14 at 14:24
  • $\begingroup$ Yes! More precisely, I calculate the texture for a parallelogram and use only a half of it. One can optimize it further, but it is no so simple. $\endgroup$ – ybeltukov Jan 5 '14 at 14:30
  • $\begingroup$ So PlotPoints->n, Subpoints->m, MaxRecursion->0 should be equivalent to PlotPoints->n*m, Subpoints->0, MaxRecursion->0? $\endgroup$ – Alexey Popkov Jan 5 '14 at 14:45
  • $\begingroup$ @AlexeyPopkov Yes, but with Subpoints->1 in the second case. $\endgroup$ – ybeltukov Jan 5 '14 at 15:03
  • 1
    $\begingroup$ @AlexeyPopkov They are visually similar, but not equivalent. The second one contains a lot of small triangles with a lot of small textures. This is very slow and inefficient. fastDensityPlot is fast when you use a small number of big triangles with big textures (two big triangles in the limit). The opposite limit is DensityPlot which produce a lot of small colorized (not texturized) triangles. $\endgroup$ – ybeltukov Jan 5 '14 at 15:52

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.