java - 颜色与图例不同步

标签 java jfreechart

我有一个 3D 数据集 XYZDataset我想通过保留 (x,y) 坐标并使用颜色光谱表示 z 轴来绘制为 2D 图。

基于此example ,这是我的绘图类以及光谱颜色类。

package com.ingilab.algo.comparator.tools.plot;

import java.awt.Color;
import java.awt.Paint;
import java.awt.Shape;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.PaintScale;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.util.ShapeUtilities;

public class Plot2D extends ApplicationFrame {

    private static final int N = 100;

    /**
     * A demonstration application showing an XY series containing a null value.
     *
     * @param title  the frame title.
     */
    final XYSeries series;

    public Plot2D(final String title, String X, String Y, XYSeries series) {

        super(title);
        this.series = series;

        final XYSeriesCollection data = new XYSeriesCollection(series);

        final JFreeChart chart = ChartFactory.createScatterPlot(
            title,
            X, 
            Y, 
            data,
            PlotOrientation.VERTICAL,
            true,
            true,
            false
        );

        final ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        setContentPane(chartPanel);

    }

    public Plot2D (final String title, JFreeChart chart) {
        super(title);
        series = null;

        final ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        setContentPane(chartPanel); 
    }


    /** 
     * Creates a sample chart. 
     *  
     * @param dataset  the dataset. 
     * @param max 
     *  
     * @return A sample chart. 
     */ 
    public static JFreeChart createChart(XYZDataset dataset, 
            String title, String x, String y, String z, double max) { 
        NumberAxis xAxis = new NumberAxis(x); 
        xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); 
        xAxis.setLowerMargin(0.0); 
        xAxis.setUpperMargin(0.0); 
        NumberAxis yAxis = new NumberAxis(y); 
        yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); 
        yAxis.setLowerMargin(0.0); 
        yAxis.setUpperMargin(0.0); 

        XYBlockRenderer renderer = new XYBlockRenderer();
        SpectrumPaintScale scale = new SpectrumPaintScale(0, max);
        //PaintScale scale = new GrayPaintScale(-2.0, 1.0); 
        renderer.setPaintScale(scale); 

        //Z axis
        NumberAxis scaleAxis = new NumberAxis(z);
        scaleAxis.setAxisLinePaint(Color.white);
        scaleAxis.setTickMarkPaint(Color.white);
        PaintScaleLegend legend = new PaintScaleLegend(scale, scaleAxis);
        legend.setSubdivisionCount(128);
        legend.setAxisLocation(AxisLocation.TOP_OR_RIGHT);
        legend.setPadding(new RectangleInsets(10, 10, 10, 10));
        legend.setStripWidth(20);
        legend.setPosition(RectangleEdge.RIGHT);
        legend.setBackgroundPaint(Color.WHITE);

        XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer); 
        plot.setBackgroundPaint(Color.lightGray); 
        plot.setDomainGridlinesVisible(false); 
        plot.setRangeGridlinePaint(Color.white); 
        plot.setRenderer(new XYLineAndShapeRenderer(false, true) {

            @Override
            public Shape getItemShape(int row, int col) {
                    return ShapeUtilities.createDiagonalCross(5, 2);
            }
        });

        JFreeChart chart = new JFreeChart(title, plot); 
        chart.addSubtitle(legend);
        chart.removeLegend(); 
        chart.setBackgroundPaint(Color.white); 

        return chart; 
    } 


    ////////////////////////////////////
    //                                //
    //         PaintScaleColor        //
    //                                //
    ////////////////////////////////////

    private static class SpectrumPaintScale implements PaintScale {

        private static final float H1 = 0f;
        private static final float H2 = 1f;
        private final double lowerBound;
        private final double upperBound;

        public SpectrumPaintScale(double lowerBound, double upperBound) {
            this.lowerBound = lowerBound;
            this.upperBound = upperBound;
        }

        @Override
        public double getLowerBound() {
            return lowerBound;
        }

        @Override
        public double getUpperBound() {
            return upperBound;
        }

        @Override
        public Paint getPaint(double value) {
            float scaledValue = (float) (value / (getUpperBound() - getLowerBound()));
            float scaledH = H1 + scaledValue * (H2 - H1);
            return Color.getHSBColor(scaledH, 1f, 1f);
        }
    }
    public static void main(String[] args) 
    {   
        final DefaultXYZDataset timePerSizePerChrno = new 
        DefaultXYZDataset();

        ydb [0][1] = 1;
        ydb [1][1] = 78.0;
        ydb [2][1] = 1341.0;

        ydb [0][2] = 2;
        ydb [1][2] = 100.0;
        ydb [2][2] = 475.0;

        ydb [0][1] = 3;
        ydb [1][1] = 9215.0;
        ydb [2][1] = 684.0;

        ydb [0][1] = 4;
        ydb [1][1] = 90.0;
        ydb [2][1] = 251.0;

        ydb [0][1] = 5;
        ydb [1][1] = 75.0;
        ydb [2][1] = 7022.0;

        double maxZ = 7022;
        timePerSizePerChrno.addSeries("Series", ydb);

        //////////////////////////////////////////
        //         PLOTING RESUlTS              // 
        //////////////////////////////////////////
        final Plot2D plot3 = new Plot2D("Loading Performance Color Map", Plot2D.createChart (timePerSizePerChrno, 
                "Loading Performance Color Map", "Order Call", "Time in Ms", "Size in Ko", maxZ));
        plot3.pack();
        RefineryUtilities.centerFrameOnScreen(plot3);
        plot3.setVisible(true); 
    }
}

