一. hjfreechart简介

jfreechart是JAVA平台上的一个开源报表系统(开放的图表绘制类库),通过它可以生成柱状图,饼状图,散点图,折线图等多种图形。

jfreechart的主页是http://www.jfree.org/jfreechart/index.html

二. 项目引入jfreechart

    <dependency>
        <groupId>org.jfree</groupId>
        <artifactId>jfreechart</artifactId>
        <version>1.5.3</version>
    </dependency>

三. 快速绘图教程

1. 折线图

折线图

package plot;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
 
public class Example {
	public static void main(String[] args) {
 
		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(15, "schools", "1970");
		dataset.addValue(30, "schools", "1980");
		dataset.addValue(60, "schools", "1990");
		dataset.addValue(120, "schools", "2000");
		dataset.addValue(240, "schools", "2010");
		dataset.addValue(300, "schools", "2020");
		dataset.addValue(320, "schools", "2022");
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createLineChart(
				"Example", // 图标题
				"Year", // x轴标题
				"Schools Count", // y轴标题
				dataset, //数据集
				PlotOrientation.VERTICAL, //图表方向
				false, true, false);
 
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}
 
}

2. 条形图

条形图

package plot;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
 
public class Example {
	public static void main(String[] args) {
 
		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(1.0, "A", "Ⅰ");
		dataset.addValue(3.0, "A", "Ⅱ");
		dataset.addValue(5.0, "A", "Ⅲ");
		dataset.addValue(5.0, "A", "Ⅳ");
		dataset.addValue(5.0, "B", "Ⅰ");
		dataset.addValue(6.0, "B", "Ⅱ");
		dataset.addValue(10.0, "B", "Ⅲ");
		dataset.addValue(4.0, "B", "Ⅳ");
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createBarChart(
				"Example", // 图标题
				"Category",            
		         "Score",            
		         dataset,          
		         PlotOrientation.VERTICAL,           
		         true, true, false);
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}
 
}

3. 3D条形图

3D条形图

package plot;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
 
public class Example {
	public static void main(String[] args) {
 
		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(1.0, "A", "Ⅰ");
		dataset.addValue(3.0, "A", "Ⅱ");
		dataset.addValue(5.0, "A", "Ⅲ");
		dataset.addValue(5.0, "A", "Ⅳ");
		dataset.addValue(5.0, "B", "Ⅰ");
		dataset.addValue(6.0, "B", "Ⅱ");
		dataset.addValue(10.0, "B", "Ⅲ");
		dataset.addValue(4.0, "B", "Ⅳ");
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createBarChart3D(
				"Example", // 图标题
				"Category", 
				"Score", 
				dataset, 
				PlotOrientation.VERTICAL, 
				true, true, false);
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}
 
}

4. 饼状图

饼状图

package plot;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
 
public class Example {
	public static void main(String[] args) {
 
		// 创建数据
		DefaultPieDataset dataset = new DefaultPieDataset();
		dataset.setValue("A", 20);
		dataset.setValue("B", 10);
		dataset.setValue("C", 40);
		dataset.setValue("D", 30);
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createPieChart(
				"Example", // 图标题
				dataset, // 数据集
				false, true, true);
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
 
	}
 
}

5. 3D饼状图

3D饼图

package plot;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
 
public class Example {
	public static void main(String[] args) {
 
		// 创建数据
		DefaultPieDataset dataset = new DefaultPieDataset();
		dataset.setValue("A", 20);
		dataset.setValue("B", 10);
		dataset.setValue("C", 40);
		dataset.setValue("D", 30);
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createPieChart3D(
				"Example", // 图标题
				dataset, // 数据集
				false, true, true);
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
 
	}
 
}

6. XY图

XY图

package plot;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
 
public class Example {
	public static void main(String[] args) {
 
		// 创建数据
		XYSeries data = new XYSeries("InternetExplorer");
		data.add(1.0, 1.0);
		data.add(2.0, 2.0);
		data.add(3.0, 3.0);
		data.add(4.0, 2.0);
		data.add(5.0, 1.0);
		data.add(6.0, 2.0);
		data.add(6.0, 3.0);
		data.add(7.0, 2.0);
		data.add(8.0, 1.0);
		data.add(9.0, 2.0);
		XYSeriesCollection dataset = new XYSeriesCollection();
		dataset.addSeries(data);
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createXYLineChart(
				"Example", 
				"X", 
				"Y", 
				dataset, 
				PlotOrientation.VERTICAL, 
				false,true, false);
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
 
	}
 
}

7. 散点图

散点图

package plot;
 
import java.io.IOException;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
 
public class Example {
	public static void main(String[] args) throws IOException {
 
		// 添加数据
		XYSeriesCollection dataset = new XYSeriesCollection();
		XYSeries series1 = new XYSeries("Series1");
		for (int i = 0; i < 100; i++) {
			series1.add(Math.random()*100, Math.random()*100);
		}
		dataset.addSeries(series1);
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createScatterPlot(
		        "Example", 
		        "X-Axis", "Y-Axis", dataset);
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
 
	}
 
}

8. 气泡图

气泡图

package plot;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.DefaultXYZDataset;
 
