Круговые диаграммы Pie Charts

Библиотека JFreeChart позволяет создавать и настраивать интерфейс представления круговых диаграмм, включающее :

  • определение цветов секций и их контурных линий;
  • определение значений меток секций;
  • извлечение (выделение) секции;
  • размещение на панели нескольких диаграмм;
  • представление диаграммы с эффектом 3d.

Методы создания круговой диаграммы

Утилита ChartFactory включает несколько статических методов создания круговых диаграмм :

public static
JFreeChart createPieChart(String title, PieDataset dataset);

JFreeChart createPieChart(String title, PieDataset dataset,
            boolean legend, boolean tooltips, Locale locale);
			
JFreeChart createPieChart(String title, PieDataset dataset,
            boolean legend, boolean tooltips, boolean urls);
			
JFreeChart createPieChart(String title, PieDataset dataset,
        PieDataset previousDataset, int percentDiffForMaxScale,
        boolean greenForIncrease, boolean legend, boolean tooltips,
        Locale locale, boolean subTitle, boolean showDifference)

JFreeChart createPieChart(String title, PieDataset dataset,
        PieDataset previousDataset, int percentDiffForMaxScale,
        boolean greenForIncrease, boolean legend, boolean tooltips, 
        boolean urls, boolean subTitle, boolean showDifference);

В представленных ниже примерах используется третий метод createPieChart.

Определение цвета секций

При создании круговых диаграмм используются цвета секций по умолчанию. Чтобы переопределить цвет секции необходимо использовать метод setSectionPaint(Comparable, Paint). Например :

PiePlot plot = (PiePlot) chart.getPlot();
plot.setSectionPaint("Секция А", new Color(232, 232, 232));
plot.setSectionPaint("Секция Б", new Color(200, 255, 200));

На странице описания JFreeChart приводится пример создания и использования градиентой заливки цвета секции RadialGradientPaint.

Выделение контуров секций

Контуры секций диаграммы выделены тонкой линией серого цвета. Чтобы скрыть контурную линию используется метод setSectionOutlinesVisible(boolean).

PiePlot plot = (PiePlot) chart.getPlot();
plot.setSectionOutlinesVisible(false);

Цвет и размер контурной линии можно изменить с использованием следующих методов :

// Методы определения контурных линий диаграммы
public void setBaseSectionOutlinePaint (Paint  paint );
public void setBaseSectionOutlineStroke(Stroke stroke);

// Методы определения контурной линии одной из секций диаграммы
public void setSectionOutlinePaint (Comparable key, Paint  paint );
public void setSectionOutlineStroke(Comparable key, Stroke stroke);

Для выделения контурной линии определенной секции необходимо использовать вторую пару методов, в которую в качестве первого параметра необходимо передать наименование секции, описанное в Dataset. В примере PieChartDemo.java продемонстрировано использование методов настройки контурных линий.

Определение значений в метках секций

Метки секций можно использовать для размещения дополнительной информации об абсолютном или относительном значениях секций, определенных в PieDataset. Для внесения изменений в метки необходимо использовать класс PieSectionLabelGenerator. Библиотека JFreeChart включает несколько конструкторов данного класса, представленых ниже.

public StandardPieSectionLabelGenerator();
public StandardPieSectionLabelGenerator(Locale locale) {
    this(DEFAULT_SECTION_LABEL_FORMAT, locale)
};
public StandardPieSectionLabelGenerator(String labelFormat) {
    this(labelFormat, NumberFormat.getNumberInstance(),
                      NumberFormat.getPercentInstance());
};
public StandardPieSectionLabelGenerator(String labelFormat, 
                                        Locale locale) {
    this(labelFormat, NumberFormat.getNumberInstance(locale),
                      NumberFormat.getPercentInstance(locale));
};
public StandardPieSectionLabelGenerator(String labelFormat,
                                        NumberFormat numberFormat,
                                        NumberFormat percentFormat);

Код отдельных конструкторов раскрыт, чтобы не только показать взаимосвязь разных конструкторов, но и влияние объекта локализации (Locale), которая позволяет представить численные значения в принятом в определенной стране формате.

