# Fast DensityPlot

Is it possible to increase the perforamce the DensityPlot?

For example, let's try to plot this "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]


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

The question is

1. How to increase the speed?

2. How to decrease the MaxMemoryUsed?

3. How to decrease the size of the output?

-

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 convert GraphicsComplex to separate polygons, toTriangles split polygons to triangles, and texturize put 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]


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]


The definitions of the above functions are

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.

-
As I understand, you subdivide each triangle into Subpoints^2 regions and calculate values of f in the nodes. Is it correct? – Alexey Popkov Jan 5 '14 at 14:24
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. – ybeltukov Jan 5 '14 at 14:30
So PlotPoints->n, Subpoints->m, MaxRecursion->0 should be equivalent to PlotPoints->n*m, Subpoints->0, MaxRecursion->0? – Alexey Popkov Jan 5 '14 at 14:45
@AlexeyPopkov Yes, but with Subpoints->1 in the second case. – ybeltukov Jan 5 '14 at 15:03
@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. – ybeltukov Jan 5 '14 at 15:52