Reputation: 4470
I am generating a heatmap, using Jtable and filling it with numbers, then with colors . Instead of colors, I want to show the circles or some other graphical image, which would be relative in size, like this . 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
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:
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