Линейные диаграммы Line Chart

Библиотека JFreeChart позволяет создавать линейные диаграммы (линейные графики) с использованием в качестве набора данных интерфейсы CategoryDataset и XYDataset. Line Chart график представляет кусочно-линейную функцию, у которой отображаемые значения связаны соединительными линии (category, value). Чтобы создать линейную диаграмму необходимо использовать один из методов класса ChartFactory.

Методы создания диаграммы Line Chart

Класс ChartFactory включает два перегруженных метода createLineChart создания линейной диаграммы :

JFreeChart createLineChart(String title,
                           String categoryAxisLabel,
                           String valueAxisLabel,
                           CategoryDataset dataset);
JFreeChart createLineChart(String title,
                           String categoryAxisLabel,
                           String valueAxisLabel,
                           CategoryDataset dataset,
                           PlotOrientation orientation,
                           boolean legend,
                           boolean tooltips,
                           boolean urls);

Имеются также 2 метода создания линейной 3d диаграммы createLineChart3D. Наименование и значение параметров методов представлено в общем описании библиотеки JFreeChart.

Настройка линейной диаграммы Line Chart

Библиотека JFreeChart включает свойства и методы для настройки всех компонентов линейной диаграммы.

Фона диаграммы и графика

// Фон диаграммы
chart.setBackgroundPaint(Color.white);

// Фон графика
CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(232, 232, 232));

Подзаголовок диаграммы

TextTitle source = new TextTitle("Подзаголовок диаграммы");
source.setFont(new Font("SansSerif", Font.PLAIN, 10));
source.setPosition(RectangleEdge.BOTTOM);
source.setHorizontalAlignment(HorizontalAlignment.RIGHT);

chart.addSubtitle(source);

Цвет сетки графика

plot.setDomainGridlinePaint(Color.gray);
plot.setRangeGridlinePaint (Color.gray);

Линии графиков

Узловые точки на графике изображены определенными фигурами (квадрат, треугольник и т.д) в цвете графика. Фигуры можно не изображать, используя метод setShapesVisible (setSeriesShapesVisible) с параметром false. Также можно скрыть линии графика методом setLinesVisible (setSeriesLinesVisible), оставив только значения. Для определения цвета и ширины линии графика используются методы setSeriesPaint и setSeriesStroke.

XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
// Удаление связующих линий первого графика
renderer.setSeriesLinesVisible (0, false);
// Удаление меток Series второго графика
renderer.setSeriesShapesVisible(1, false);

// Настройка графика (цвет, ширина линии) 3-го графика
renderer.setSeriesPaint  (2, Color.orange);
renderer.setSeriesStroke (2, new BasicStroke(2.5f));

Класс XYSplineRenderer

Использование класса XYSplineRenderer позволяет представить графики не в виде кусочно-линейных функций, а в виде сглаженных линий.

Библиотека JFreeChart включает три перегруженных конструктора класса XYSplineRenderer.

// Creates a new instance with the precision attribute defaulting
// to 5 and no fill of the area 'under' the spline.
XYSplineRenderer();

// Creates a new renderer with the specified precision and no fill
// of the area 'under' (between '0' and) the spline.
XYSplineRenderer(int precision);

// Creates a new renderer with the specified precision and specified 
// fill of the area 'under' (between '0' and) the spline.
XYSplineRenderer(int precision, XYSplineRenderer.FillType fillType)

Пример LineChart3.java демонстрирует использование сплайн-класса XYSplineRenderer при различных параметрах.

Полная версия документации класса XYSplineRenderer представлена здесь.

Примеры построения линейных диаграмм

LineChart1.java Пример создания линейной диаграммы, настройка линий графика.
LineChart2.java Пример настройки интерфейса диаграммы и линий графика.
LineChart3.java Пример использования сплайн-класса XYSplineRenderer.
NormalDistribution.java Пример графиков нормального распределения, размещение аннотаций на графике.

