Java Heatmap (Example Code)

Heatmap General Description

A heatmap is a visual representation of a list of points.

This is handy in a lot of situations. If you want to quickly analyze a log you created of positions players died in a game, positions your users clicked on your website, etc.

Basically anywhere where the log of points is generated from something visual.

Usage Java Heatmap

The code below is quite easy to use. Just include the .java file and use it as following:

List<java.awt.Point> points; // your points
String outputFile;
String originalImage; // the path to the image the heatmap is to be layed over. eg a screenshot of a homepage or a level
HeatMap myMap = newHeatMap(points, outputFile, originalImage);
myMap.createHeatMap(multiplier); // multiplier depends on density of points. try something between 1f and 10f

The heatmap will be created now and you will find it at the specified output file.

If not: you might have to adjust the following paths:
private static final String CIRCLEPIC
private static final String SPECTRUMPIC
so that they point to where the two .png files (added in the download) or the files you created yourself for this purpose are stored.

If it is still not working I will refer you to the exception messages. Most likely is that it has to do with file permissions.

Be warned: If the list of points is too big, this program will take quite a long time to execute and also consume some memory. Try it with a couple of points first and then increase the amount. I tried it on my computer with generated random points: 500k were no problem, 1m still where computed quite fast, but my computer made weird noises with 2m^^

If someone knows a way to make remap and negateImage faster I would be very thankful. Right now, they each take up about 48% of the time (depending on amount of points of course, this is with about 6k).

Example Heatmaps

Download Java Heatmap Example Implementation

heatmap [21.22 kB]

5 thoughts on “Java Heatmap (Example Code)

  1. Hello,
    I liked the heat map implementation.
    Why don’t you use bitwise operator ~ to negate the color ?

    private BufferedImage negateImage(final BufferedImage img) {
            final int width = img.getWidth();
            final int height = img.getHeight();
            for (int x = 0; x &lt; width; x++) {
                for (int y = 0; y &lt; height; y++) {
                    img.setRGB(x, y,  ~img.getRGB(x, y));
                }
            }
            return img;
        }
  2. @Sylvain thanks, that’s a great idea. I actually already found another way of negating an image and forgot to update this post:

        private BufferedImage negateImage(BufferedImage img) {
            RescaleOp op = new RescaleOp(-1.0f, 255f, null);
            BufferedImage negative = op.filter(img, null);
            return negative;
        }

    When I timed the code, this method is considerably faster than both of our implementations:

    name           per call (mean, ns)     per call (median, ns)     95th percentile (ns)     total (ms)     runs    
    function2      51347911                51044122                  49968132                 4.10783288     100      
    function3      690825776               689233822                 676454300                55.26606208    100      
    function1      699379013               696750925                 686529518                55.95032104    100

    Where function2 is the above code, function3 is your code, and function1 is my original implementation.

  3. Hi,
    I know this is old but, your updated negateImage method doesn’t work for me but the one suggested by @Sylvain and your older one works great (with said time concerns).

  4. I think it is late, but some small issues.
    – First, you do two passes to a heatmap, one to negate() it and another to remap() it. Those functions should act only on one pixel so you can do both actions in a single pass. For example:

    for (int i = 0; i < heatMap.getWidth(); i++) {
    for (int j = 0; j < heatMap.getHeight(); j++) {
    heatMap.setRGB(i, j, remapPixel(negatePixel(heatMap.getRGB(i, j))));
    }
    }

    – Second, you are reading the input image twice. Once in initMap(), only to get the dimensions of the image, and then one more time near the end of createHeatMap() to edit the image. Your constructor should store the BufferedImage instead of storing the File, so you can avoid reading the image from file twice. Actually, for a good design, the constructor should take a BufferedImage as input and createHeatMap() should return the modified BufferedImage as output, because you never know if the user has the image stored in a File or in any other format (e.g. coming from an InputStream).

    – Third, you are reading bolilla.png and colors.png from file every time you create a heat map. For the people that wants to create several heat maps, it would be more efficient that you read those images once when the class is loaded and you store their BufferedImages in static fields.

    I made a little experiment with a 1824×25300 image and 500,000 random points, and with my tips I moved from 108 seconds to 101 seconds. I guess the improvement is not so much, but at least is something. And I guess the bigger the input image, the more time you will save.

Leave a Reply

Your email address will not be published.