public class ShowExample {
	public static void main(String[] args) {
 
		// 创建数据
		DefaultXYZDataset dataset = new DefaultXYZDataset();
		double x[] = { 30, 40, 50, 60, 70, 80 };
		double y[] = { 10, 20, 30, 40, 50, 60 };
		double z[] = { 1, 2, 3, 4, 2, 1 };
		double xyz[][] = { x, y, z };
		dataset.addSeries("Series", xyz);
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createBubbleChart(
		         "AGE vs WEIGHT vs WORK", 
		         "Weight", 
		         "AGE", 
		         dataset, 
		         PlotOrientation.HORIZONTAL, 
		         true, true, false);
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}
 
}

9. 时序图

时序图


package plot;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.SeriesException;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
 
public class ShowExample {
	public static void main(String[] args) {
 
		// 创建数据
		TimeSeries series = new TimeSeries("Random Data");
		Second current = new Second();
		double value = 100.0;
		for (int i = 0; i < 4000; i++) {
			try {
				value = value + Math.random() - 0.5;
				series.add(current, value);
				current = (Second) current.next();
			} catch (SeriesException e) {
				System.err.println("Error adding to series");
			}
		}
		XYDataset dataset = (XYDataset) new TimeSeriesCollection(series);
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createTimeSeriesChart(
				"Computing Test", 
				"Seconds", 
				"Value", 
				dataset, 
				false,false, false);
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}
 
}

四. 常见类与方法

在本章中,我们将讨论一些在JFreeChart库重要的软件包,类和方法。这些软件包,类和方法是最常见的,同时建立了各种使用JFreeChart库图表。

1. ChartFactory 类

ChartFactory是org.jfree.chart包中抽象类。它提供了实用方法的集合,用于生成标准的图表。以下是几个重要方法的列表:

类构造方法

方法 描述
ChartFactory() ChartFactory类的默认构造函数。

类方法

S.N. 方法 & 描述
1 createPieChart(java.lang.String title, PieDataset dataset, boolean legend, boolean tooltips, boolean urls) 此方法使用默认设置创建一个饼图。它返回JFreeChart类型的对象。
2 createPieChart3D(java.lang.String title, PieDataset dataset, boolean legend, boolean tooltips, boolean urls) 此方法使用指定的数据集三维/3D饼图。
3 createBarChart(java.lang.String title, java.lang.String categoryAxisLabel, java.lang.String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) 参数java.lang.String categoryAxisLabel标签放置在X轴的值。该参数的java.lang.String valueAxisLabel标签放置在Y轴的数值。此方法创建一个条形图。
4 createBarChart3D(java.lang.String title, java.lang.String categoryAxisLabel, java.lang.String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) 此方法创建一个柱形图具有3D效果。它返回JFreeChart类型的对象。
5 createLineChart(java.lang.String title, java.lang.String categoryAxisLabel, java.lang.String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls)
此方法使用默认设置创建一个折线图。  
6 createLineChart3D(java.lang.String title, java.lang.String categoryAxisLabel, java.lang.String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) 此方法创建一个折线图与3D效果。
7 createXYLineChart(java.lang.String title, java.lang.String xAxisLabel, java.lang.String yAxisLabel, XYDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) 此方法使用默认设置创建基于XYDataset的折线图。

2. ChartFrame 类

ChartFrame类在org.jfree.chart包中,提供所有的帧相关的功能和工具。 ChartFrame类继承自父类,如Frame, Window, Container, Component 类功能。

类构造方法

S.N. 构造方法及描述
1 ChartFrame (java.lang.Frame String, JfreeChart chart) 它构建一个框架/frame。
2 Chart Frame (java.lang.Frame String, JfreeChart chart, boolean scrollpane) 它构建一个框架/frame。

类方法

S.N. 构造方法及描述
1 getChartPanel() 此方法返回图表面板的框架/frame。

3. ChartPanel 类

org.jfree.chart包中的ChartPanel类用于swing GUI部件,用于显示JfreeChart对象。

类构造方法

S.N. 构造方法及描述
1 ChartPanel(JFreeChart chart) 此构造一个面板/panel ,显示指定的图表。
2 ChartPanel(JFreeChart chart, boolean useBuffer) 这个构造函数构造包含图表的面板/panel。
3 ChartPanel(JFreeChart chart, boolean properties, boolean save, boolean print, boolean zoom, boolean tooltips) 此构造一个JFreeChart面板。

类方法

S.N. 方法及描述
1 setPreferredSize(java.awt.Dimension) 该方法用于java.awt中设置的帧大小。 Dimension类对象作为参数。这个方法是从javax.swing.JComponent中实现。

4. ChartUtilities 类

org.jfree.chart包中的CharUtilites类提供JFreeCharts包括将图表转换成图像文件格式,如PNG,JPEG和创建HTML图像映射方法的实用方法的集合。

类构造函数

S.N. 构造方法及描述
1 ChartUtilities() 这是类的一个默认构造函数

类方法

S.N. 方法及描述
1 saveChartAsPNG(java.io.File file, JfreeChart chart, int width, int height) 此方法转换和保存图表为PNG格式指定的文件。
2 saveChartAsJPEG(java.io.File file, JfreeChart chart, int width, int height) 此方法转换并保存一个图表,以JPEG格式指定的文件。