Методы формирования наборов данных для диаграмм вынесены в отдельный модуль Dataset.java. Таким образом, исходные данные отделены от кода формирования интерфейса диаграмм для облегчения восприятия. Примеры можно скачать в конце страницы.

Листинг Dataset.java

Класс Dataset включает два метода, возвращаюих значения типов CategoryDataset и XYDataset. В наборе данных CategoryDataset используется числовое значение только для одной оси. Набор данных XYDataset формируется на основе данных типа XYSeries, включающих числовые значения для двух осей.

Метод createDataset1 вызывается в первом примере LineChart1.java. Метод createDataset2 ипользуется в примерах LineChart2.java и LineChart3.java. В примере LineChart2 метод возвращает три набора данных в одной коллекции при параметре idx равном -1. В примере LineChart3 метод createDataset2 вызывается 3 раза для получения трех коллекций данных, чтобы к каждой коллекции подключить свой сплайн-класс XYSplineRenderer.

public class Dataset 
{
    public static CategoryDataset createDataset1()
    {
        DefaultCategoryDataset dataset; 

        final String series1 = "Series 1" ;
        final String series2 = "Series 2" ;
        final String series3 = "Series 3" ;

        final String category1 = "Январь" ;
        final String category2 = "Февраль";
        final String category3 = "Март"   ;
        final String category4 = "Апрель" ;
        final String category5 = "Май"    ;

        dataset = new DefaultCategoryDataset();

        dataset.addValue(3.1, series1, category1);
        dataset.addValue(2.2, series1, category2);
        . . .
        dataset.addValue(7.2, series2, category1);
        dataset.addValue(5.4, series2, category2);
        . . .
        dataset.addValue(3.5, series3, category1);
        dataset.addValue(2.9, series3, category2);
        . . .
        return dataset;        
    }    
    public static XYDataset createDataset2(final int idx) 
    {
        final XYSeries series1 = new XYSeries("Series 1");
        series1.add( 1.0, 1.0);
        series1.add( 2.0, 4.0);
        . . .
        final XYSeries series2 = new XYSeries("Series 2");
        series2.add(1.0, 5.0);
        series2.add(2.0, 7.0);
        . . .
        final XYSeries series3 = new XYSeries("Series 3");
        series3.add(3.0, 4.0);
        series3.add(4.0, 3.0);
        . . .
        XYSeriesCollection dataset = new XYSeriesCollection();
        if (idx == -1) {
            dataset.addSeries(series1);
            dataset.addSeries(series2);
            dataset.addSeries(series3);
        } else if (idx == 0) {
            dataset.addSeries(series1);
        } else if (idx == 1) {
            dataset.addSeries(series2);
        } else if (idx == 2) {
            dataset.addSeries(series3);
        }                
        return dataset;
    }
}

Пример линейной диаграммы

В примере LineChart1.java не устанавливаем наименование DomainAxis и настраиваем линии двух графиков. Интерфейс диаграммы представлен на следующем скриншоте.

Листинг LineChart1.java

