How to make heat maps in Flex

Last semester I worked with Darya Filippova, Joonghoon Lee, Andreea Olea, and Krist Wongsuphasawat on a project for Ben Shneiderman’s Information Visualization course.  We took a subset of the accident data collected by the CATT Lab and built a tool to help figure out why certain stretches of road have a higher number of accidents than others.  We developed a number of visualizations to achieve this goal.  My major contribution was the heat map.

I’ve only seen a few Flex apps that use heat maps to show clusters of data, and I’ve never come across any source code.  Corunet has a blog post detailing their server-side heat map algorithm, and I ported it to Actionscript.  I’ve continued to play around with the code since the semester ended, making it more efficient, extensible, etc., and I think it’s about time it saw the light of day.

The application below traces your mouse movements, storing the x and y positions in an ArrayCollection which is fed to the heat map.  The size of the collection is capped at 1000 points because I didn’t want to blow up anyone’s browser, but any machine that can actually run a web browser shouldn’t run into any problems with that many points.

You can view the source here.

The algorithm isn't all that complex, and the functions built into the BitmapData class take care of a lot of the dirty work.  Basically, a circle with a gradient fill is drawn for each point in the collection.  The gradient ranges from black on the edge to blue in the center.  Bluer regions represent areas that have had more "influence" than others.  The exact shade of blue used in the center is dependent upon the maximum number of coincident points.  As this number increases, the relative influence each point has decreases, preventing the entire heat map from being rendered as a supersaturated mass.  The BitmapData's threshold method is used to convert the black-blue image to a fully colored heat map.

The HeatMap class is driven by an ArrayCollection of Objects, and the Objects are mapped to the screen coordinates based on their x and y values if they exist. Because not everything has an x and y value, the HeatMap has a transformationFunction property which is used to project objects to screen coordinates. Also, a weightFunction property is available which allows weights to be assigned on a per-object basis. The usage of these to functions is similar to that of the dataFunction property in the charting classes.

That's all there is to it.  The source is pretty well documented, so you can get the nitty gritty details there.

Update (August 25, 2008)

I've added the HeatMap component to my Google Code repository, so the source shown here isn't the most up-to-date.  Rather than continually update this post when I make a change, I'll let the most current revision speak for itself.

The HeatMap, and all of my future opensource work will be licensed under the MIT license.

This entry was posted in Flex and tagged , . Bookmark the permalink. Both comments and trackbacks are currently closed.