5. JFreeChart 类

JFreeChart 类是在org.jfree.chart包的核心类。这个类提供了JFreeChart的方法来创建柱状图,折线图,饼图和XY坐标图,包括时间序列数据。

类构造函数

S.N. 构造方法及描述
1 JfreeChart(Plot plot) 此构造函数创建基于所提供的节点一个新的图表。
2 JfreeChart(java.lang.String title, java.awt.Font titleFont, Plot plot, boolean createLegend) 该构造函数创建一个新的图表给定标题和绘图。
3 JfreeChart(java.lang.String title, Plot plot) 该构造函数创建一个新的图表给定标题和绘图。

类方法

S.N. 方法及描述
1 getXYPlot() 此方法返回节点图表作为XYPlot。使用XYPolt我们可以XY图表做了一些实用操作。

6. PiePlot 类

这个类是org.jfree.chart.plot包的一部分,来自同一个包扩展Plot 类。这个类提供了一些方法来创建饼图块。

类的构造函数

S.N. 构造方法及描述
1 PiePlot() 它创建了一个新的绘图。
2 PiePlot(PieDataset dataset) 它创建了一个绘图,饼图由指定的数据集。

类方法

S.N. 方法及描述
1 setStartAngle(double angle) 此方法设置起始角度和发送PlotChangeEvent向所有注册的侦听器

7. PiePlot3D 类

PiePlot3D类和PiePlot类在同一个包中的子类。因此,这两个类有相同的功能,PiePlot类只不过是用于创建3D图形。

类的构造函数

S.N. 构造方法及描述
1 PiePlot3D() 此构造函数创建没有数据集的新实例。
2 PiePlot3D(PieDataset dataset) 该构造函数创建一个饼图和使用指定的数据集三维效果。

类方法

S.N. 方法及描述
1 setForegroundAlpha(float alpha) 它设置alpha透明度并向所有发送PlotChangeEvent注册的侦听器。
2 setInteriorGap(double percent) 它设置了内部差距并发送PlotChangeEvent向所有注册的侦听器。这种控制的饼图绘图边缘与绘图区本身(即,其中部分标签显示的区域)之间的空间。这个方法是从父类PiePlot继承。

8. PlotOrientation 类

这是一个串行化类从org.jfree.chart.plot封装,它是用来显示一个二维曲线图的方位。方向可以是垂直的或水平的。它设置Y轴的方向。传统的绘图有一个垂直的Y轴。

字段摘要

S.N. 类型 字段 & 描述
1 PlotOrientation HORIZONTAL 为一个曲线图,其中所述范围轴(Y轴)是水平。
2 PlotOrientation VERTICAL 为一个曲线图,其中所述范围轴(Y轴)是垂直的。这个默认的方向。

类方法

S.N. 方法及描述
1 isHorizontal() 如果这个方向是水平的,此方法返回true,否则返回false。
2 isVertical() 如果这个方向是VERTICAL,此方法返回true,否则返回false。

9. XYPlot 类

这在org.jfree.chart.plot包可用一个通用类,并将其用于在(X,Y)对的形式标绘数据。这个曲线图可以从实现XYDataSet接口的任何其它类中使用的数据。 XYPlot利用一个XYItemRenderer的画在图上的每个点。

类的构造函数

S.N. 构造方法及描述
1 XYPlot() 该构造器没有数据集,无轴,无渲染器创建一个新的XYPlot实例。
2 XYPlot(XYDataset dataset,ValueAxis domainAxis,ValueAxis rangeAxis,XYItemRenderer renderer),此构造函数创建一个新的绘图并指定数据集,轴和渲染。

类方法

S.N. 方法及描述
1 setRenderer(XYItemRenderer renderer) 此方法设置渲染器的主要数据集,并发送更改事件向所有注册的侦听器。

10. NumberAxis 类

这个类是org.jfree.chart.axis封装,它可以访问任意轴的数值数据。当我们设置任何轴的范围为默认值,它根据所述数据的范围配合。但使用NumberAxis,类我们可以设置较低的利润率和定义域和值域轴的上侧边距。

类的构造函数

S.N. 构造方法及描述
1 NumberAxis( ) 这是NumberAxis一个默认的构造函数。
2 NumberAxis( java.lang.String label) 构造函数NumberAxis使用必要的默认值在哪里。

类方法

S.N. 方法及描述
1 setLowerMargin(double margin) 它为轴心的利润率较低(为轴心范围的百分比),并发送一个AxisChangeEvent所有已注册的侦听器。这个方法是从父类ValueAxis继承。
2 setUpperMargin(double margin) 它设置于所述轴的上缘(视轴范围的百分比),并发送一个AxisChangeEvent给所有注册的监听器。这种方法也存在于ValueAxis类。

11. XYLineAndShapeRenderer 类

这是在org.jfree.chart.renderer.xy包下的类,它需要连接数据点与线,并绘制形状,在每个数据点下是可用的。这个渲染器类是专为XYPlot类配合使用。

类的构造函数

S.N. 构造和描述
1 XYLineAndShapeRenderer() 它创建了一个新的渲染器有两种线条和形状可见。
2 XYLineAndShapeRenderer (boolean lines, boolean shapes) 它创建了一个新的渲染与特定的属性。