Для изменения типа линии графиков используется метод setSeriesStroke класса LineAndShapeRenderer. Класс java.awt.BasicStroke определяет атрибуты прорисовки линии графика. Набор данных для графиков имеет тип CategoryDataset.

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

    public LineChart1(final String title) 
    {
        super(title);
        final CategoryDataset dataset    = Dataset.createDataset1();
        final JFreeChart      chart      = createChart(dataset);
        final ChartPanel      chartPanel = new ChartPanel(chart);
        
        chartPanel.setPreferredSize(new Dimension(560, 480));
        setContentPane(chartPanel);
    }

    private JFreeChart createChart(final CategoryDataset dataset)
    {
        final JFreeChart chart = ChartFactory.createLineChart(
            "Линейный график 1",       // chart title
            null,                      // domain axis label
            "Значение",                // range axis label
            dataset,                   // data
            PlotOrientation.VERTICAL,  // orientation
            true,                      // include legend
            true,                      // tooltips
            false                      // urls
        );

        chart.setBackgroundPaint(Color.white);

        final CategoryPlot plot = (CategoryPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.lightGray);
        plot.setRangeGridlinePaint(Color.white);

        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(
                           NumberAxis.createIntegerTickUnits());
        rangeAxis.setAutoRangeIncludesZero(true);

        LineAndShapeRenderer renderer;
        renderer = (LineAndShapeRenderer) plot.getRenderer();

        renderer.setSeriesStroke(
            0, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, 
                                     BasicStroke.JOIN_ROUND,
                      1.0f, new float[] {10.0f, 6.0f}, 0.0f)
        );
        renderer.setSeriesStroke(
            1, new BasicStroke(2.0f, BasicStroke.CAP_ROUND,
                                     BasicStroke.JOIN_ROUND,
                      1.0f, new float[] {6.0f, 6.0f}, 0.0f)
        );        
        return chart;
    }
    
    public static void main(final String[] args)
    {
        final LineChart1 demo = new LineChart1("Линейный график 1");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
}

Пример настройки линейной диаграммы

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

Листинг LineChart2.java

Набор используемых для графиков данных имеет тип XYDataset. Для скрытия наименования осей в метод createXYLineChart передаются соответствующие нулевые параметры. Цвет фона диаграммы и графика устанавливаются методом setBackgroundPaint (Color). Цвет сетки графика определяется методами setDomainGridlinePaint(Color) и setRangeGridlinePaint (Color).

Чтобы скрыть линии графика используется метод setSeriesLinesVisible (boolean). Фигуры узловых значений 2-го графика скрываются методом setSeriesShapesVisible(int, boolean).

У третьего графика изменяется цвет и толщина линии методами setSeriesPaint, setSeriesStroke.

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

    public LineChart2(final String title) 
    {
        super(title);

        XYDataset   dataset    = Dataset.createDataset2(-1);
        JFreeChart  chart      = createChart(dataset);
        ChartPanel  chartPanel = new ChartPanel(chart);

        chartPanel.setPreferredSize(new java.awt.Dimension(560, 480));
        setContentPane(chartPanel);
    }

    private JFreeChart createChart(XYDataset dataset)
    {
        final JFreeChart chart = ChartFactory.createXYLineChart(
                        "Линейный график 2", null, null, dataset,
                        PlotOrientation.VERTICAL, true, false, false);

        chart.setBackgroundPaint(Color.white);

        final XYPlot plot = chart.getXYPlot();
        plot.setBackgroundPaint(new Color(232, 232, 232));

        plot.setDomainGridlinePaint(Color.gray);
        plot.setRangeGridlinePaint (Color.gray);

        // Определение отступа меток делений
        plot.setAxisOffset(new RectangleInsets (1.0, 1.0, 1.0, 1.0));

        // Скрытие осевых линий
        ValueAxis axis = plot.getDomainAxis();
        axis.setAxisLineVisible (false);

        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        // Удаление связующих линий Series 1
        renderer.setSeriesLinesVisible (0, false);
        // Удаление меток Series 2
        renderer.setSeriesShapesVisible(1, false);

        // Настройка графика (цвет, ширина линии) Series 3
        renderer.setSeriesPaint  (2, Color.orange);
        renderer.setSeriesStroke (2, new BasicStroke(2.5f));
        plot.setRenderer(renderer);
        
        // Настройка NumberAxis
        NumberAxis rangeAxis = plot.getRangeAxis();
        
        rangeAxis.setAxisLineVisible (false);
        rangeAxis.setStandardTickUnits(NumberAxis
                                      .createIntegerTickUnits());
        return chart;
    }

    public static void main(final String[] args) 
    {
        final LineChart2 demo = new LineChart2("Линейный график 2");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
}

Пример использования XYSplineRenderer