我遇到的问题是颜色光谱应用于 XYZDataset系列而不是 z 值(我的数据集中有一个独特的系列)。

enter image description here

例如上图。您可以看到所有点都是红色的,我希望它们根据它们的值映射到右侧的色谱。我还想删除光谱末端的红色,因为它可能会令人困惑(光谱以红色开始和结束)。

对于给定系列如何使用色谱绘制不同点 (x,y) 的任何猜测,知道 z 值在 [0, maxZ] 之间。

最佳答案

您更新的示例创建了 XYBlockRenderer ,如图here ,并应用自定义 PaintScale到渲染器;该比例还用于创建匹配的 PaintScaleLegend 。使用XYBlockRenderer后创建 XYPlot ,原文XYBlockRenderer被丢弃并替换为 XYLineAndShapeRenderer ,它覆盖 getItemShape() 。新XYLineAndShapeRendererPaintScale一无所知.

相反,覆盖 getItemFillPaint()在你的XYLineAndShapeRenderer ,如图here 。而不是List<Color>如图所示,使用 getPaint()您定制的方法PaintScale插入所需的 Shape每个数据点的颜色基于其相应的 z 值。

XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(false, true) {
    @Override
    public Paint getItemFillPaint(int row, int col) {
        return scale.getPaint(dataset.getZValue(row, col));
    }
    …
};

此外,

  • 要获得不同的光谱,请在 PaintScale 中指定所需的边界色调。 .

    private static final float H1 = 0f;
    private static final float H2 = (float) (Math.PI / 8);
    
  • 使用DatasetUtils.findZBounds()确定数据集范围。

    Range r = DatasetUtils.findZBounds(dataset);
    
  • event dispatch thread 上构造和操作 Swing GUI 对象.

plot

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Paint;
import java.awt.Shape;
import javax.swing.JFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.PaintScale;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.Range;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.data.xy.XYZDataset;
import org.jfree.chart.ui.RectangleEdge;
import org.jfree.chart.ui.RectangleInsets;
import org.jfree.chart.util.ShapeUtils;
import org.jfree.data.general.DatasetUtils;

/**
 * @see https://stackoverflow.com/a/54180207/230513
 * @see https://stackoverflow.com/a/37235165/230513
 */
public class Plot2D {