类方法

S.N. 方法及描述
1 setSeriesPaint(int series, java.awt.Paint paint) 此方法设置用于一系列的涂料,并发送RendererChangeEvent给所有注册的监听器。这个方法是从AbstratRenderer抽象类从渲染器包中JFreeChart的API。
2 setSeriesStroke(int series, java.awt.Stroke stroke) 此方法设置用于一系列的流程,并发送RendererChangeEvent向所有注册的侦听器。这个方法是从AbstratRenderer抽象类,它是这个包的超类。

12. XYItemRenderer通用数据集

这是用于使一个单一的(X,Y)格式项在XYPlot接口。org.Jfree.data.general包其具有类和接口,以定义不同类型的数据集来构造图。

PieDataset

这是作为一个通用的数据集,其中值与键相关联的接口。正如其名称所暗示的,可以使用这个数据集提供数据的饼图。此接口扩展KeyedValues数据集的接口。所有使用此接口的方法取自KeyedValues,Values和数据集的接口。

13. DefaultPieDataset 类

这是一个默认的实现类PieDataset接口。

类的构造函数

S.N. 构造函数和描述
1 DefaultPieDataset() 该构造函数创建一个新的数据集,初始为空。
2 DefaultPieDataset(KeyedValues data) 它从一个KeyedValues实例复制数据创建了一个新的数据集。

类方法

S.N. 方法及描述
1 setValue(java.lang.Comparable key, double value) 它设置数据值的键,发送DatasetChangeEvent向所有注册的侦听器。
2 setValue(java.lang.Comparable key, java.lang.Number value) 它设置数据值的键,发送DatasetChangeEvent向所有注册的侦听器。

14. SeriesException 类

这是一个异常类。它会引发发生在时间序列中数据集的数据的异常。异常是引发上的重复或无效数据的次数。时间序列不能与重复应用,格式必须是有效的。

15. DefaultCategoryDataset

这是一个默认的实现类CategoryDataset接口。

类的构造函数

S.N. 构造函数及描述
1 DefaultCategoryDataset() 此构造函数创建新的空数据集。

类方法

S.N. 方法及描述
1 addValue(double value, java.lang.Comparable rowKey, java.lang.Comparable columnKey) 这种方法增加了一个值,以使用可比的键表。
2 addValue(java.lang.Number value, java.lang.Comparable rowKey, java.lang.Comparable columnKey) 这种方法增加了一个值的表。
3 setValue(double value, java.lang.Comparable rowKey, java.lang.Comparable columnKey) 此方法添加或在表中更新的值,并发送aDatasetChangeEvent给所有注册的监听器。
4 setValue(java.lang.Number value, java.lang.Comparable rowKey, java.lang.Comparable columnKey) 此方法添加或在表中更新的值,并发送DatasetChangeEvent给所有注册的监听器。

参见JFreeChart的API,用于各种其他方法和字段的详细信息。

16. 序列数据集

系列数据集用于XY图表。该软件包是org.Jfree.data.xy,其中包含类和属于XY图表接口。核心接口是XYDataset。

XYDataset

这是通过该数据中的(X,Y)的项目的形式可被访问的接口。正如其名称所提示的,可以使用这个数据集服务XY图表。一些在这个接口中的方法都取自SeriesDateset接口。

XYZDataset

这是通过该数据的形式(x,y,z)的项目可被访问的接口。正如其名称所暗示的,可以使用这个数据集服务XYZ图。一些在这个接口中的方法都取自SeriesDateset。

XYSeries

这是一类,它代表了在所述形式的零个或多个数据项(x,y)的序列。默认情况下,该系列中的数据项都按升序排列由x值,并重复允许的x值。无论是排序和复制缺省值可以在构造函数中被改变。 Y值可以表示为空值代表缺失值。

类构造函数

S.N. 构造函数描述
1 XYSeries(java.lang.Comparable key) 该构造函数创建一个新的空系列。
2 XYSeries(java.lang.Comparable key, boolean autoSort) 它构造一个新的空系列,具有自动排序标志集的请求,并且重复的值是允许的。
3 XYSeries(java.lang.Comparable key, boolean autoSort, boolean allowDuplicateXValues) 它构造一个新的xy系列不包含任何数据。

类方法

S.N. 方法描述
1 add(double x, double y) 这种方法增加了数据项成系列。

在上述方法中使用的教程例子。如果想了解其余的方法和字段,请参考JFreeChart的API。

XYSeriesCollection

XYSeriesCollection类有类似父类AbstractIntervelDataset,AbstractXYDatset,AbstractSeriesDataset和AbstractDataset。一些在这个类中的方法属于这个类的父类。

类的构造函数

S.N. 构造函数描述
1 XYSeriesCollection() 它构造一个空的数据集。
2 XYSeriesCollection(XYSeries xyseries)它构建了一个数据集,并用一个系列的填充。

类方法

S.N. 方法及描述
1 addSeries(XYSeries series) 这种方法增加了一系列的收集和发送DatasetChangeEvent向所有注册的侦听器。
参见JFreeChart的API其余的方法和字段。  