Пример LineChart3.java отличается от предыдущего примера LineChart2.java только дополнительным использованием слайн-класса XYSplineRenderer. Интерфейс диаграммы представлен на следующем скриншоте.

Листинг примера LineChart3.java

Библиотека JFreeChart позволяет использовать один слайн-класс XYSplineRenderer для всех графиков. Для этого необходимо использовать метод setRenderers (XYItemRenderer[]), например :

XYSplineRenderer renderer = new XYSplineRenderer()
plot.setRenderers (new XYItemRenderer[] {renderer});

Однако в этом случае не будет столь заметно влияние параметра precision. Поэтому в примере LineChart3.java создаются три набора данных, к каждому из которых подключается свой слайн-класс XYSplineRenderer. В первом графике (red) используется слайн-класс со значением по умолчанию (precision=5). Как видно на диаграмме график имеется незначительные шераховатости.

В третьем графике (orange) значение precision слайн-класса равно 2, и сглаживание графика очень слабое. И только второй график (blue) с precision, равным 8, выглядит достойно.

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

    public LineChart3(final String title) 
    {
        super(title);

        JFreeChart  chart      = createChart();
        ChartPanel  chartPanel = new ChartPanel(chart);
        
        chartPanel.setPreferredSize(new java.awt.Dimension(560, 480));
        setContentPane(chartPanel);
    }

    private JFreeChart createChart()
    {
        final JFreeChart chart = ChartFactory.createXYLineChart(
            "Демонстрация Spline Renderer",
            null,                        // x axis label
            null,                        // y axis label
            null,                        // data
            PlotOrientation.VERTICAL,
            true,                        // include legend
            false,                       // tooltips
            false                        // urls
        );

        chart.setBackgroundPaint(Color.white);

        final XYPlot plot = chart.getXYPlot();
        plot.setBackgroundPaint(new Color(232, 232, 232));

        plot.setDomainGridlinePaint(Color.gray);
        plot.setRangeGridlinePaint (Color.gray);
        
        // Определение отступа меток делений
        plot.setAxisOffset(new RectangleInsets (1.0, 1.0, 1.0, 1.0));

        // Скрытие осевых линий и меток делений
        ValueAxis axis = plot.getDomainAxis();
        axis.setAxisLineVisible (false);    // осевая линия
        
        // Настройка NumberAxis
        final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setAxisLineVisible (false);
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

        // Настройка XYSplineRenderer
        // Precision: the number of line segments between 2 points [default: 5]
        XYSplineRenderer r0 = new XYSplineRenderer();
        r0.setSeriesShapesVisible (0, false);
        
        XYSplineRenderer r1 = new XYSplineRenderer();
        r1.setPrecision(8); 
        r1.setSeriesShapesVisible (0, false);
        
        XYSplineRenderer r2 = new XYSplineRenderer(1);
        
        r2.setSeriesShapesVisible (0, false);
        r2.setSeriesPaint         (0, Color.orange);
        r2.setSeriesStroke        (0, new BasicStroke(2.5f));
        
        // Наборы данных
        XYDataset dataset0 = Dataset.createDataset2(0);
        XYDataset dataset1 = Dataset.createDataset2(1);
        XYDataset dataset2 = Dataset.createDataset2(2);
        
        plot.setDataset(0, dataset0);
        plot.setDataset(1, dataset1);
        plot.setDataset(2, dataset2);

        // Подключение Spline Renderer к наборам данных
        plot.setRenderer(0, r0);
        plot.setRenderer(1, r1);
        plot.setRenderer(2, r2);
        
        return chart;
    }
    
    public static void main(final String[] args) 
    {
        final LineChart3 demo = new LineChart3("XYSplineRenderer");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
}

Пример диаграммы нормального распределения

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

Листинг примера NormalDistribution.java

Утилита DatasetUtilities библиотеки JFreeChart включает метод sampleFunction2D для создания набора данных графика нормального распределения. Функция нормального распределения создается классом NormalDistributionFunction2D.