    public static JFreeChart createChart(XYZDataset dataset,
        String title, String x, String y, String z, Range r) {
        NumberAxis xAxis = new NumberAxis(x);
        xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        NumberAxis yAxis = new NumberAxis(y);
        yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        SpectrumPaintScale scale = new SpectrumPaintScale(r);
        NumberAxis scaleAxis = new NumberAxis(z);
        scaleAxis.setAxisLinePaint(Color.white);
        scaleAxis.setTickMarkPaint(Color.white);
        PaintScaleLegend legend = new PaintScaleLegend(scale, scaleAxis);
        legend.setSubdivisionCount(128);
        legend.setAxisLocation(AxisLocation.TOP_OR_RIGHT);
        legend.setPadding(new RectangleInsets(10, 10, 10, 10));
        legend.setStripWidth(20);
        legend.setPosition(RectangleEdge.RIGHT);
        legend.setBackgroundPaint(Color.WHITE);
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(false, true) {
            @Override
            public Paint getItemFillPaint(int row, int col) {
                return scale.getPaint(dataset.getZValue(row, col));
            }

            @Override
            public Shape getItemShape(int row, int col) {
                return ShapeUtils.createDiagonalCross(5, 2);
            }
        };
        renderer.setUseFillPaint(true);
        renderer.setSeriesShapesFilled(0, true);
        renderer.setSeriesShapesVisible(0, true);
        XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
        plot.setBackgroundPaint(Color.lightGray);
        plot.setDomainGridlinesVisible(false);
        plot.setRangeGridlinePaint(Color.white);
        plot.setRenderer((renderer));

        JFreeChart chart = new JFreeChart(title, plot);
        chart.addSubtitle(legend);
        chart.removeLegend();
        chart.setBackgroundPaint(Color.white);

        return chart;
    }

    private static class SpectrumPaintScale implements PaintScale {

        private static final float H1 = 0f;
        private static final float H2 = (float) (Math.PI / 8);
        private final Range range;

        public SpectrumPaintScale(Range r) {
            this.range = r;
        }

        @Override
        public double getLowerBound() {
            return range.getLowerBound();
        }

        @Override
        public double getUpperBound() {
            return range.getUpperBound();
        }

        @Override
        public Paint getPaint(double value) {
            float scaledValue = (float) (value / (getUpperBound() - getLowerBound()));
            float scaledH = H1 + scaledValue * (H2 - H1);
            return Color.getHSBColor(scaledH, 1f, 1f);
        }
    }

    public static void main(String[] args) {
        double xyz[][] = {
            {    1,    2,    3,    4,    5 }, // x
            { 1000, 3000, 9215, 4000, 1000 }, // y
            { 1341,  500, 3125, 1000, 7022 }  // z
        };
        final DefaultXYZDataset dataset = new DefaultXYZDataset();
        dataset.addSeries("Series", xyz);
        Range r = DatasetUtils.findZBounds(dataset);
        EventQueue.invokeLater(() -> {
            JFrame f = new JFrame("Color Map");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JFreeChart chart = Plot2D.createChart(dataset, "Color Map",
                "Order Call", "Time in Ms", "Size in Ko", r);
            f.add(new ChartPanel(chart) {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(600, 300);
                }
            });
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        });
    }
}

关于java - 颜色与图例不同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54150496/

相关文章:

java - JFreeChart确定网格的尺寸

java - Systemd:添加 logback 后无法启动 spring boot

java - 如何在 Jasper Report 中向条形图添加水平线?

java - Java 项目中服务器和客户端包的共享资源

java - 为什么我会收到 "classes must have either one (and only one) constructor"错误?

java - StackedBarchart 中不同行键的自定义颜色

grails - Grails JFreeChart无法解析类:org.jfree.chart.ChartFactory

java - 将 JFreeChart 添加到 JPanel

java - 如何使用 Unirest 将数据从 Vaadin 发布到 Vertx?

java - 当我们执行 Modelservice.Save() 时,Hybris 会做什么?