Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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)

share|improve this question
add comment

1 Answer 1

up vote 5 down vote accepted

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}
   ]
  ]
share|improve this answer
    
+1 Wow, works great! This should be done by default by mma. –  Ajasja May 23 '12 at 15:39
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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