Для нанесения аннотаций на график используются классы XYPointerAnnotation и XYTextAnnotation. Класс XYPointerAnnotation включает изображение стрелки, которую можно привязать к различным частям текста и повернуть на требуемый угол. Текстовую аннотацию XYTextAnnotation можно поворачивать. Шрифт и фон аннотаций настраиваются.

В примере временной диаграммы TimeSeriesMarker.java для выделения объекта на график наносится аннотация в виде красного кружка с использованием класса XYDrawableAnnotation.

public class NormalDistribution extends ApplicationFrame
{
    private static final long   serialVersionUID = 1L;
    private static final String TITLE = "Нормальное распределение";
    //----------------------------------------------------------------
    public NormalDistribution(final String title)
    {
        super(title);
        Function2D normal1=new NormalDistributionFunction2D(-2.0,0.5);
        Function2D normal2=new NormalDistributionFunction2D( 0.0,0.4);
        Function2D normal3=new NormalDistributionFunction2D( 0.8,1.5);

        XYSeriesCollection dataset = new XYSeriesCollection();

        dataset.addSeries(createXYSeries("Normal1", normal1));
        dataset.addSeries(createXYSeries("Normal2", normal2));
        dataset.addSeries(createXYSeries("Normal3", normal3));
        
        JFreeChart chart = ChartFactory.createXYLineChart(TITLE,
                    null, "Y", dataset, PlotOrientation.VERTICAL,
                    true, true, false);
        final ChartPanel chartPanel = new ChartPanel(chart);
        
        final XYPlot plot = chart.getXYPlot();
        plot.getRenderer().setSeriesPaint(2, new Color (255, 224, 64));
        
        XYPointerAnnotation pointer1;
        XYPointerAnnotation pointer2;
        XYTextAnnotation    annotation;
        pointer1 = new XYPointerAnnotation(" Normal 1 ",
                                           -2.15, 0.65, Math.PI);
        pointer1.setBaseRadius(35.0);
        pointer1.setTipRadius(10.0);
        pointer1.setPaint          (Color.yellow);
        pointer1.setBackgroundPaint(Color.red   );
        pointer1.setFont(new Font("SansSerif", Font.PLAIN, 12));
        pointer1.setTextAnchor(TextAnchor.HALF_ASCENT_RIGHT);
        plot.addAnnotation(pointer1);

        pointer2 = new XYPointerAnnotation(" Normal 2 ", 
                                           0.08, 0.95, 2.0 * Math.PI);
        pointer2.setBaseRadius(35.0);
        pointer2.setTipRadius(10.0);
        pointer2.setPaint          (Color.black);
        pointer2.setBackgroundPaint(Color.blue );
        pointer2.setFont(new Font("SansSerif", Font.PLAIN, 12));
        pointer2.setTextAnchor(TextAnchor.HALF_ASCENT_LEFT);
        plot.addAnnotation(pointer2);
        
        annotation = new XYTextAnnotation("  График  ", 2.5, 0.18);
        annotation.setBackgroundPaint(new Color (255, 224, 64));
        annotation.setFont(new Font("SansSerif", Font.PLAIN, 9));
        annotation.setRotationAngle(Math.PI / 4.0);
        plot.addAnnotation(annotation);

        chartPanel.setPreferredSize(new java.awt.Dimension(580, 480));
        setContentPane(chartPanel);
    }
    //----------------------------------------------------------------
    private XYSeries createXYSeries(String caption, Function2D normal)
    {
        return DatasetUtilities.sampleFunction2DToSeries(normal, 
                                             -4.5, 4.5, 100, caption);
    }
    //----------------------------------------------------------------
    public static void main(final String[] args)
    {
        NormalDistribution demo = new NormalDistribution(TITLE);
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
}

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

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

  Рейтинг@Mail.ru