xAxis.setCategoryMargin(0.0); -> But there is still a margin

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
toki79
Posts: 2
Joined: Thu Oct 29, 2015 9:40 am
antibot: No, of course not.

xAxis.setCategoryMargin(0.0); -> But there is still a margin

Post by toki79 » Thu Oct 29, 2015 10:23 am

Hi,

my aim is to create an area chart. Issue is, that there slight vertical gridlines in the result and I don't understand why. Grid is deactivated.

Code: Select all

plot.setRangeGridlinesVisible(false);
plot.setDomainGridlinesVisible(false);
plot.setRangeMinorGridlinesVisible(false);
plot.setDomainCrosshairVisible(false);
So, those slight vertical lines have something to with

Code: Select all

xAxis.setCategoryMargin(0.0);

If I increase this value, the lines become bigger, however I would expect that they vanish with the value of 0.0.

I attach the complete class, which is runnable and will show the result.

Code: Select all



import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Iterator;

import javax.swing.JFrame;

import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFPictureData;
import org.apache.poi.xslf.usermodel.XSLFPictureShape;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.Axis;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.RingPlot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StackedAreaRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.ui.RefineryUtilities;
import org.jfree.util.ShapeUtilities;


public class ChartGenerator {
	
    public static void main(String args[]) {
    	//XSLFSlide slide = pptIO.getSlide("ENTWDQ");
        ChartGenerator cg = new ChartGenerator();
        
        DefaultCategoryDataset ds = new DefaultCategoryDataset();
        ds.addValue(0.2, "%", "Jan 15");
        ds.addValue(0.3, "%", "Feb 15");
        ds.addValue(0.4, "%", "Mrz 15");
        ds.addValue(0.5, "%", "Apr 15");
        ds.addValue(0.4, "%", "Mai 15");
        ds.addValue(0.2, "%", "Jun 15");
        ds.addValue(0.1, "%", "Jul 15");
        ds.addValue(0.3, "%", "Aug 15");
        ds.addValue(0.8, "%", "Sep 15");
        ds.addValue(0.85, "%", "Okt 15");
        ds.addValue(0.9, "%", "Nov 15");
        ds.addValue(1, "%", "Dez 15");
        
        double yellowBorder = 0.9;
        double redBorder = 0.8;
        
        
        JFreeChart chart = cg.buildAreaLineCombi_(ds, redBorder, yellowBorder, 300, 200);
        
        
//        DefaultPieDataset dat = new DefaultPieDataset();
//		dat.setValue("Korrekt", 0.8);
//		dat.setValue("Inkorrekt", 1 - 0.8);
//
//		int width = 20;
//		int height = 20;
//
//
//		JFreeChart chart = cg.buildPie_(dat, 0.8f, 0.4f, width, height );
 
        
        
        JFrame f = new JFrame();
        final ChartPanel chartPanel = new ChartPanel(chart);
       // chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        f.setContentPane(chartPanel);
        
  
        f.pack();
        RefineryUtilities.centerFrameOnScreen(f);
        f.setVisible(true);
        
        
    }
	
