piechart border obscruring legend

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
tonyGriffiths
Posts: 11
Joined: Wed Jun 21, 2006 10:38 am

piechart border obscruring legend

Post by tonyGriffiths » Wed Jan 24, 2007 12:00 pm

I've added a customised legend as a subtitle as per the legendwrappeddemo example. I use the following code:

Code: Select all

		JFreeChart chart = (JFreeChart) _chart;
		PiePlot plot = (PiePlot) chart.getPlot();
		
		// Chart
		plot.setOutlinePaint(null);
		
		// Title
		chart.getTitle().setFont(new Font("SansSerif", Font.BOLD, 12));
		
		// Section labels		
		plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} ({2})"));
		plot.setLabelBackgroundPaint(new Color(220, 220, 220));
		plot.setLabelFont(new Font("SansSerif", Font.PLAIN, 8));
				
		StandardPieSectionLabelGenerator slbl = new StandardPieSectionLabelGenerator( 
		         "{0}={2}", 
		         new DecimalFormat("#,##0"), 
		         new DecimalFormat("0%")); 
		plot.setLabelGenerator(slbl);
		plot.setLegendLabelGenerator(slbl);

		plot.setInteriorGap(0.1);
		
		chart.removeLegend();
		
		LegendTitle legend = new LegendTitle(chart.getPlot());
        legend.setItemFont(new Font("SansSerif", Font.PLAIN, 10));
        BlockContainer wrapper = new BlockContainer(new BorderArrangement());
        wrapper.setBorder(new BlockBorder(1.0, 1.0, 1.0, 1.0));
        
        StringBuffer subtitleBuffer = new StringBuffer();
        subtitleBuffer.append("(");
        
        boolean needsComma = false;
        for(int k=0;k<wellTypesToDisplay.size();k++) {
        	
        	if(needsComma == true) subtitleBuffer.append(", ");
        	if(((k+1)%5) == 0) subtitleBuffer.append("\n");
        	
        	subtitleBuffer.append(wellTypesToDisplay.get(k));
        	
        	needsComma = true;
        }
        subtitleBuffer.append(" Wells) = " + this.numberOfWells + " Wells");
        
        LabelBlock subtitle = new LabelBlock(subtitleBuffer.toString());
        subtitle.setFont(new Font("SansSerif", Font.PLAIN, 8));
        subtitle.setPadding(5, 5, 2, 5);
        wrapper.add(subtitle, RectangleEdge.BOTTOM);
However when I generate the chart I get the legend text being obscured by the border for the legend, i.e., the border rectangle is too small to completely enclose the test, so that the text is written over the border.

[img]
http://www.intetech.com/images/borderExample.bmp
[/img]

Any ideas how to get rid of the nasty overlap?

Thanks,

Tony

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

Post by david.gilbert » Wed Jan 24, 2007 4:09 pm

I'm not sure about this. Do you have some runnable code I can try?
David Gilbert
JFreeChart Project Leader

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

tonyGriffiths
Posts: 11
Joined: Wed Jun 21, 2006 10:38 am

Post by tonyGriffiths » Wed Jan 24, 2007 4:29 pm

It's tricky as this is a custmizer for a cewolf servlet.

The customizer could be constructed as:

Code: Select all

String[] wellTypesToDisplay = {
  "production",
  "injection",
  "waste disposal"
};
int numberOfWells = 100;

  DatasetProducer pieTotalsData = new DatasetProducer() {
    public Object produceDataset(Map params) {
      DefaultPieDataset dataset = new DefaultPieDataset();
        dataset.setValue("One", 43.2);
        dataset.setValue("Two", 10.0);
        dataset.setValue("Three", 27.5);
        dataset.setValue("Four", 17.5);
        dataset.setValue("Five", 11.0);
        dataset.setValue("Six", 19.4);

       return dataset;
    }
    
    public String getProducerId() {
      return "pieTotalsDataProducer";
    }
    
    public boolean hasExpired(Map params, Date since) {
      return true;
    }
  };
  pageContext.setAttribute("pieTotalsData", pieTotalsData);