DefaultXYZDataset

DefaultXYZDataset类都有父类,如AbstractIntervelDataset,AbstractXYDatset,AbstractSeriesDataset,AbstractDataset和AbstractXYZDataset。一些在这个类中的方法属于这一类的父类。

类的构造函数

S.N. 构造方法及描述
1 DefaultXYZDataset() 它构造一个空的数据集。

类方法

S.N. 方法及描述
1 addSeries(java.lang.Comparable seriesKey, double[ ][ ] data ) 该方法增加了一系列的收集和发送DatasetChangeEvent向所有注册的侦听器。

请参考JFreeChart的API,其余的方法和字段。

JFreeCharts的时间序列

该软件包是org.jfree.data.time。该软件包包含用于时间相关的数据的类和接口。

TimeSeries

此类表示数据项的期值的形式,其中一段是RegularTimePeriod抽象类,如时间,日,小时,分钟和秒类的一些实例序列。

类的构造函数

S.N. 构造方法及描述
1 TimeSeries(java.lang.Comparable name) 它创建新的空系列。
2 TimeSeries(java.lang.Comarable name, java.lang.String domain, java.lang.Strin range) 它会创建一个不包含任何数据的新的时间序列。

类方法

S.N. 方法及描述
1 add(RegularTimePeriod period,double value) 该方法增加了一个新的数据项用以串联。

其余的方法和字段参见JFreeChart的API。

TimeSeriesCollection

这是作为时间序列的对象的集合的类。这个类实现了XYDataset接口,以及它扩展了IntervelXYDataset接口。这使得它可以方便地收集序列数据对象。

类的构造函数

S.N. 构造方法及描述
1 TimeSeriesCollection() 它构造一个空的数据集,绑在默认时区。
2 TimeSeriesCollection(TimeSeries series) 它构造一个包含单个系列(更多可添加),绑在默认时区的数据集。
3 TimeSeriesCollection(TimeSeries series, java.util.TimeZone zone) 它构造包含单个系列(更可添加),绑定到特定的时间段的数据集。
4 TimeSeriesCollection(java.util.TimeZone zone) 它构造一个空的数据集时,绑定到特定的时间区。

类方法

S.N. 方法及描述
1 addSeries(TimeSeries series) 方法增加了一系列的收集和发送DatasetChangeEvent向所有注册的侦听器。

其余的方法和字段请参考JFreeChart的API。

Second类

这个类表示一个特定的日子一秒钟。这个类是不可变的,这是对所有RegularTimePeriod子类的要求。

类的构造函数

S.N. 构造函数及描述
1 Second() 它构造一个新的Second,基于系统的日期/时间。
2 Second(java.util.Date time) 它构造从指定日期/时间和默认时区的新实例。
3 Second(java.util.Date time, java.util.TimeZone zone, java.util.Locale locale) 它创建基于所提供的时间和时区的新的Second对象。
4 Second(int second, int minute, int hour, int day, int month, int year)它创建了一个新的Second对象。
5 Second(int second, Minute minute) 它构建了一个新的Second。

类方法

S.N. 方法及描述
1 getSecond() 它返回分钟和秒。
2 next() 它返回当前的下一秒。

其余的方法和字段请参考JFreeChart的API。

JFreeCharts中的帧

该软件包是org.jfree.ui。这是包所属JFreeChart的JCommons的API。它包含用于创建预配置的图表框架的实用程序类。

ApplicationFrame

这是用于创建简单的应用程序的主框架的基类。帧监听窗口关闭事件,并作出反应,关闭JVM。这是很好的小型演示应用。对于企业应用程序,需要使用一些更稳健的东西。在这个类中的主要核心方法取自Component, Container, Window, Frame 和Jframe类。

类构造函数

S.N. 构造方法及描述
1 ApplicationFrame(java.lang.String title) 它会创建一个字符串标题的应用程序框架。

这个类有助于创建AWT框架。这就是为什么我们使用这个类作为父类在本教程中的例子的原因。

其采取父类的方法用于打开一个框架,关闭一个框架,改变大小,改变背景或前景颜色和监听器。

RefineryUtilities

这是关于用户界面的工具方法的类的集合。

类方法

S.N. 方法及描述
1 centerFrameOnScreen(java.awt.Window frame) 它定位在屏幕的中间的指定帧。

在上述方法中使用的教程例子以外的类,方法和字段参见JFreeChart的API。

五. 高级用法

1. 图形的展示与保存


package plot;
 
import java.io.File;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
 
