在JTable中制作3色标热图

时间:2017-06-14 17:11:39

标签: java swing jtable heatmap

我有一个JTable,比方说100x100的整数。 我将此矩阵规范化以使相应的值从0到1

现在我需要制作热图(就像我们在excel中进行条件格式化)/示例图enter image description here

这是通过使用3路颜色缩放创建的,中间和最大设置为百分位数50和90。

现在,我正在尝试在JTable中生成相同的内容,并且我没有看到类似的颜色渐变。

enter image description here

我需要尽可能多地复制颜色的光滑度。我的代码是

int[][] color = { { 99, 190, 123 }, { 255, 235, 132 }, { 248, 105, 107 } };
    int idx1 = 0;
    int idx2 = 0;
    ArrayList<Integer> rgbList = new ArrayList<Integer>();

    if (value == 0.0)
    {
        idx1 = 0;
        idx2 = 0;
    }
    else if (value < fiftyPercentile)
    {
        idx1 = 0;
        idx2 = 1;
    }
    else if (value > nintyPercentile)
    {
        idx1 = 2;
        idx2 = 2;
    }
    else
    {
        idx1 = 1;
        idx2 = 2;
    }


    double r = ((color[idx2][0] - color[idx1][0]) * value + color[idx1][0]);
    double g = ((color[idx2][1] - color[idx1][1]) * value + color[idx1][1]);
    double b = ((color[idx2][2] - color[idx1][2]) * value + color[idx1][2]);

    rgbList.add((int) (r));
    rgbList.add((int) (g));
    rgbList.add((int) (b));
    return rgbList;

2 个答案:

答案 0 :(得分:4)

  

我需要尽可能多地复制颜色的光滑度。

使用Color.getHSBColor()获取N等间距色调的调色板,如here所示。

private List<Color> clut = new ArrayList<>(N); // color lookup table
…
for (int i = 0; i < n; i++) {
    clut.add(Color.getHSBColor((float) i / N, 1, 1));
}

您可以限制色调的频谱,如here所示;因为您的调色板从绿色变为黄色到红色,您需要将0.0(红色)反转为0.33…(绿色)。您可以在your TableCellRenderer中使用它们,如图所示here用于交替颜色,here用于亮度值调色板。 @ aterai example的变化说明了 N - 色热图的效果,从绿色到黄色,橙色到红色。

List<Color> palette = new ArrayList<>(N);
…
float gHue = 1 / 3f;
for (int i = 0; i < N; i++) {
    palette.add(Color.getHSBColor(gHue - ( i * gHue / N), 0.5f, 1));
}

image

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

/**
 * @see https://stackoverflow.com/a/44557115/230513
 * @see https://stackoverflow.com/a/44559171/230513
 */
public class TableTest {

    private static final int N = 100;

    public JComponent makeUI() {
        String[] columnNames = {"1", "2"};
        Object[][] data = {
            {0d, 1d}, {.5, .6}, {.66, .77},
            {.85, .89}, {.78, .99}, {.95, .88}
        };
        DefaultTableModel model = new DefaultTableModel(data, columnNames) {
            @Override
            public Class<?> getColumnClass(int column) {
                return Double.class;
            }
        };
        Random r = new Random();
        double d = r.nextDouble();
        for (int i = 0; i < 100; i++) {
            model.addRow(new Double[]{r.nextDouble(), r.nextDouble()});
        }
        JTable table = new JTable(model);
        List<Color> palette = makeHSBPalette();
        table.setDefaultRenderer(Double.class, new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(
                JTable table, Object value, boolean isSelected,
                boolean hasFocus, int row, int column) {
                super.getTableCellRendererComponent(
                    table, value, isSelected, hasFocus, row, column);
                if (value instanceof Double) {
                    setBackground(getColor(palette, (Double) value));
                }
                return this;
            }
        });
        JPanel p = new JPanel(new BorderLayout());
        p.add(new JScrollPane(table));
        return p;
    }

    private static List<Color> makeHSBPalette() {
        List<Color> palette = new ArrayList<>(N);
        float gHue = 1 / 3f;
        for (int i = 0; i < N; i++) {
            palette.add(Color.getHSBColor(gHue - ( i * gHue / N), 0.5f, 1));
        }
        return palette;
    }

    private static Color getColor(List<Color> palette, double v) {
        if (v < 0f || v > 1f) {
            throw new IllegalArgumentException("Parameter outside of expected range");
        }
        return palette.get((int) (Math.min(v * N, N - 1)));
    }

    public static void main(String... args) {
        EventQueue.invokeLater(() -> {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            f.getContentPane().add(new TableTest().makeUI());
            f.setSize(320, 240);
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        });
    }
}

