如何在SpiderWebPlot中自定义范围轴值

问题描述

我正在尝试在应用程序中实现蜘蛛图。为此,我使用了Spiderwebplot补丁文件。这解决了我的范围轴显示问题。但是在这里,我无法根据数据集的最小值和最大值动态更改轴值。 我期望输出为下图中的第二张图片。我想根据数据集值更改范围轴值和图形结构。

enter image description here

有关更多信息,我在下面共享我的示例代码段。

package com.test;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.SpiderWebPlot;
import org.jfree.data.category.DefaultCategoryDataset;

public class DemoChart {
    public static JFreeChart createChart1() {
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        dataset.addValue(100.0,"Group A","Jan 19");
        dataset.addValue(99.97,"Aug 19");
        dataset.addValue(99.96,"Sep 19");
        dataset.addValue(99.98,"Oct 19");
        dataset.addValue(99.99,"Jul 19");
        SpiderWebPlotPatch o = new SpiderWebPlotPatch();
        SpiderWebPlot plot = o.getPlot(dataset);
        JFreeChart chart = new JFreeChart(plot);
        return chart;
    }
    public static void main(String args[]) throws IOException {
        JFreeChart jfreechart = createChart1();
        BufferedImage createBufferedImage = jfreechart.createBufferedImage(500,500);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ImageIO.write(createBufferedImage,"png",bos);
        byte[] byteArray = bos.toByteArray();
        try (FileImageOutputStream fos = new FileImageOutputStream(new File("C:\\Users\\abc\\Desktop\\abc.png"))) {
            fos.write(byteArray);
        }
    }
}

SpiderWebPlotPatch.java

package com.test;

import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;

import org.jfree.chart.plot.SpiderWebPlot;
import org.jfree.data.category.CategoryDataset;

public class SpiderWebPlotPatch {

    public SpiderWebPlot getPlot(CategoryDataset data) {
        final SpiderWebPlot plot = new SpiderWebPlot(data) {
            // put this many labels on each axis.
            private int ticks = DEFAULT_TICKS;
            private static final int DEFAULT_TICKS = 5;
            private NumberFormat format = NumberFormat.getInstance();
            // constant for creating perpendicular tick marks.
            private static final double PERPENDIculaR = 90;
            // the size of a tick mark,as a percentage of the entire line length.
            private static final double TICK_SCALE = 0.015;
            // the gap between the axis line and the numeric label itself.
            private int valueLabelGap = DEFAULT_GAP;
            private static final int DEFAULT_GAP = 10;
            // the threshold used for determining if something is "on" the axis
            private static final double THRESHOLD = 15;

            /**
             * {@inheritDoc}
             */
            @Override
            protected void drawLabel(final Graphics2D g2,final Rectangle2D plotArea,final double value,final int cat,final double startAngle,final double extent) {
                super.drawLabel(g2,plotArea,value,cat,startAngle,extent);
                final FontRenderContext frc = g2.getFontRenderContext();
                final double[] transformed = new double[2];
                final double[] transformer = new double[2];
                final Arc2D arc1 = new Arc2D.Double(plotArea,Arc2D.OPEN);
                for (int i = 1; i <= ticks; i++) {

                    final Point2D point1 = arc1.getEndPoint();

                    final double deltaX = plotArea.getCenterX();
                    final double deltaY = plotArea.getCenterY();
                    double labelX = point1.getX() - deltaX;
                    double labelY = point1.getY() - deltaY;

                    final double scale = ((double) i / (double) ticks);
                    final AffineTransform tx = AffineTransform.getScaleInstance(scale,scale);
                    // for getting the tick mark start points.
                    final AffineTransform pointTrans = AffineTransform.getScaleInstance(scale + TICK_SCALE,scale + TICK_SCALE);
                    transformer[0] = labelX;
                    transformer[1] = labelY;
                    pointTrans.transform(transformer,transformed,1);
                    final double pointX = transformed[0] + deltaX;
                    final double pointY = transformed[1] + deltaY;
                    tx.transform(transformer,1);
                    labelX = transformed[0] + deltaX;
                    labelY = transformed[1] + deltaY;

                    double rotated = (PERPENDIculaR);

                    AffineTransform rotateTrans = AffineTransform.getRotateInstance(Math.toradians(rotated),labelX,labelY);
                    transformer[0] = pointX;
                    transformer[1] = pointY;
                    rotateTrans.transform(transformer,1);
                    final double x1 = transformed[0];
                    final double y1 = transformed[1];

                    rotated = (-PERPENDIculaR);
                    rotateTrans = AffineTransform.getRotateInstance(Math.toradians(rotated),labelY);

                    rotateTrans.transform(transformer,1);

                    final Composite saveComposite = g2.getComposite();
                    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1.0f));

                    g2.draw(new Line2D.Double(transformed[0],transformed[1],x1,y1));

                    if (startAngle == this.getStartAngle()) {
                        final String label = format.format(((double) i / (double) ticks) * this.getMaxValue());
                        final Rectangle2D labelBounds = getLabelFont().getStringBounds(label,frc);

                        final LineMetrics lm = getLabelFont().getLineMetrics(label,frc);
                        final double ascent = lm.getAscent();

                        // move based on quadrant.
                        if (Math.abs(labelX - plotArea.getCenterX()) < THRESHOLD) {
                            // on Y Axis,label to right.
                            labelX += valueLabelGap;
                            // center vertically.
                            labelY += ascent / (float) 2;
                        } else if (Math.abs(labelY - plotArea.getCenterY()) < THRESHOLD) {
                            // on X Axis,label underneath.
                            labelY += valueLabelGap;
                        } else if (labelX >= plotArea.getCenterX()) {
                            if (labelY < plotArea.getCenterY()) {
                                // quadrant 1
                                labelX += valueLabelGap;
                                labelY += valueLabelGap;
                            } else {
                                // quadrant 2
                                labelX -= valueLabelGap;
                                labelY += valueLabelGap;
                            }
                        } else {
                            if (labelY > plotArea.getCenterY()) {
                                // quadrant 3
                                labelX -= valueLabelGap;
                                labelY -= valueLabelGap;
                            } else {
                                // quadrant 4
                                labelX += valueLabelGap;
                                labelY -= valueLabelGap;
                            }
                        }
                        g2.setPaint(getLabelPaint());
                        g2.setFont(getLabelFont());
                        g2.drawString(label,(float) labelX,(float) labelY);
                    }
                    g2.setComposite(saveComposite);
                }
            }