KPIPieGraphCustomizer pieTotalsGraphDataPP = new KPIPieGraphCustomizer(kpi, wellTypesToDisplay, numberOfWells); 
pageContext.setAttribute("pieTotalsGraphDataPP", pieTotalsGraphDataPP);
Here's a cut down versio of the code for the customizer class:

Code: Select all

import java.text.DecimalFormat;
import java.util.*;
import java.awt.*;

import org.jfree.chart.*;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.block.BlockContainer;
import org.jfree.chart.block.BorderArrangement;
import org.jfree.chart.block.LabelBlock;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.*;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.ui.HorizontalAlignment;
import org.jfree.ui.RectangleEdge;

public class KPIPieGraphCustomizer implements ChartPostProcessor {

	private String kpi;
	private IWITSettings settings;
	private int numberOfWells;
	private ArrayList<String> wellTypesToDisplay;
	
	public KPIPieGraphCustomizer(String kpi, int numberOfWells) {
		this.kpi = kpi; 
		this.numberOfWells = numberOfWells;
	}

	public KPIPieGraphCustomizer(String kpi, ArrayList<String> wellTypes, int numberOfWells) { 
		this(kpi, numberOfWells);
		
		this.wellTypesToDisplay = wellTypes;
	}
	
	public KPIPieGraphCustomizer(String kpi, String wellType, int numberOfWells) { 
		this(kpi, numberOfWells);
		
		ArrayList<String> wellTypes = new ArrayList<String>();
		wellTypes.add(wellType);
		
		this.wellTypesToDisplay = wellTypes;
	}

	public void processChart(Object _chart, Map params) {
		JFreeChart chart = (JFreeChart) _chart;
		PiePlot plot = (PiePlot) chart.getPlot();
		
		// Chart
		plot.setOutlinePaint(null);
		
		// Title
		chart.getTitle().setFont(new Font("SansSerif", Font.BOLD, 12));
		
		// Section labels		
		plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} ({2})"));
		plot.setLabelBackgroundPaint(new Color(220, 220, 220));
		plot.setLabelFont(new Font("SansSerif", Font.PLAIN, 8));
				
		StandardPieSectionLabelGenerator slbl = new StandardPieSectionLabelGenerator( 
		         "{0}={2}", 
		         new DecimalFormat("#,##0"), 
		         new DecimalFormat("0%")); 
		plot.setLabelGenerator(slbl);
		plot.setLegendLabelGenerator(slbl);

		plot.setInteriorGap(0.12);
		
		chart.removeLegend();
		
		LegendTitle legend = new LegendTitle(chart.getPlot());
        legend.setItemFont(new Font("SansSerif", Font.PLAIN, 10));
        BlockContainer wrapper = new BlockContainer(new BorderArrangement());
        wrapper.setBorder(new BlockBorder(1.0, 1.0, 1.0, 1.0));
        
        StringBuffer subtitleBuffer = new StringBuffer();
        subtitleBuffer.append("(");
        
        boolean needsComma = false;
        for(int k=0;k<wellTypesToDisplay.size();k++) {
        	
        	if(needsComma == true) subtitleBuffer.append(", ");
        	if(((k+1)%5) == 0) subtitleBuffer.append("\n");
        	
        	subtitleBuffer.append(wellTypesToDisplay.get(k));
        	
        	needsComma = true;
        }
        subtitleBuffer.append(" Wells) = " + this.numberOfWells + " Wells");
        
        LabelBlock subtitle = new LabelBlock(subtitleBuffer.toString());
        subtitle.setFont(new Font("SansSerif", Font.PLAIN, 8));
        subtitle.setPadding(5, 5, 2, 5);
        wrapper.add(subtitle, RectangleEdge.BOTTOM);
        