public class Example {
	public static void main(String[] args) throws IOException {
		
		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
	    dataset.addValue( 15 , "schools" , "1970" );
	    dataset.addValue( 30 , "schools" , "1980" );
	    dataset.addValue( 60 , "schools" , "1990" );
	    dataset.addValue( 120 , "schools" , "2000" );
	    dataset.addValue( 240 , "schools" , "2010" ); 
	    dataset.addValue( 300 , "schools" , "2014" );
	    
	    // 创建JFreeChart对象
	    JFreeChart chart = ChartFactory.createLineChart(
	         "Example",  // 图标题
	         "Year",  // x轴
	         "Schools Count",// y轴
	         dataset,
	         PlotOrientation.VERTICAL,
	         false,true,false);
	    
	    // 保存到本地(PNG或者JPEG格式)
	    File f = new File( "chart.png" ); 
	    ChartUtilities.saveChartAsPNG(f ,chart, 800 ,400);
        // 保存为矢量图形(需要借助JFreeSVG包)
        SVGGraphics2D g2 = new SVGGraphics2D(640, 480);
        chart.draw(g2, new Rectangle(640, 480));
        File f = new File("SVGBarChartDemo.svg");
        SVGUtils.writeToSVG(f, g2.getSVGElement());
 
	    // 利用swing进行展示
	    JPanel jPanel = new ChartPanel(chart);
        JFrame frame = new JFrame("JFreechart Test");
        frame.add(jPanel);
        frame.setBounds(0, 0, 800, 500);
        frame.setVisible(true);
 
        // 利用awt进行显示
        ChartFrame chartFrame = new ChartFrame("Test", chart);
        chartFrame.pack();
        chartFrame.setVisible(true);      
        
	}
}

2. 通用设置

package plot;
 
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.RectangleEdge;
 
public class Test {
	public static void main(String[] args) {
		
		
		// 添加数据集
        DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
        dataSet.addValue(3542, "2020年", "第一季度");// Y轴-图例-X轴
        dataSet.addValue(3692, "2020年", "第二季度");// Y轴-图例-X轴
        dataSet.addValue(8542, "2020年", "第三季度");// Y轴-图例-X轴
        dataSet.addValue(5742, "2020年", "第四季度");// Y轴-图例-X轴
 
        dataSet.addValue(1242, "2021年", "第一季度");// Y轴-图例-X轴
        dataSet.addValue(2612, "2021年", "第二季度");// Y轴-图例-X轴
        dataSet.addValue(1942, "2021年", "第三季度");// Y轴-图例-X轴
        dataSet.addValue(4612, "2021年", "第四季度");// Y轴-图例-X轴
        
        
        // 主题样式设置
        StandardChartTheme standardChartTheme = new StandardChartTheme("CN"); // 创建主题样式
        standardChartTheme.setExtraLargeFont(new Font("宋体", Font.BOLD, 64)); // 设置标题字体
        standardChartTheme.setRegularFont(new Font("宋体", Font.BOLD, 32)); // 设置图例的字体
        standardChartTheme.setLargeFont(new Font("宋体", Font.BOLD, 20)); // 设置轴向的字体
        standardChartTheme.setChartBackgroundPaint(Color.WHITE);// 设置主题背景色
        ChartFactory.setChartTheme(standardChartTheme);// 应用主题样式
 
        
        // 定义图表对象
        JFreeChart chart = ChartFactory.createLineChart(
        		// 图表的标题-横轴标题-纵轴标题-数据集
        		"JFreeChart折线图", "销售额", "季度", dataSet, 
        		// 图表方向-图例-工具提示-超链接
        		PlotOrientation.VERTICAL,true, false, false);
        // chart.setTitle(new TextTitle(title[0], new Font("宋书", Font.BOLD, 64)));// 重新设置标题
        // chart.removeLegend();// 是否移除图例
        CategoryPlot plot = (CategoryPlot)chart.getPlot(); // 获得图表显示对象
        plot.setOutlineVisible(false);// 是否显示外边框
        plot.setOutlinePaint(Color.WHITE);// 外边框颜色
        // plot.setOutlineStroke(new BasicStroke(2.f));// 外边框框线粗细
        plot.setBackgroundPaint(Color.WHITE);// 白色背景
        plot.setNoDataMessage("无图表数据");// 无数据提示
        plot.setNoDataMessageFont(new Font("宋体", Font.BOLD, 32));// 提示字体
        plot.setNoDataMessagePaint(Color.RED);// 提示字体颜色
 
        
        // 图例
        LegendTitle legend = chart.getLegend();// 图例对象
        legend.setPosition(RectangleEdge.BOTTOM);// 图例所在位置(上、下、左、右)
        legend.setVisible(true);// 是否显示图例
        legend.setBorder(2, 0, 0, 2); // 图例上下左右边框粗细
        legend.setItemFont(new Font("宋体", Font.BOLD, 32));// 图例大小
        
 
        // 网格线
        plot.setDomainGridlinePaint(Color.BLUE);
        plot.setDomainGridlinesVisible(true);// 竖线
        plot.setRangeGridlinePaint(Color.BLACK);
        plot.setRangeGridlinesVisible(true);// 横线
 
        
        // 横坐标
        CategoryAxis xAxis = plot.getDomainAxis();
        xAxis.setTickLabelFont(new Font("宋体", Font.BOLD, 25));// 设置X轴值字体
        xAxis.setLabelFont(new Font("宋书", Font.BOLD, 32));// 设置X轴标签字体
        xAxis.setAxisLineStroke(new BasicStroke(1f)); // 设置X轴线粗细
        xAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);// 倾斜
        xAxis.setAxisLinePaint(Color.BLACK);// 轴线颜色
        xAxis.setUpperMargin(0.18D);// 右边距
        xAxis.setLowerMargin(0.1D);// 左边距
 
        
        // 纵坐标
        ValueAxis yAxis = plot.getRangeAxis();
        yAxis.setTickLabelFont(new Font("宋体", Font.BOLD, 25));// 设置y轴字体
        yAxis.setLabelFont(new Font("宋体", Font.BOLD, 32));// 设置X轴标签字体
        yAxis.setAxisLineStroke(new BasicStroke(1f)); // 设置y轴线粗细
        yAxis.setAxisLinePaint(Color.BLACK);// 轴线颜色
        yAxis.setUpperMargin(0.18D);// 上边距
        yAxis.setLowerMargin(0.1D);// 下边距
 
        
        LineAndShapeRenderer r1 = new LineAndShapeRenderer();
        // 数据标签
        r1.setBaseItemLabelsVisible(true);// 是否显示数据标签
        r1.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());// 数据标签格式
        r1.setSeriesPaint(0, Color.BLUE);
        r1.setBaseShapesFilled(Boolean.TRUE); // 在数据点显示实心的小图标
        r1.setBaseShapesVisible(true); // 设置显示小图标
        r1.setBaseItemLabelFont(new Font("Dialog", Font.BOLD, 12));// 设置数字的字体大小
        r1.setBaseStroke(new BasicStroke(4f));
        // 线条颜色
        r1.setSeriesPaint(0, new Color(204, 232, 207)); 
        r1.setSeriesPaint(1, new Color(0x00, 0xff, 0xff)); 
        r1.setSeriesShapesVisible(0,  false);
        r1.setSeriesShapesVisible(1,  false);
        plot.setDataset(dataSet);
        // 应用以上设置
        plot.setRenderer(r1); 
 
        // 条形图间距设置
        // BarRenderer r = (BarRenderer) plot.getRenderer();
		// renderer.setItemMargin(0.01);
 
        
        
        // 显示图表
        ChartFrame chartFrame = new ChartFrame("Test", chart);
        chartFrame.pack();
        chartFrame.setVisible(true);  
	}
 
}