            /**
             * sets the number of tick marks on this spider chart.
             * 
             * @param ticks the new number of tickmarks.
             */
            public void setTicks(final int ticks) {
                this.ticks = ticks;
            }

            /**
             * sets the numberformat for the tick labels on this spider chart.
             * 
             * @param format the new number format object.
             */
            public void setFormat(final NumberFormat format) {
                this.format = format;
            }

        };
        return plot;
    }

}

使用不同的数据集值

// dataset 1
dataset.addValue(100.0,"Jan 19");
dataset.addValue(99.97,"Aug 19");
dataset.addValue(99.96,"Sep 19");
dataset.addValue(99.98,"Oct 19");
dataset.addValue(99.99,"Jul 19");   
//dataset 2
dataset.addValue(100.0,"Oct 19");
dataset.addValue(50.0,"Jul 19");

enter image description here

在补丁文件中,我看到以下几行产生了轴范围值。

 final String label = format.format(((double)i/(double)ticks)*this.getMaxValue());
 final Rectangle2D labelBounds = getLabelFont().getStringBounds(label,frc);
 final LineMetrics lm = getLabelFont().getLineMetrics(label,frc);

解决方法

您只需要更改绘图例程“drawRadarPoly”和“drawLabel”中的以下代码

“draw”中的原始代码行:

Point2D point = getWebPoint(plotArea,angle,value / this.getMaxValue());

进入

Plot2D point = getWebPoint(plotArea,(value-this.getMinValue()) / this.getMaxValue() - this.getMinValue))

为此,您显然需要确定要使用的数据集的最小值,但这可以像确定最大值一样完成。

对于“drawLabel”方法你需要改变

final String label = format.format((double)i/(double)ticks)*this.getMaxValue());

进入

final String label = format.format(this.getMinValue()+((this.getMaxValue()-this.getMinValue))/ticks)*i);

如果需要,添加一个切换回零点定义的开关也可能是个好主意...