Текстовый параметр labelFormat позволяет в нужном формате подставить значения. Полный формат может включать 3 позиции : «{0} = {1}, {2}». Значение {0} определяет метку используемой секции. Наличие в формате {1} определяет подстановку абсолютного значения. Чтобы подставить процентное значение необходимо в формате указать {2}. Пример подстановки абсолютных и относительных значений в метку представлен ниже (см. PieChartMulti.java).

Исходные коды примеров

Рассмотрим три примера использования круговых диаграм Pie Chart для отображения информации о «семейных расходах» :

  • в первом примере PieChartExploded.java вырежем одну из секций диаграммы;
  • во втором примере PieChartDemo.java настроим интерфейс диаграммы с использованием цветов и шрифтов;
  • в третьем примере PieChartMulti.java на одной панели разместим две диаграммы, в которых в метки дополнительно включим абсолютные и относительные значения.

Данные для диаграмм опишем в отдельном модуле Dataset.java.

Листинг Dataset.java

import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;

public class Dataset 
{
   public static final String[] SECTIONS    = {"Квартира", 
                                               "Питание", 
                                               "Школа, фитнес", 
                                               "Развлечения",
                                               "Дача"};
   public static final double[] EXPENSES_05 = {7035.8, 26000, 
                                               9200.0, 9450.0, 
                                               15000.0};
   public static final double[] EXPENSES_06 = {6988.7, 22450, 
                                               4180.0,12840.0,
                                               16500.0};


    public static PieDataset createPieDataset(final double[] expenses)
    {
        DefaultPieDataset dataset = new DefaultPieDataset();
        for (int i = 0; i < SECTIONS.length; i++)
            dataset.setValue(SECTIONS[i], new Double(expenses[i]));
        return dataset;
    }
}

Данные для круговых диаграмм включают наименования секций и их численные значения для EXPENSES_05, EXPENSES_05 для двух разных перидов (месяцев). Метод createPieDataset возвращает набор данных типа PieDataset.

Пример с извлечением секции, PieChartExploded.java

В примере PieChartExploded.java из диаграммы вырежем секцию с использованием метода setExplodePercent (String, float). В качестве параметров методу необходимо передать наименование секции и процентное значение радиуса, на которое секция будет извлечена из диаграммы. Интерфейс примера представлен на следующем скриншоте.

Листинг PieChartExploded.java

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;

import org.jfree.data.general.PieDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

public class PieChartExploded extends ApplicationFrame
{
    private static final long serialVersionUID = 1L;

    PieDataset dataset = Dataset.createPieDataset(Dataset.EXPENSES_05);
    JFreeChart chart = createChart(dataset);

    public PieChartExploded(final String title) 
    {
        super(title);
        dataset = Dataset.createPieDataset(Dataset.EXPENSES_05);
        chart = createChart(dataset);

        // Размещение диаграммы в панели
        final ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new java.awt.Dimension(600, 400));
        setContentPane(chartPanel);
    }
    private JFreeChart createChart(final PieDataset dataset)
    {
        chart = ChartFactory.createPieChart("Диаграмма расходов",
                                      dataset, true, true, false);
        PiePlot plot = (PiePlot) chart.getPlot();
        plot.setExplodePercent(Dataset.SECTIONS[3], 0.20);
        return chart;
    }
    public static void main(final String[] args)
    {
        PieChartExploded demo = new PieChartExploded("Pie Chart");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
}

Пример PieChartDemo.java

В примере PieChartDemo.java настроим интерфейс диаграммы (фон, заголовок, подзаголовок, контурные линии секций) с использованием методов управления цветом фона, выравниванием и шрифтами. Заголовок сместим влево, подзаголовок разместим внизу справа. Кроме этого, контурные линии секции выделим белым цветом, а одну из секций выделим отдельным цветом. Интерфейс примера представлен на следующем скриншоте.

Листинг PieChartDemo.java

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;

import javax.swing.JPanel;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.title.TextTitle;
import org.jfree.chart.StandardChartTheme;

import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import org.jfree.ui.HorizontalAlignment;

import org.jfree.data.general.PieDataset;