        // *** this is important - you need to add the item container to
        // the wrapper, otherwise the legend items won't be displayed when
        // the wrapper is drawn... ***
        BlockContainer items = legend.getItemContainer();
        items.setPadding(2, 10, 5, 2);
        wrapper.add(items);
        legend.setWrapper(wrapper);
        
        legend.setPosition(RectangleEdge.BOTTOM);
        legend.setHorizontalAlignment(HorizontalAlignment.CENTER);
        legend.setBorder(new BlockBorder(new Color(0,0,0,0)));
        chart.addSubtitle(legend);
        
        chart.fireChartChanged();
		
		if(true) {
			// RED, AMBER, GREEN
			plot.setSectionPaint(0, Color.RED);
			plot.setSectionPaint(1, new Color(153, 204, 0));
			plot.setSectionPaint(2, Color.GREEN);

		} 

		plot.setNoDataMessage("No data available");

	}

}

The jsp to display this would be:

Code: Select all

			<cewolf:chart id="totalsPieChart" title="<%=totalsHeader%>" type="pie">
				<cewolf:colorpaint color="#FFFFFF"/>
    			<cewolf:data>
    				<cewolf:chartpostprocessor id="pieTotalsGraphDataPP"></cewolf:chartpostprocessor>
					<cewolf:producer id="pieTotalsData" />
				</cewolf:data>
			</cewolf:chart>
			<cewolf:img chartid="totalsPieChart" renderer="/cewolf" width="300" height="300"/>
Is this enough?

Thanks

Tony

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

Post by david.gilbert » Wed Jan 24, 2007 4:38 pm

If you can get this into something I can cut, paste, compile and run as a client application, then I'm more likely to look at it.
David Gilbert
JFreeChart Project Leader

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

tonyGriffiths
Posts: 11
Joined: Wed Jun 21, 2006 10:38 am

Post by tonyGriffiths » Wed Jan 24, 2007 5:30 pm

This runs ok, and demonstrates the problem

Tony

Code: Select all

import java.awt.Color;
import java.awt.Font;
import java.text.DecimalFormat;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.block.BlockContainer;
import org.jfree.chart.block.BorderArrangement;
import org.jfree.chart.block.LabelBlock;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.ui.HorizontalAlignment;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RefineryUtilities;

public class PieChartTest extends JFrame {

	private int numberOfWells;
	private ArrayList<String> wellTypesToDisplay;
	
    /**
     * Default constructor.
     *
     * @param title  the frame title.
     */
    public PieChartTest(String title, ArrayList<String> wellTypes, int numberOfWells) {
        super(title);
        
        this.wellTypesToDisplay = wellTypes;
        this.numberOfWells = numberOfWells;
        
        JPanel chartPanel = this.createDemoPanel();
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        setContentPane(chartPanel);
    }
    
    /**
     * Creates a sample dataset.
     * 
     * @return A sample dataset.
     */
    private static PieDataset createDataset() {
        DefaultPieDataset dataset = new DefaultPieDataset();
        dataset.setValue("One", 43.2);
        dataset.setValue("Two", 10.0);
        dataset.setValue("Three", 27.5);
        dataset.setValue("Four", 17.5);
        dataset.setValue("Five", 11.0);
        dataset.setValue("Six", 19.4);
        return dataset;
    }
    
    /**
     * Creates a sample chart.
     * 
     * @param dataset  the dataset.
     * 
     * @return A chart.
     */
    private JFreeChart createChart(PieDataset dataset) {
        JFreeChart chart = ChartFactory.createPieChart(
            "Pie Chart Demo 2",  // chart title
            dataset,             // dataset
            true,                // include legend
            true,
            false
        );
        PiePlot plot = (PiePlot) chart.getPlot();
 
    	// Chart
		plot.setOutlinePaint(null);
		
		// Title
		chart.getTitle().setFont(new Font("SansSerif", Font.BOLD, 12));
		
		// Section labels		
		plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} ({2})"));
		plot.setLabelBackgroundPaint(new Color(220, 220, 220));
		plot.setLabelFont(new Font("SansSerif", Font.PLAIN, 8));
				