3. 其他设置

3.1 坐标轴刻度设置

package com.test;
 
import java.io.File;
import java.io.IOException;
 
import javax.swing.JFrame;
import javax.swing.JPanel;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
 
public class Test {
 
	public static void main(String[] args) throws IOException {
		
		// 创建数据
		final XYSeries data = new XYSeries( "InternetExplorer" );
		data.add( 1.0 , 4.0 );          
		data.add( 2.0 , 5.0 );          
		data.add( 3.0 , 4.0 ); 
		data.add( 4.0 , 5.0 );          
		data.add( 5.0 , 4.0 );          
		data.add( 6.0 , 5.0 );
		data.add( 6.0 , 4.0 ); 
		data.add( 7.0 , 5.0 ); 
		data.add( 8.0 , 4.0 ); 
		data.add( 9.0 , 5.0 ); 
		final XYSeriesCollection dataset = new XYSeriesCollection( );        
		dataset.addSeries(data);
	    
	    // 创建JFreeChart对象
	    JFreeChart chart = ChartFactory.createXYLineChart(
	    		"Example", "X", "Y", dataset,
	    		PlotOrientation.VERTICAL,
	    		false, true, false);
 
	    // 设置坐标轴刻度间距
	    XYPlot plot = (XYPlot) chart.getPlot();
	    NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();  
	    xAxis.setTickUnit(new NumberTickUnit(2));
	    
	    // 保存到本地
	    File lineChart = new File( "1.png" ); 
	    ChartUtilities.saveChartAsPNG(lineChart ,chart, 1000 ,500);
 
	}
 
}

六. 其他图表

  1. 时间序列图

时间序列图


package plot;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.time.Month;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.ui.TextAnchor;
 
import javax.swing.*;
import java.awt.*;
import java.text.SimpleDateFormat;
 
