Цвет не синхронизируется с легендой - PullRequest
0 голосов
/ 11 января 2019

У меня есть 3D-набор данных XYZDataset, который я хочу построить как 2D-график, сохраняя координаты (x, y) и представляя ось z с использованием спектра цветов.

Основываясь на этом примере , вот мой класс построения вместе с классом цвета спектра.

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].

1 Ответ

0 голосов
/ 14 января 2019

Ваш обновленный пример создает XYBlockRenderer, как показано здесь , и применяет пользовательский PaintScale к визуализатору; шкала также используется для создания соответствующего PaintScaleLegend. После использования XYBlockRenderer для создания XYPlot исходный XYBlockRenderer отбрасывается и заменяется на XYLineAndShapeRenderer, который переопределяет getItemShape(). Новый XYLineAndShapeRenderer ничего не знает о PaintScale.

Вместо этого переопределите getItemFillPaint() в вашем XYLineAndShapeRenderer, как показано здесь . Вместо показанного 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);
    
  • Создание и управление объектами Swing GUI * только 1044 * в потоке отправки событий .

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);
        });
    }
}
...