10
$\begingroup$

When I tried to present some pre-calculated density histograms inside Manipulate I noticed that the display of DensityHistogram is extremely slow. Here is a simple benchmark:

Second[x_] := x[[2]];
data = RandomVariate[BinormalDistribution[Abs@Random[]], {5, 10^4}];
histograms = 
  DensityHistogram[#, 30, PerformanceGoal -> "Speed"] & /@ 
   data;
contourplots = 
  ListContourPlot[Second@HistogramList[#, 30], 
     InterpolationOrder -> 0] & /@ data;
rasterizedSmall = Rasterize[#, ImageSize -> Small] & /@ histograms;
rasterizedMedium = Rasterize[#, ImageSize -> Medium] & /@ histograms;

t = AbsoluteTime[];
histograms
AbsoluteTime[] - t
(* ==> 1.6410939 *)    

t = AbsoluteTime[];
contourplots
AbsoluteTime[] - t
(* ==> 0.0860049 *)

t = AbsoluteTime[];
rasterizedSmall
AbsoluteTime[] - t
(* ==> 0.0390022 *)    

t = AbsoluteTime[];
rasterizedMedium
AbsoluteTime[] - t
(* ==> 0.0280016 *)    

So we see that it takes almost two seconds to display five pre-calculated density histograms, while five list contour plots are displayed in ~100 ms.

What is wrong and is there an easy way to fix it?

(I'm using mma 8.0.1 on Win 7 and I've already turned off antialising)

$\endgroup$
0

1 Answer 1

7
$\begingroup$

You have to inspect your graphics carefully. What you do here is you compare apples and oranges. While your DensityHistogram contains about 100 colors (89 in this special case)

enter image description here

the ListContourPlot contains only 10 colors.

enter image description here

This is what you could have observed directly. Under the hood happens more which leads to the slowness of the DensityHistogram. The ListContourPlot uses the relatively new GraphicsComplex directive which works like that:

When you want to draw a polygon or rectangle or whatever, you don't use the coordinates directly because adjacent polygons share points and you would repeat the same coordinates over and over again. Instead, you start with a list of all coordinates and then you refer only to the index of those coordinates.

Additionally, while DensityHistogram creates many many Rectangle directives, ListContourPlot creates only some Polygon-directives and includes many polygons in one call:

Polygon[{pt11, pt12,...},{pt21,...},...}] represents a collection of polygons.

This leads usually to speed improvement.

Therefore, your ListContourPlot is faster because it

  1. is less complex in general
  2. uses GraphicsComplex
  3. uses a few Polygon calls instead of many Rectangle calls

To test this, just look at the InputForm of your DensityHistogram. You could write some lines of code to extract all coordinates, build a GraphicsComplex and convert the many Rectangles into Polygon calls:

histPatrick =
 With[{hist = DensityHistogram[
     RandomVariate[BinormalDistribution[Abs@Random[]], 10^4], 30, 
     PerformanceGoal -> "Speed"]},
  Block[{coords, coordRule, tmpgr},
   tmpgr = 
    hist /. Rectangle[a : {x1_, y1_}, b : {x2_, y2_}] :> 
      Polygon[{a, {x2, y1}, b, {x1, y2}}];
   coords = Cases[tmpgr, Polygon[{a__}] :> a, Infinity];
   coordRule = Thread[coords -> Range[Length[coords]]];
   tmpgr /. 
     Graphics[dirs_, rest___] :> 
      Graphics[
       GraphicsComplex[coords, 
        dirs /. Polygon[pts_] :> Polygon[pts /. coordRule]], 
       rest] /. {start___, Longest[polys__Polygon], end___} :> {start,
       Distribute[{polys}, Polygon], end}
   ]
  ]
$\endgroup$
1
  • $\begingroup$ +1 Wow, works great! This should be done by default by mma. $\endgroup$
    – Ajasja
    Commented May 23, 2012 at 15:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.