public class TimeSeriesChart {
    private TimeSeriesChart() {
 
        // A网站的访问量统计
        @SuppressWarnings("deprecation")
		TimeSeries timeSeries1 = new TimeSeries("A", Month.class);
        // 添加数据
        timeSeries1.add(new Month(1, 2016), 154);
        timeSeries1.add(new Month(2, 2016), 256);
        timeSeries1.add(new Month(3, 2016), 312);
        timeSeries1.add(new Month(4, 2016), 489);
        timeSeries1.add(new Month(5, 2016), 563);
        timeSeries1.add(new Month(6, 2016), 555);
        timeSeries1.add(new Month(7, 2016), 359);
        timeSeries1.add(new Month(8, 2016), 291);
        timeSeries1.add(new Month(9, 2016), 123);
        timeSeries1.add(new Month(10, 2016), 438);
        timeSeries1.add(new Month(11, 2016), 286);
 
        // A网站的访问量统计
        TimeSeries timeSeries2 = new TimeSeries("A", Month.class);
        // 添加数据
        timeSeries2.add(new Month(1, 2016), 124);
        timeSeries2.add(new Month(2, 2016), 326);
        timeSeries2.add(new Month(3, 2016), 12);
        timeSeries2.add(new Month(4, 2016), 567);
        timeSeries2.add(new Month(5, 2016), 546);
        timeSeries2.add(new Month(6, 2016), 123);
        timeSeries2.add(new Month(7, 2016), 222);
        timeSeries2.add(new Month(8, 2016), 545);
        timeSeries2.add(new Month(9, 2016), 56);
        timeSeries2.add(new Month(10, 2016), 543);
        timeSeries2.add(new Month(11, 2016), 221);
 
        // 定义时间序列的集合
        TimeSeriesCollection lineDataset = new TimeSeriesCollection();
        lineDataset.addSeries(timeSeries1);
        lineDataset.addSeries(timeSeries2);
 
 
//         JFreeChart chart = ChartFactory.createXYStepChart("Time line graph", "M", "F", xySeriesCollection, PlotOrientation.HORIZONTAL, false, false, false);
        JFreeChart chart = ChartFactory.createTimeSeriesChart("Time line graph", "M", "F", lineDataset, false, false, false);
        //设置主标题
        chart.setTitle(new TextTitle("A,B网站访问量统计对比图"));
        //设置子标题
        TextTitle subtitle = new TextTitle("2016年度", new Font("宋体", Font.BOLD, 12));
        chart.addSubtitle(subtitle);
 
        chart.setAntiAlias(true);
 
        //设置时间轴的范围。
        XYPlot plot = (XYPlot) chart.getPlot();
        DateAxis dateaxis = (DateAxis) plot.getDomainAxis();
        dateaxis.setDateFormatOverride(new SimpleDateFormat("M"));
        dateaxis.setTickUnit(new DateTickUnit(DateTickUnit.MONTH, 2));
 
        //设置曲线是否显示数据点
        XYLineAndShapeRenderer xylinerenderer = (XYLineAndShapeRenderer) plot.getRenderer();
        xylinerenderer.setBaseShapesVisible(true);
 
        //设置曲线显示各数据点的值
        XYItemRenderer xyitem = plot.getRenderer();
        xyitem.setBaseItemLabelsVisible(true);
        xyitem.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER));
        xyitem.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator());
        xyitem.setBaseItemLabelFont(new Font("Dialog", Font.BOLD, 12));
        plot.setRenderer(xyitem);
 
        JPanel jPanel = new ChartPanel(chart);
        JFrame frame = new JFrame("JFreechart Test");
        frame.add(jPanel);
        frame.setBounds(0, 0, 800, 600);
        frame.setVisible(true);
    }
 
    public static void main(String[] args) {
        TimeSeriesChart timeSeriesChart = new TimeSeriesChart();
    }
}
  1. XY阶梯面积图

XY阶梯面积图


package plot;
 
import java.awt.Color;
import java.io.IOException;
 
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
 
public class Example {
	public static void main(String[] args) throws IOException {
 
		// 创建XYSeriesCollection对象
		XYSeriesCollection dataset = new XYSeriesCollection();
		// 系列一数据
		XYSeries series1 = new XYSeries("Series1");
		series1.add(2, 4);
		series1.add(3, 6);
		series1.add(5, 2);
		series1.add(8, 5);
		series1.add(1, 8);
 
		// 系列二数据
		XYSeries series2 = new XYSeries("Series2");
		series2.add(5, 6);
		series2.add(9, 5);
		series2.add(10, 9);
		series2.add(18, 11);
		series2.add(15, 18);
		// 添加到数据集
		dataset.addSeries(series1);
		dataset.addSeries(series2);
 
		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createXYStepAreaChart("XY Step Area Chart", // Chart Title
				"X-Axis", // X-Axis Label
				"Y-Axis", // Y-Axis Label
				dataset);
 
		XYPlot plot = (XYPlot) chart.getPlot();
		plot.setBackgroundPaint(new Color(229, 150, 97, 60));
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
 
	}
 
}
  1. 条形图与折线图结合

条形图与折线图结合

package plot;
 
import java.io.IOException;
 
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
 
public class ShowExample {
	public static void main(String[] args) throws IOException {
 
		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(1.0, "A", "Ⅰ");
		dataset.addValue(3.0, "A", "Ⅱ");
		dataset.addValue(5.0, "A", "Ⅲ");
		dataset.addValue(5.0, "A", "Ⅳ");
		dataset.addValue(5.0, "B", "Ⅰ");
		dataset.addValue(6.0, "B", "Ⅱ");
		dataset.addValue(10.0, "B", "Ⅲ");
		dataset.addValue(4.0, "B", "Ⅳ");
 
		// 创建CategoryPlot对象
		CategoryPlot plot = new CategoryPlot();
 
		// 添加第一个数据集并渲染为line
		CategoryItemRenderer lineRenderer = new LineAndShapeRenderer();
		plot.setDataset(0, dataset);
		plot.setRenderer(0, lineRenderer);
 
		// 添加第二个数据集并渲染为线条bar
		CategoryItemRenderer baRenderer = new BarRenderer();
		plot.setDataset(1, dataset);
		plot.setRenderer(1, baRenderer);
 
		// 设置坐标轴
		plot.setDomainAxis(new CategoryAxis("Time"));
		plot.setRangeAxis(new NumberAxis("Value"));
 
		// 创建JFreeChart对象
		JFreeChart chart = new JFreeChart(plot);
 
		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
 
	}
 
}

文章抄自:Java绘图库JFreeChart的详细使用教程(入门级)