问题描述
我正在尝试在应用程序中实现蜘蛛图。为此,我使用了Spiderwebplot补丁文件。这解决了我的范围轴显示问题。但是在这里,我无法根据数据集的最小值和最大值动态更改轴值。 我期望输出为下图中的第二张图片。我想根据数据集值更改范围轴值和图形结构。
有关更多信息,我在下面共享我的示例代码段。
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");
在补丁文件中,我看到以下几行产生了轴范围值。
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);
如果需要,添加一个切换回零点定义的开关也可能是个好主意...