我想根据条形图所代表的bin中是否包含特定值来突出显示条形图。例如,如果下面的红色条表示100-110(含)之间的值的数量,则感兴趣的特定值是103.我想突出显示该条(将其更改为与其他颜色不同的颜色吧)即红色而不是蓝色
我想过继承
org.jfree.data.statistics.HistogramDataset
与XYBarRenderer的子类一起使用以利用
org.jfree.chart.renderer.xy.XYItemRendererState#startSeriesPass
方法。我的想法是,我可以创建两个具有不同基色的相同系列。并配置startSeriesPass方法以绘制第一个系列中的所有条形(bin),除了需要突出显示的栏。然后在下一次迭代期间仅绘制需要从第二个系列突出显示的条。
这已经证明非常困难,因为org.jfree.data.statistics.HistogramDataset将它的getBins方法定义为包保护,我想这是设计的。
基于此我想知道是否有一种规范的方法来改变histogramDataset中特定条形的颜色
答案 0 :(得分:1)
除了突出显示直方图数据集中的条形
之外,下面的控制器还可以执行多项操作package com.capitalone.mobile.orx.jchartpoc.controller;
import java.awt.Color;
import java.awt.Font;
import java.awt.Paint;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYPointerAnnotation;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.statistics.HistogramBin;
import org.jfree.data.statistics.HistogramDataset;
import org.jfree.ui.RectangleInsets;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Norbert Powell
* Created on Dec 21, 2016
*/
@RestController
public class HistogramController {
public class HistogramPlotGenerator {
private double upperBound;
private double minimum;
private double maximum;
private int bins = 10;
public class RelativeSpendRenderer extends XYBarRenderer{
private static final long serialVersionUID = 1L;
@Getter @Setter
private int userSpendLevelBarColumn;
@Getter @Setter
private Color userSpendLevelBarColumnColor = new Color(208,48,39);
public RelativeSpendRenderer(int usplCol) {
this.userSpendLevelBarColumn = usplCol;
}
@Override
public Paint getItemPaint(int row, int column) {
if (column == userSpendLevelBarColumn){
return userSpendLevelBarColumnColor;
}
return super.getItemPaint(row, column);
}
}
public JFreeChart createHisto(){
long chartCreationTime = System.currentTimeMillis();
HistogramDataset histogramDataSet = new HistogramDataset();
List<Number> spendLevels =
Arrays.asList(12,21,34,3,24,56,7,8,9,100,75,555,65,32,566,700,800,900,307,1000,10201,222,323,444,201,111);
double userSpendLevelValue = spendLevels.get(10).doubleValue(); // point to be highlighted
double [] spls = new double [spendLevels.size()];
minimum = Double.MAX_VALUE;
maximum = 0.0;
for(int i=0; i < spendLevels.size(); i++){
double spl = spendLevels.get(i).doubleValue();
maximum = Math.max(maximum,spl);
minimum = Math.min(minimum, spl);
spls[i] = spl;
}
upperBound = 0.0;
histogramDataSet.addSeries("Spend", spls, bins,minimum,maximum);
for ( int i=0; i <bins; i++){
upperBound = Math.max(histogramDataSet.getYValue(0, i), upperBound);
}
JFreeChart barGraph = ChartFactory.createHistogram(null, "$$$", null, histogramDataSet, PlotOrientation.VERTICAL, false, false, false);
System.out.println("Time to create bar chart: " + (System.currentTimeMillis() - chartCreationTime)+"ms");
int userSpendBarIndex = getHighlightBar(userSpendLevelValue);
XYPlot plot = barGraph.getXYPlot();
plot.setRenderer(new RelativeSpendRenderer(userSpendBarIndex));
placePointer(histogramDataSet, userSpendBarIndex, plot);
modifyChart(barGraph);
return barGraph;
}
private void placePointer(HistogramDataset histogramDataSet,int userSpendBarIndex, XYPlot plot) {
double x =histogramDataSet.getX(0, userSpendBarIndex).doubleValue();
double y = histogramDataSet.getY(0, userSpendBarIndex).doubleValue();
double angle = (3*Math.PI/2);
XYPointerAnnotation arrow = new XYPointerAnnotation(" ", x, y, angle);
arrow.setTipRadius(0); // distance of arrow head from bar
arrow.setBaseRadius(10);// distance from arrow head to end of arrow if arrowLength and BaseRadius are > 0 and arrowLength > BaseRadius only the arrow head will be shown
if (y == upperBound){
plot.getRangeAxis().setUpperBound(upperBound + arrow.getBaseRadius());
}else{
plot.getRangeAxis().setUpperBound(upperBound);
}
plot.addAnnotation(arrow);
}
private int getHighlightBar(double userSpendValue){
int highlightBarIndex=0;
double binWidth = (maximum - minimum) / bins;
double lower = minimum;
double upper;
ArrayList<HistogramBin> binList = new ArrayList<HistogramBin>(bins);
for (int i = 0; i < bins; i++) {
HistogramBin bin;
// make sure bins[bins.length]'s upper boundary ends at maximum
// to avoid the rounding issue. the bins[0] lower boundary is
// guaranteed start from min
if (i == bins - 1) {
bin = new HistogramBin(lower, maximum);
}
else {
upper = minimum + (i + 1) * binWidth;
bin = new HistogramBin(lower, upper);
lower = upper;
}
binList.add(bin);
}
for(HistogramBin bin : binList){
if (userSpendValue >= bin.getStartBoundary() && userSpendValue <= bin.getEndBoundary()){
return highlightBarIndex;
}
highlightBarIndex++;
}
return -1;
}
private void modifyChart(JFreeChart chart) {
Color lineChartColor = new Color(1, 158, 213);
// plot manipulations
XYPlot xyPlotModifier = chart.getXYPlot();
xyPlotModifier.setOutlineVisible(false);
xyPlotModifier.setRangeMinorGridlinesVisible(false);
xyPlotModifier.setRangeCrosshairVisible(false);
xyPlotModifier.setRangeGridlinesVisible(false);
xyPlotModifier.setRangeZeroBaselineVisible(false);
xyPlotModifier.setBackgroundPaint(Color.WHITE);
xyPlotModifier.getDataset().getSeriesCount();
//Axis modifications
xyPlotModifier.getRangeAxis().setVisible(false);
xyPlotModifier.getDomainAxis().setTickLabelsVisible(false);
xyPlotModifier.getDomainAxis().setMinorTickMarksVisible(false);
xyPlotModifier.getDomainAxis().setTickMarksVisible(false);
xyPlotModifier.getDomainAxis().setLabelFont(new Font("SansSerif", Font.PLAIN, 1));
xyPlotModifier.setAxisOffset(new RectangleInsets(0.0,0.0,0.0,0.0));
// Actual data point manipulations
XYBarRenderer renderer = (XYBarRenderer) xyPlotModifier.getRenderer();
renderer.setSeriesPaint(0,lineChartColor, true);
renderer.setBaseOutlinePaint(Color.BLACK, true);
renderer.setDrawBarOutline(true);
chart.removeLegend();
}
}
@RequestMapping(value = "getHisto", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public ResponseEntity<byte[]> getPNGChart(@RequestHeader HttpHeaders headers)throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
HistogramPlotGenerator generator = new HistogramPlotGenerator();
ChartUtilities.writeBufferedImageAsPNG(baos, generator.createHisto().createBufferedImage(352, 90));
return new ResponseEntity<byte[]>(baos.toByteArray(), HttpStatus.OK);
}
}
getHighLightBar
和
RelativeSpendRenderer类
协同工作以生成需要突出显示的条形索引,并在打印时搜索索引以突出显示它。
placePointer方法考虑了放在最高栏上的指针,并确保指针不会被截断
答案 1 :(得分:0)