Search code examples
javabufferedimageheatmapgraphics2ddrawimage

How to represent NA values as empty pixels (white) for HeatMap in Java?


I am using the Java HeatMap library (http://www.mbeckler.org/heatMap/) to generate heatMap for my data. I am working with a daatset which has NA values. So, basically I want no color (white color) for the pixels which have NA value. But, unfortunately this library does not support data with NA value and what I get is a plan block of image with the base color. I tried looking into the source code, so as to make some changes. Within the code, the drawData() method is used to color each pixel in the bufferedImage (possibly!). Can someone help me with how I can implement support for NA values and to show them with no color? I have little to no experience with BufferedImage and Graphics2D class.

Here is the drawData() method from the source code of the library:

/**
     * Creates a BufferedImage of the actual data plot.
     *
     * After doing some profiling, it was discovered that 90% of the drawing
     * time was spend drawing the actual data (not on the axes or tick marks).
     * Since the Graphics2D has a drawImage method that can do scaling, we are
     * using that instead of scaling it ourselves. We only need to draw the
     * data into the bufferedImage on startup, or if the data or gradient
     * changes. This saves us an enormous amount of time. Thanks to
     * Josh Hayes-Sheen ([email protected]) for the suggestion and initial code
     * to use the BufferedImage technique.
     *
     * Since the scaling of the data plot will be handled by the drawImage in
     * paintComponent, we take the easy way out and draw our bufferedImage with
     * 1 pixel per data point. Too bad there isn't a setPixel method in the
     * Graphics2D class, it seems a bit silly to fill a rectangle just to set a
     * single pixel...
     *
     * This function should be called whenever the data or the gradient changes.
     */
    private void drawData()
    {

      //  System.out.println("Column: " + data.length + " row: " + data[0].length);
        bufferedImage = new BufferedImage(data.length,data[0].length, BufferedImage.TYPE_INT_ARGB);
        bufferedGraphics = bufferedImage.createGraphics();

        for (int x = 0; x < data.length; x++)
        {
            for (int y = 0; y < data[0].length; y++)
            {
                bufferedGraphics.setColor(colors[dataColorIndices[x][y]]);
                bufferedGraphics.fillRect(x, y, 1, 1);
            }
        }
    }

sample data can be found at: http://www.filedropper.com/data_13

So, this is how it looks at the moment:

From Java:

enter image description here

From R:

enter image description here

Please ignore the orientation of the two images


Solution

  • As the BufferedImage is created as ARGB, you could just not paint anything on those pixels that should be undefined, and they'll stay transparent. Something like:

    public static int NA = ...;
    
    private void drawData()
    {
        bufferedImage = new BufferedImage(data.length,data[0].length, BufferedImage.TYPE_INT_ARGB);
        Graphics2D bufferedGraphics = bufferedImage.createGraphics();
        try {
            for (int x = 0; x < data.length; x++)
            {
                for (int y = 0; y < data[0].length; y++)
                {
                    int colorIndex = dataColorIndices[x][y];
                    if (colorIndex != NA) {
                        bufferedGraphics.setColor(colors[colorIndex]);
                        bufferedGraphics.fillRect(x, y, 1, 1);
                    }
    // Alternate flow, if you really want the pixels to be white
    //                else {
    //                    bufferedGraphics.setColor(Color.WHITE);
    //                    bufferedGraphics.fillRect(x, y, 1, 1);
    //                }
                }
            }
        }
        finally {
            bufferedGraphics.dispose();
        }
    }
    

    I also dispose the Graphics2D instance, to avoid resource leaks.