public class PieChartDemo extends ApplicationFrame
{
    private static final long serialVersionUID = 1L;

    private JFreeChart  chart   = null;
    private PieDataset  dataset = null;

   static {
        /*
         * set a theme using the new shadow generator feature 
         * available in 1.0.14 - for backwards compatibility
         * it is not enabled by default
         */
        ChartFactory.setChartTheme(
           new StandardChartTheme("JFree/Shadow", true));
    }
    public PieChartDemo(String title) {
        super(title);
        setContentPane(createChartPanel());
    }
    public JPanel createChartPanel()
    {
        dataset = Dataset.createPieDataset(Dataset.EXPENSES_05);
        chart = createChart(dataset);
        chart.setPadding(new RectangleInsets(4, 8, 2, 2));
        
        ChartPanel panel = new ChartPanel(chart);
        panel.setFillZoomRectangle(true);
        panel.setMouseWheelEnabled(true);
        panel.setPreferredSize(new Dimension(600, 400));
        return panel;
    }

    private JFreeChart createChart(PieDataset dataset)
    {
        JFreeChart chart = ChartFactory.createPieChart(
            "Семейные расходы",  // chart title
            dataset,             // data
            false,               // no legend
            true,                // tooltips
            false                // no URL generation
        );

        // Определение фона графического изображения
        chart.setBackgroundPaint(new Color(232, 232, 255));
        
        // Определение заголовка
        TextTitle title = chart.getTitle();
        title.setHorizontalAlignment(HorizontalAlignment.LEFT);
        title.setPaint(Color.DARK_GRAY);
        title.setFont(new Font("Arial", Font.BOLD, 26));

        // Определение подзаголовка
        TextTitle subtitle = new TextTitle(
                           "Семейные расходы за текущий месяц", 
                            new Font("Courier New", Font.PLAIN, 12));
        subtitle.setPaint(Color.DARK_GRAY);
        subtitle.setPosition(RectangleEdge.BOTTOM);
        subtitle.setHorizontalAlignment(HorizontalAlignment.RIGHT);
        chart.addSubtitle(subtitle);

        PiePlot plot = (PiePlot) chart.getPlot();
        // Фон
        plot.setBackgroundPaint(null);
        plot.setInteriorGap(0.04);
        // Обрамляющая граница
        plot.setOutlineVisible(false);

        // Выделение контурных линий секций
        plot.setBaseSectionOutlinePaint(Color.WHITE);
        plot.setBaseSectionOutlineStroke(new BasicStroke(2.0f));

        plot.setSectionOutlinePaint ("Дача", Color.CYAN);
        plot.setSectionOutlineStroke("Дача", new BasicStroke(3.0f));
        plot.setSectionOutlinesVisible(true);

        // Настройка меток названий секций
        plot.setLabelFont(new Font("Courier New", Font.BOLD, 20));
        plot.setLabelLinkPaint(Color.WHITE);
        plot.setLabelLinkStroke(new BasicStroke(2.0f));
        plot.setLabelOutlineStroke(null);
        plot.setLabelPaint(Color.DARK_GRAY);
        plot.setLabelBackgroundPaint(null);
        return chart;
    }
 
    public static void main(String[] args)
    {
        PieChartDemo demo = new PieChartDemo("JFreeChart: Pie Chart");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
}

Пример размещения двух диаграмм на панели, PieChartMulti.java

Всё познаётся в сравнении, поэтому в некоторых случаях требуется наглядно показать информацию за разные периоды времени. Библиотека Swing в сочетании с JFreeChart позволяют это сделать просто и красиво.

В примере PieChartMulti две диаграммы размещаются на панели JPanel друг под другом с использованием шаблона GridLayout. В качестве данных для верхней диаграммы используем значения Dataset.EXPENSES_05. Для нижней диаграммы - Dataset.EXPENSES_06. В зависимости от установленного флага (chart3d) диаграммы будут представлены либо в обычном виде, либо в 3d.

В качестве отличий от предыдущих примеров дополнительно в метках секций верхней диаграммы укажем абсолютные и процентные отношения значений секций. В нижней диаграмме метки удалим и диаграмму расcтянем по всей площади. Интерфейс примера с двумя обычными диаграммами представлен на следующем скриншоте. В метки секций подставлены абсолютные значения.

Листинг PieChartMulti.java

Для добавления в метку значений (абсолютное/процентное) используется класс PieSectionLabelGenerator. Метод setCircular со значением false раccтягивает диаграмму по всей площади с учетом меток. Методом setForegroundAlpha изменяется прозрачность фона. Чтобы убрать метки из нижней диаграммы используется метод setLabelGenerator(null) с нулевым параметром.

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PiePlot3D;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;

import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

import org.jfree.data.general.PieDataset;

public class PieChartMulti extends ApplicationFrame
{
    private static final long serialVersionUID = 1L;