	private JFreeChart buildAreaLineCombi_(DefaultCategoryDataset dataset, double redBorder, double yellowBorder, int width, int height) {
		    double redB = redBorder;
	        double yellowB = yellowBorder - redBorder;
	        double greenB = 1 - yellowBorder;
	        
	        
	        // create the first dataset...
	        DefaultCategoryDataset datasetArea = new DefaultCategoryDataset();
	        Iterator<String> iter = dataset.getColumnKeys().iterator();
	        while (iter.hasNext()) {
	        	String column = iter.next();
	        	datasetArea.addValue(redB, "Red", column);
	        	datasetArea.addValue(yellowB, "Yellow", column);
	        	datasetArea.addValue(greenB, "Green", column);
	        }
	
	        // create the first renderer...
	  //      final CategoryLabelGenerator generator = new StandardCategoryLabelGenerator();
	        final CategoryItemRenderer areaRenderer = new StackedAreaRenderer();
	    //    renderer.setLabelGenerator(generator);
	        areaRenderer.setItemLabelsVisible(false);	        
	        areaRenderer.setSeriesPaint(0, Color.gray);
	        areaRenderer.setSeriesPaint(1, Color.BLACK); //Constants.YELLOW);
	        areaRenderer.setSeriesPaint(2, Color.GRAY);	  
	        
	        
	        final CategoryItemRenderer lineRenderer = new LineAndShapeRenderer();
	        lineRenderer.setSeriesPaint(0, Color.blue);
	        lineRenderer.setSeriesStroke(
	                0, new BasicStroke(
	                    3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND,
	                    1.0f, new float[] {1.0f, 0.0f}, 0.0f
	                )
	            );
	        lineRenderer.setSeriesShape(0, ShapeUtilities.createDiamond(0));
	        
	        final CategoryPlot plot = new CategoryPlot();
	        plot.setDataset(datasetArea);
	        plot.setRenderer(areaRenderer);
	        
	 
	        plot.setDomainAxis(new CategoryAxis("Category"));
	        plot.setDataset(1, dataset);
	        plot.setRenderer(1, lineRenderer);
	     // change the rendering order so the primary dataset appears "behind" the 
	        // other datasets...
	        plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
	        plot.setRangeAxis(new NumberAxis("Value"));
	        plot.setOrientation(PlotOrientation.VERTICAL);
	        plot.setRangeGridlinesVisible(false);
	        plot.setDomainGridlinesVisible(false);
	        plot.setRangeMinorGridlinesVisible(false);
	        plot.setDomainCrosshairVisible(false);
	    

	     
	
	        plot.setRangeGridlinePaint(Color.red);
	        plot.setDomainGridlinePaint(Color.red);
	        plot.setRangeMinorGridlinePaint(Color.RED);
//	        plot.setDomainGridlineStroke(lineRenderer.getSeriesStroke(0));
	        
	        
	        CategoryAxis xAxis = plot.getDomainAxis();
	        xAxis.setCategoryMargin(0.0);
	    
	        
	        
	        //domainAxis.setLabelAngle(90);
	        xAxis.setLabel(null);
	        xAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
	        //xAxis.setTickLabelFont(Color.FONT_CHART_LBL);
	        xAxis.setLowerMargin(0);
	        xAxis.setUpperMargin(0);	        


	        ValueAxis yAxis = plot.getRangeAxis();
	        yAxis.setRange(0, 1);
	        yAxis.setFixedAutoRange(0.2);
	        yAxis.setLabel(null);
	        //yAxis.setTickLabelFont(Color.FONT_CHART_LBL);
	        yAxis.setLowerBound(0.8f);

	        String numberFormat = "0%";
	        DecimalFormat df = new DecimalFormat(numberFormat);
            ((NumberAxis) yAxis).setNumberFormatOverride(df);
	    
	        //final XYLineAndShapeRenderer renderer2 = new XYLineAndShapeRenderer();


	        // create the third dataset and renderer...
	        final ValueAxis rangeAxis2 = new NumberAxis("Axis 2");
	        plot.setRangeAxis(1, rangeAxis2);
            rangeAxis2.setVisible(false);

	        
	        
	        //plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
	        final JFreeChart chart = new JFreeChart(plot);
	        

	        chart.setTitle("Overlaid Bar Chart");
	      //  chart.setLegend(new StandardLegend());
	        
	        chart.setTitle("");
	        chart.removeLegend();
	        chart.clearSubtitles();
	        chart.setBackgroundPaint(Color.white);

	        return chart;
	}
	

	
	public XSLFPictureShape buildAreaLineCombi(DefaultCategoryDataset dataset, double redBorder, double yellowBorder, XMLSlideShow ppt, XSLFSlide slide) throws IOException {
		float quality = 1; /* Quality factor */
int width = 400;
int height = 300;
		JFreeChart chart = buildAreaLineCombi_(dataset, redBorder, yellowBorder,  width, height);
//showChart(chart);				
		ByteArrayOutputStream chart_out = new ByteArrayOutputStream();
		
		//ChartUtilities.writeChartAsJPEG(chart_out, quality, chart, width, height);
		ChartUtilities.writeChartAsPNG(chart_out, chart, width, height);
		byte[] pictureData = chart_out.toByteArray();

FileOutputStream fout = new FileOutputStream("bild.png");
fout.write(pictureData);
fout.close();
	    XSLFPictureData pd = ppt.addPicture(pictureData, PictureData.PictureType.PNG);	    
	    XSLFPictureShape pic = slide.createPicture(pd);
        return pic;
	}
	
 	private void showChart(JFreeChart chart) {
 		JFrame f = new JFrame();
        final ChartPanel chartPanel = new ChartPanel(chart);
       // chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        f.setContentPane(chartPanel);
        
  
        f.pack();
        RefineryUtilities.centerFrameOnScreen(f);
        f.setVisible(true);
	}

	private Image createCircleBg(int width, int height) {
		BufferedImage img =
				  new BufferedImage(width, height,
				                    BufferedImage.TYPE_INT_ARGB);

		
				Graphics2D g2 = img.createGraphics();
		
                g2.setColor(Color.LIGHT_GRAY);
				g2.fillOval(0, 0, width, height);
		
		return img;
	}
	

}


david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: xAxis.setCategoryMargin(0.0); -> But there is still a ma

Post by david.gilbert » Sat Oct 31, 2015 8:04 am

These are rendering artefacts which do unfortunately make the resulting chart look bad. JFreeChart is displaying the data by calculating two polygons for each data item and calling Java2D to fill those polygons. Even though the two polygons have aligned edges, Java2D doesn't quite fill the space between them in some cases. One workaround is to switch off antialiasing using a rendering hint:

Code: Select all

chart.getRenderingHints().put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
That solves the problem for me, but it does have other impacts on the quality of the output.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

toki79
Posts: 2
Joined: Thu Oct 29, 2015 9:40 am
antibot: No, of course not.

Re: xAxis.setCategoryMargin(0.0); -> But there is still a ma

Post by toki79 » Fri Nov 20, 2015 3:11 pm

Hello David,

thank you for the Explanation. Setting Atialiasing off helped me with those lines, too. But as you mentioned, there are sideeffects. My lines are not smooth anymore.
Do you think, there is a solution without this drawback?

Regards,

Tobias

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: xAxis.setCategoryMargin(0.0); -> But there is still a ma

Post by david.gilbert » Tue Nov 24, 2015 5:45 pm

toki79 wrote:Do you think, there is a solution without this drawback?
I think the only approach that would work is to have the renderer calculate the area polygon that needs filling in one step for ALL data points, rather than filling individual polygons per data point. That's pretty much a rewrite of the renderer though, and not straightforward code to write.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

Locked