如何显示具有不同颜色的单个直方图条

时间:2016-12-12 16:22:57

标签: java histogram jfreechart highlighting

我创建了一个带有JfreeChart的直方图,看起来像这样enter image description here

我想根据条形图所代表的bin中是否包含特定值来突出显示条形图。例如,如果下面的红色条表示100-110(含)之间的值的数量,则感兴趣的特定值是103.我想突出显示该条(将其更改为与其他颜色不同的颜色吧)即红色而不是蓝色

enter image description here

我想过继承

  

org.jfree.data.statistics.HistogramDataset

与XYBarRenderer的子类一起使用以利用

  

org.jfree.chart.renderer.xy.XYItemRendererState#startSeriesPass

方法。我的想法是,我可以创建两个具有不同基色的相同系列。并配置startSeriesPass方法以绘制第一个系列中的所有条形(bin),除了需要突出显示的栏。然后在下一次迭代期间仅绘制需要从第二个系列突出显示的条。

这已经证明非常困难,因为org.jfree.data.statistics.HistogramDataset将它的getBins方法定义为包保护,我想这是设计的。

基于此我想知道是否有一种规范的方法来改变histogramDataset中特定条形的颜色

2 个答案:

答案 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)

选中此Link

    final CategoryItemRenderer renderer = new CustomRenderer(
        new Paint[] {Color.blue, Color.blue, Color.blue,
            Color.red, Color.blue, Color.blue,
            Color.blue, Color.blue}
    );

只提供特殊栏的特定颜色

您也可以查看this