    PieDataset   dataset_05 = null;
    PieDataset   dataset_06 = null;
    JFreeChart   chart1     = null;
    JFreeChart   chart2     = null;
    JFreeChart   chart3     = null;
    JFreeChart   chart4     = null;
    PieSectionLabelGenerator
                 pslg       = null;
    boolean      chart3d    = false;

    public PieChartMulti(String title) 
    {
        super(title);
        JPanel panel = new JPanel(new GridLayout(2, 1));
        // Создание наборов данных
        dataset_05 = Dataset.createPieDataset(Dataset.EXPENSES_05);
        dataset_06 = Dataset.createPieDataset(Dataset.EXPENSES_06);

        // Создание диаграмм
        if (!chart3d) {
            chart1 = ChartFactory.createPieChart(
                                      "Диаграмма расходов, май",
                                      dataset_05,
                                      false, false, false);
            PiePlot plot1 = (PiePlot) chart1.getPlot();
            // Добавим в метку фактическое значение секции
            pslg = new StandardPieSectionLabelGenerator("{0} = {1}", 
                       NumberFormat.getNumberInstance(), 
                       NumberFormat.getPercentInstance());
            plot1.setLabelGenerator(pslg);
            plot1.setLabelGap(0.02); 

            chart2 = ChartFactory.createPieChart(
                                      "Диаграмма расходов,  июнь",
                                      dataset_06,
                                      false, false, false);
            PiePlot plot2 = (PiePlot) chart2.getPlot();
            plot2.setCircular(false);

            plot2.setInteriorGap(0.0);
            plot2.setLabelGenerator(null);

            // Размещение диаграмм на панели ChartPanel
            panel.add(new ChartPanel(chart1));
            panel.add(new ChartPanel(chart2));
        } else {
            chart3 = ChartFactory.createPieChart3D(
                                      "Диаграмма расходов,  май",
                                      dataset_05,
                                      false, false, false);
            PiePlot3D plot3 = (PiePlot3D) chart3.getPlot();
            plot3.setForegroundAlpha(0.6f);
            plot3.setCircular(true);
            // Добавим в метку %-соотношение от общей суммы 
            pslg = new StandardPieSectionLabelGenerator("{0} = {2}", 
                                   NumberFormat.getNumberInstance(), 
                                  NumberFormat.getPercentInstance());
            plot3.setLabelGenerator(pslg);

            chart4 = ChartFactory.createPieChart3D(
                                      "Диаграмма расходов,  июнь",
                                      dataset_06,
                                      false, false, false);
            PiePlot3D plot4 = (PiePlot3D) chart4.getPlot();
            plot4.setForegroundAlpha(0.6f);
            plot4.setLabelGenerator(null);
            // Размещение диаграмм на панели ChartPanel
            panel.add(new ChartPanel(chart3));
            panel.add(new ChartPanel(chart4));
        }

        panel.setPreferredSize(new Dimension(540, 480));
        setContentPane(panel);
    }
    public static void main(String[] args)
    {
        PieChartMulti demo = new PieChartMulti("Pie Chart");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
}

Интерфейс примера с двумя 3d диаграммами представлен на следующем скриншоте.В метки секций подставлены процентные значения.

Скачать примеры

Исходные коды примеров создания круговых диаграмм Pie Chart с использованием библиотеки JFreeChart в виде maven-проекта можно скачать здесь (20.0 Кб).

  Рейтинг@Mail.ru