user1631306
user1631306

Reputation: 4470

How to draw heatmap in java, showing circles instead of color

I am generating a heatmap, using Jtable and filling it with numbers, then with colors enter image description here. Instead of colors, I want to show the circles or some other graphical image, which would be relative in size, like this enter image description here. I found one library in R to do it, geom_tile, but couldn't find out any way to do it in Javs. Do you guys have any idea or example of how to do it?

Upvotes: 0

Views: 3182

Answers (1)

cello
cello

Reputation: 5486

To draw custom table cells, you need to provide your own implementation of a TableCellRenderer.

Your custom TableCellRenderer must only implement one method: getTableCellRendererComponent, which must return a Component or JComponent.

Your TableCellRenderer can then return a custom JComponent which paints the circle depending on the cell value, which gets set beforehand.

In the following there is a sample code demonstrating setting your custom HeatmapCellRenderer, which uses a DotRenderer as component to render a single cell:

public class TableHeatmap {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        // create a demo table 10 x 10 cells
        JTable table = new JTable(10, 10);
        frame.setContentPane(table);

        // fill in some random data
        for (int row = 0; row < 10; row++) {
            for (int col = 0; col < 10; col++) {
                table.setValueAt((int) (Math.random() * 10), row, col);
            }
        }

        // set our custom TableCellRenderer
        table.setDefaultRenderer(Object.class, new HeatmapCellRenderer());
        table.setRowHeight(30);

        // show the window
        frame.pack();
        frame.setVisible(true);
    }

    private static class HeatmapCellRenderer implements TableCellRenderer {

        private final DotRenderer renderer = new DotRenderer();

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            if (value instanceof Integer) {
                this.renderer.setValue((Integer) value);
                return this.renderer;
            }
            return null;
        }
    }

    private static class DotRenderer extends JComponent {
        private int value;

        public void setValue(int value) {
            this.value = value;
        }

        @Override
        protected void paintComponent(Graphics g) {
            g.setColor(Color.BLUE);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
            g.setColor(Color.RED);
            int centerX = this.getWidth() / 2;
            int centerY = this.getHeight() / 2;
            g.fillOval(centerX - this.value, centerY - this.value, this.value * 2, this.value * 2);
        }

    }

}

The above code should generate a table similar to the following screenshot:

example screenshot

By using more complex objects than just an Integer for your cells, you could implement more complex renderers. If you have for example a simple data class class MyData { int value1; int value2; } and insert such values into the table, you could implement a Renderer that sets the background color dependent on value1, and the size of the dot based on value2 of the cell value. Adding a value3 to the class would further allow to color the dots based on these values, coming pretty close to your example image.

Upvotes: 4

Related Questions