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.
July 16th, 2008 at 2:45 pm
nice work
July 19th, 2008 at 12:22 am
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
August 7th, 2008 at 8:54 pm
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.
August 8th, 2008 at 12:36 pm
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.
August 9th, 2008 at 12:55 am
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.
August 9th, 2008 at 6:14 am
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.
November 12th, 2008 at 11:41 pm
a1rqvawntdh6uyog