		StandardPieSectionLabelGenerator slbl = new StandardPieSectionLabelGenerator( 
		         "{0}={2}", 
		         new DecimalFormat("#,##0"), 
		         new DecimalFormat("0%")); 
		plot.setLabelGenerator(slbl);
		plot.setLegendLabelGenerator(slbl);

		plot.setInteriorGap(0.12);
		
		chart.removeLegend();
		
		LegendTitle legend = new LegendTitle(chart.getPlot());
        legend.setItemFont(new Font("SansSerif", Font.PLAIN, 10));
        BlockContainer wrapper = new BlockContainer(new BorderArrangement());
        wrapper.setBorder(new BlockBorder(1.0, 1.0, 1.0, 1.0));
        
        StringBuffer subtitleBuffer = new StringBuffer();
        subtitleBuffer.append("(");
        
        boolean needsComma = false;
        for(int k=0;k<wellTypesToDisplay.size();k++) {
        	
        	if(needsComma == true) subtitleBuffer.append(", ");
        	if(((k+1)%5) == 0) subtitleBuffer.append("\n");
        	
        	subtitleBuffer.append(wellTypesToDisplay.get(k));
        	
        	needsComma = true;
        }
        subtitleBuffer.append(" Wells) = " + numberOfWells + " Wells");
        
        LabelBlock subtitle = new LabelBlock(subtitleBuffer.toString());
        subtitle.setFont(new Font("SansSerif", Font.PLAIN, 8));
        subtitle.setPadding(5, 5, 2, 5);
        wrapper.add(subtitle, RectangleEdge.BOTTOM);
        
        // *** this is important - you need to add the item container to
        // the wrapper, otherwise the legend items won't be displayed when
        // the wrapper is drawn... ***
        BlockContainer items = legend.getItemContainer();
        items.setPadding(2, 10, 5, 2);
        wrapper.add(items);
        legend.setWrapper(wrapper);
        
        legend.setPosition(RectangleEdge.BOTTOM);
        legend.setHorizontalAlignment(HorizontalAlignment.CENTER);
        legend.setBorder(new BlockBorder(new Color(0,0,0,0)));
        chart.addSubtitle(legend);
        
        chart.fireChartChanged();
		
		if(true) {
			// RED, AMBER, GREEN
			plot.setSectionPaint(0, Color.RED);
			plot.setSectionPaint(1, new Color(153, 204, 0));
			plot.setSectionPaint(2, Color.GREEN);

		} 

		plot.setNoDataMessage("No data available");
        
        return chart;
    }
    
    /**
     * Creates a panel for the demo (used by SuperDemo.java).
     * 
     * @return A panel.
     */
    public JPanel createDemoPanel() {
        JFreeChart chart = this.createChart(createDataset());
        return new ChartPanel(chart);
    }
    
    /**
     * Starting point for the demonstration application.
     *
     * @param args  ignored.
     */
    public static void main(String[] args) {
    	ArrayList<String> wellTypes = new ArrayList<String>();
    	wellTypes.add("Production");
    	wellTypes.add("Injection");
    	wellTypes.add("Waste Disposal");
    	
    	int numberOfWells = 100;
    	
        PieChartTest demo = new PieChartTest("Pie Chart Demo 2", wellTypes, numberOfWells);
        demo.pack();
        
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);

    }
}

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

Post by david.gilbert » Wed Jan 24, 2007 5:42 pm

What JRE and OS are you using? I get the following from your code, which looks fine to me:

Image
David Gilbert
JFreeChart Project Leader

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

tonyGriffiths
Posts: 11
Joined: Wed Jun 21, 2006 10:38 am

Post by tonyGriffiths » Wed Jan 24, 2007 5:50 pm

JRE = 1.5.0_05
OS = Windows XP Pro

[img]
http://www.intetech.com/images/demo.JPG
[/img]

See image for my results

Tony[/img]

Locked