答案 1 :(得分:4)

另一种选择是使用LinearGradientPaintPixelGrabber

private static int[] makeGradientPallet() {
    BufferedImage image = new BufferedImage(100, 1, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2  = image.createGraphics();
    Point start    = new Point(0, 0);
    Point end      = new Point(99, 0);
    float[] dist   = {0.5f, 0.9f, 1.0f};
    Color[] colors = {new Color(99, 190, 123),
                      new Color(255, 235, 132),
                      new Color(248, 105, 107)};
    g2.setPaint(new LinearGradientPaint(start, end, dist, colors));
    g2.fillRect(0, 0, 100, 1);
    g2.dispose();

    int width = image.getWidth(null);
    int[] pallet = new int[width];
    PixelGrabber pg = new PixelGrabber(image, 0, 0, width, 1, pallet, 0, width);
    try {
        pg.grabPixels();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
    return pallet;
}

<强>截图

enter image description here

<强> TableTest.java

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.*;

public class TableTest {
  public JComponent makeUI() {
    String[] columnNames = {"1", "2"};
      Object[][] data = {
          {0d, 1d}, {.5, .6}, {.66, .77},
          {.85, .89}, {.78, .99}, {.95, .88}
      };
    DefaultTableModel model = new DefaultTableModel(data, columnNames) {
      @Override public Class<?> getColumnClass(int column) {
        return Double.class;
      }
    };
    Random r = new Random();
    double d = r.nextDouble();
    for (int i = 0; i < 100; i++) {
      model.addRow(new Double[] {r.nextDouble(), r.nextDouble()});
    }
    JTable table = new JTable(model);
    int[] pallet = makeGradientPallet();
    table.setDefaultRenderer(Double.class, new DefaultTableCellRenderer() {
      @Override public Component getTableCellRendererComponent(
          JTable table, Object value, boolean isSelected,
          boolean hasFocus, int row, int column) {
        super.getTableCellRendererComponent(
          table, value, isSelected, hasFocus, row, column);
        if (value instanceof Double) {
          Color bgc = getColorFromPallet(pallet, (Double) value);
          setBackground(bgc);
        }
        return this;
      }
    });
    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(table));
    return p;
  }
  private static int[] makeGradientPallet() {
    BufferedImage image = new BufferedImage(100, 1, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2  = image.createGraphics();
    Point start    = new Point(0, 0);
    Point end      = new Point(99, 0);
    float[] dist   = {0.5f, 0.9f, 1.0f};
    Color[] colors = {
        new Color(99, 190, 123),
        new Color(255, 235, 132),
        new Color(248, 105, 107)
    };
    g2.setPaint(new LinearGradientPaint(start, end, dist, colors));
    g2.fillRect(0, 0, 100, 1);
    g2.dispose();

    int width = image.getWidth(null);
    int[] pallet = new int[width];
    PixelGrabber pg = new PixelGrabber(image, 0, 0, width, 1, pallet, 0, width);
    try {
      pg.grabPixels();
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }
    return pallet;
  }
  private static Color getColorFromPallet(int[] pallet, double v) {
    if (v < 0f || v > 1f) {
      throw new IllegalArgumentException("Parameter outside of expected range");
    }
    int i = (int)(pallet.length * v);
    int max = pallet.length - 1;
    int index = Math.min(Math.max(i, 0), max);
    return new Color(pallet[index]);
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new TableTest().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}