20 Comments

  1. Darya Filippova
    Posted July 16, 2008 at 2:45 pm | Permalink

    nice work

  2. Posted July 19, 2008 at 12:22 am | Permalink

    Michael– this is very cool…I have an application I am building that this would work well for. Are you interested in doing some contract work?

    Colin Cook

  3. Trygve
    Posted August 7, 2008 at 8:54 pm | Permalink

    Michael, this work is amazing. How hard would it be for me to rewrite it without Flex? I don’t think I have time to learn Flex before my next project. I saw that the HeatMap class extends what looks like a Flex object. If you have a second please let me know your thoughts.

  4. Posted August 8, 2008 at 12:36 pm | Permalink

    Trygve: The core of HeatMap is the drawHeatMap method, and that should be easy to replicate in AS3 without using the Flex framework classes. HeatMap could extend Sprite instead of UIComponent and dataProvider could be an Array instead of an ArrayCollection. You’ll lose the IInvalidating methods, but you can redraw the heat map onEnterFrame instead. If you’re not coding in AS at all, you’ll just need to replicate drawHeatMap using your language’s bitmap utilities.

  5. Trygve
    Posted August 9, 2008 at 12:55 am | Permalink

    Thank you so much for responding!

    I hope I’m not bothering you with too many questions but I’m new to AS3 (although I have a strong programming background in Java and .NET). Can you help me understand how to render the heatBitmapData to the stage? I noticed the overloaded methods [commitProperties()] and [updateDisplayList()] however I’m assuming those are part of the UIComponent class. (I just removed the override).

    I added a few lines to the constructor of HeatMap to create some points in my array and replaced the _dataProvider with this points array in commitProperties(). Then I simply tried to call the commitProperties() and then the updateDisplayList() which in turn calls the drawHeatMap() method.

    The fla compiles fine but I don’t think I’m adding anything to the stage (just a blank white stage when I debug). I thought I would need an addChild(…?) to add it to the display list. I only want to run through the points and display the map once (meaning I don’t need to do it to loop on an enter frame event).

    I hope I’m doing a good enough job explaining myself. I could provide the source changes I made if that would help you understand my question. I know how difficult and time consuming it can be to try to help every person who may contact you so I understand if you’re unable to assist me.

    Any help you can provide will be greatly appreciated. Thanks.

  6. Trygve
    Posted August 9, 2008 at 6:14 am | Permalink

    I found my error. In the updateDisplayList() method, the following line [graphics.drawRect(0,0,width,height);] always contained zeros for height and width so the drawHeatMap() never made it through your first if statement. I had to hardcode the width and height for some reason. I tried stage.height & stage.width but that didn’t work but I can figure that out later.

    However, I have a new question for you :-). I’m afraid I may not be able to use this example after all. Is there a way to allow this heat map to be semi-transparent over an image. I’m assuming that I need to start with the underlying image as part of the bitmap before I start the processing of the points…? Am I heading in the right direction? I feel like a kid swinging blindly at a piñata.

    Again, thanks for any help you may provide. I promise I’ll stop spamming your blog soon.

  7. Posted April 17, 2009 at 1:56 pm | Permalink

    This is wonderful, thanks for posting the source! I might try to use this to do some realtime data viz.

    Thanks

  8. Posted April 22, 2009 at 4:32 pm | Permalink

    Thank you for sharing the source. Your implementation is amazing. I noticed some performance degradation with larger canvases, but thats to be expected with the amount of points being drawn. I am curious as to the format used for the Gradient dictionary arrays. I’ve never seen colors mapped that way before. How did you come up with those values? Fireworks? Photoshop? Thanks and keep up the great work.

  9. Posted April 26, 2009 at 2:35 pm | Permalink

    Shawn: This is something that a few people have asked about, so I should probably write up a post about exactly how it works. Basically, the HeatMap needs 255 exactly colors, so it just felt more natural to pre-generate the array than calculate them on the fly. To create the arrays, I built a few linear gradients, drew them to a BitmapData that was 255 pixels wide, and extracted the color at each pixel.

  10. Posted November 3, 2009 at 4:25 pm | Permalink

    It would be interesting to extract that technique into a class that could generate random gradients, or better yet, take the algorithm and allow the user to define their own.

    Again, thanks Michael!

  11. Posted December 20, 2009 at 3:56 pm | Permalink

    Thanks Michael for this great work! I’ve created a simple tool to draw the gradient by hand, and use your process to create the gradient array…

    http://isokon.net/post/gradientArray/accessColorInGradient.fla

  12. Omar
    Posted January 27, 2011 at 6:35 pm | Permalink

    Hello Michael, gr8 job… i’ve been using this component. I’d like you to tell me how can I modify the itemRadius property to change the size of a point dynamically, I’ve modified the point:Point for an Object (with the point inside) and the current radius but all objects become the same size… Hope you can give me a hand. Thank you very much…

  13. Posted January 29, 2011 at 3:01 pm | Permalink

    Omar, the HeatMap wasn’t really built to do that, but that is definitely a good feature. You would need a way to let the class know what radius to use for each point, so you could add a radiusFunction and call it in the same way as the transformation/weight functions. drawHeatMap would need to be altered so creating the heatMapItem happened inside the loop since that is the object responsible for drawing each point. I hope this helps.

  14. Omar
    Posted January 30, 2011 at 9:38 pm | Permalink

    Hello Michael, Thanks for your suggestion, I’ll take a try and let you know my results… Good Bye!

  15. Posted April 27, 2011 at 10:36 am | Permalink

    Amazing concept.

  16. Posted April 6, 2012 at 11:17 am | Permalink

    Thanks for this subject, I will use it in my flashreport project

  17. veco
    Posted April 26, 2012 at 12:24 am | Permalink

    How can we use the different GradientDictionary color schemes (THERMAL,RAINBOW,RWB) to create a gradient background color on a container that will represent the “least intense” to the “most intense” color?

    Like for example there are a total of 999 clicks on an image, I would like to plot a gradient background on a canvas/container which has the colors for the intensities on the image being heatmapped.

  18. Posted April 26, 2012 at 11:35 am | Permalink

    veco, you mean something like a legend? the GradientDictionary constants are arrays of hex color codes. You could create a linear gradient fill and loop over the array, populating the gradient stops each way. The draw a rect in the background of your container using that gradient fill.

  19. veco
    Posted April 26, 2012 at 3:57 pm | Permalink

    Thanks Mike! I’ll try this out.

  20. Leem
    Posted May 17, 2014 at 10:09 am | Permalink

    Hello Michael, thank you for your job. I have dowloaded the source and import into my FlexBuilder , when I run the application there an error tip:” File not found: file:/C:/Users/Leem/Adobe%20Flash%20Builder%204.6/michaelvandaniker%20examples/bin-debug/HeatMapApp.html” Can you tell me the reason,thank you very much.