JFreeChart 生成热力图

4
我有一个包含点(x,y)的数据集,想要创建一个该数据集的热图。更具体地说,我想要一张图像,在这张图像中,点集较为密集的区域颜色较浅,而点集较少的区域颜色较暗。
我正在使用JFreeChart库,并且找到了一些类,例如DefaultHeatMapDataset,但我不确定如何正确使用它们。
有人知道如何实现吗?
先行致谢!
Giovanni

2个回答

4

谢谢您的回答!我知道如何使用XYBlockRenderer,但是如何根据x和y建模z值呢? - Giovanni Soldi
@GiovanniSoldi:渲染器使用_z_值为每个点索引PaintScale;单击类名以查看源代码 - trashgod

2
在JFreeChart中创建热力图有点棘手,因为目前(截至版本1.0.19/1.5.0),没有相应的图表类型或绘图用于此用例。(可用的HeatMapDataset是为与HeatMapUtilities一起使用而编写的,正如David Gilbert在论坛中所述。)
创建热图的最佳方式是使用XYPlotXYBlockRendererXYZDataset,就像trashgod已经写过的那样。
下面是一个完整的、简洁的示例,您可以运行它以获得下面所示的图表:
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.LookupPaintScale;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;

import java.awt.*;
import java.util.Random;

public class HeatMapDemo extends ApplicationFrame
{
    public HeatMapDemo()
    {
        super("JFreeChart Heatmap Demo");
        final JFreeChart chart = createChart(createDataset());
        setContentPane(new ChartPanel(chart));
    }

    private static JFreeChart createChart(XYZDataset dataset)
    {
        // x-axis for time
        DateAxis xAxis = new DateAxis("Time");
        xAxis.setStandardTickUnits(DateAxis.createStandardDateTickUnits());
        xAxis.setLowerMargin(0);
        xAxis.setUpperMargin(0);

        // visible y-axis with symbols
        String labels[] = new String[500];
        for (int i = 0; i < 500; i++)
            labels[i] = "ca. " + i + "nm";
        SymbolAxis yAxis = new SymbolAxis(null, labels);
        yAxis.setTickUnit(new NumberTickUnit(50));

        // another invisible y-axis for scaling
        // (this is not necessary if your y-values are suitable) 
        NumberAxis valueAxis1 = new NumberAxis("Marker");
        valueAxis1.setLowerMargin(0);
        valueAxis1.setUpperMargin(0);
        valueAxis1.setVisible(false);

        // create a paint-scale and a legend showing it
        LookupPaintScale paintScale = new LookupPaintScale(0, 300, Color.black);
        Color c = Color.green;
        paintScale.add(0.0, c);
        paintScale.add(33.0, c = c.darker());
        paintScale.add(66.0, c.darker());
        paintScale.add(100.0, c = Color.blue);
        paintScale.add(133.0, c = c.darker());
        paintScale.add(166.0, c.darker());
        paintScale.add(200.0, c = Color.red.darker().darker());
        paintScale.add(233.0, c = c.brighter());
        paintScale.add(266.0, c.brighter());

        PaintScaleLegend psl = new PaintScaleLegend(paintScale, new NumberAxis());
        psl.setPosition(RectangleEdge.RIGHT);
        psl.setAxisLocation(AxisLocation.TOP_OR_RIGHT);
        psl.setMargin(50.0, 20.0, 80.0, 0.0);

        // finally a renderer and a plot
        XYPlot plot = new XYPlot(dataset, xAxis, yAxis, new XYBlockRenderer());
        ((XYBlockRenderer)plot.getRenderer()).setPaintScale(paintScale);
        // 2 optional lines, depending on your y-values
        plot.setRangeAxis(1, valueAxis1);
        plot.mapDatasetToRangeAxis(0, 1);

        JFreeChart chart = new JFreeChart(null, null, plot, false);
        chart.addSubtitle(psl);
        return chart;
    }

    public XYZDataset createDataset()
    {
        double[] xvalues = new double[1000*100]; // date
        double[] yvalues = new double[1000*100]; // numeric (1-100)
        double[] zvalues = new double[1000*100]; // numeric (the actual data)

        // create some random data
        final Random rand = new Random();
        long l = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            l -= 600000;
            for (int j = 0; j < 100; j++) {
                final int idx = i * 100 + j;
                xvalues[idx] = l;
                yvalues[idx] = j;
                double delta = rand.nextInt(15) * (rand.nextInt(4) == 0 ? -1 : 1);
                zvalues[idx] = Math.max(0, Math.min(300,
                    (idx < 1000 ? 0 : zvalues[idx - 1000]) + delta));
            }
        }

        DefaultXYZDataset dataset = new DefaultXYZDataset();
        dataset.addSeries("Just one Series", new double[][] { xvalues, yvalues, zvalues });
        return dataset;
    }

    public static void main(String args[])
    {
        final HeatMapDemo demo = new HeatMapDemo();
        demo.pack();
        demo.setVisible(true);
    }
}

生成的热力图如下所示:

heatmap

如果您需要一个更线性的PaintScale,可以看一下这个答案中的SpectrumPaintScale实现

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接