转载请注明出处!
其实JFreeChart就没有绘制曲线的功能,绘制折线图是可以的,但是我们可以通过数据量增大的方式,让点足够密集变成曲线,如果没有足够的数据量,可以通过后期算法加工的方式,在两个点之间获取很多的点形成曲线,我们这里使用的是ChartFactory.createLineChart方法绘制。
org.jfree
jfreechart
1.0.19
下面这是一个简单的Demo,代码不复杂,我也没写全备注,大家先复制下来运行成功,看懂代码,然后继续往下看。
package com.xxx.xx.action;
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.plot.PlotOrientation;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import com.topscomm.dist.util.CreateChartUtil;
import java.awt.*;
public class TestWord extends ApplicationFrame {
public TestWord(String titile){
//程序入口
super(titile);
//获取曲线数据,这里面是我自己造的一条
CategoryDataset dataset=createDataset();
//再用数据获取jfreechart对象,这里使用的是createLineChart折线图
JFreeChart chart=createChart(dataset);
获取panel,可以用它来设置很多样式的参数,这里就先俺默认了
ChartPanel chartPanel=new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(800,500));
//这个是jfreechart内部的方法
setContentPane(chartPanel);
}
private CategoryDataset createDataset(){
DefaultCategoryDataset dataset=new DefaultCategoryDataset();
dataset.addValue(212,"Letter","A");
dataset.addValue(504,"Letter","B");
dataset.addValue(1520,"Letter","C");
dataset.addValue(1842,"Letter","D");
dataset.addValue(2991,"Letter","E");
return dataset;
}
private JFreeChart createChart(CategoryDataset dataset){
JFreeChart chart= ChartFactory.createLineChart(
"Line Chart Demo",
"Category Axis",
"Value Axis",
dataset
);
return chart;
}
public static void main(String args[])throws Exception{
//程序执行从构造方法开始
TestWord demo=new TestWord("曲线示例");
//下面这些是弹框展示用的
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
运行后会弹出一个窗口来,这就是我们绘制的曲线图,其严格来说还不能称之为曲线图,但又在某种意义上可以,那么如何将其变成一个曲线图呢?请继续往下看
想要平滑曲线,就需要足够多的数据,比如说将上图的A-B切分为1000份,这样代码不用改动,只对数据进行处理,就会得到平滑的曲线,如图:
当然,具体怎么获取很多的数据,完全取决于你的算法,你想让曲线是怎样的一个斜率,都是由你怎么切分数据决定的。
下面再贴一段关于如何设置曲线样式的代码,下面代码无法直接运行,但里面有很详细的注释,设置样式的方式可以参考:
/**
* @description:
* @author: niu
* @date: 2022年4月7日下午4:34:03
* @modify:
*/
package com.xxx.xx.util;
import com.xxx.xx.util.dascore.ChartDto;
import com.xxx.xx.util.dascore.Serie;
import com.xxx.xx.util.dascore.DateStyle;
import com.xxx.xx.util.dascore.DateUtil;
import org.jfree.chart.*;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.PieLabelLinkStyle;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.chart.renderer.xy.StandardXYBarPainter;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;
import org.springframework.stereotype.Service;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.text.NumberFormat;
import java.util.*;
import java.util.List;
import javax.imageio.ImageIO;
/**
* 说明:
*
* @description:
* @program:
* @author: nwd
* @create: 2022-07-18 18:05
**/
@Service
public class CreateChartUtil{
private static final String NO_DATA_MSG = "数据加载失败";
private static final Font FONT = new Font("simsun", Font.PLAIN, 12);
//颜色
/*public static Color[] CHART_COLORS = {
new Color(253,236,109),
new Color(31,129,188),
new Color(255,117,153),
new Color(158,90,102),
new Color(255,204,102)
};*/
//颜色
public Color[] CHART_COLORS = {
new Color(255,255,0),
new Color(0,255,0),
new Color(255,0,0),
new Color(0,0,255),
new Color(103, 78, 167)
};
/*
* 静态代码块
*/
static{
//setChartTheme();
}
private void setChartTheme(){
// 设置中文主题样式 解决乱码
StandardChartTheme chartTheme = new StandardChartTheme("CN");
// 设置标题字体
chartTheme.setExtraLargeFont(FONT);
// 设置图例的字体
chartTheme.setRegularFont(FONT);
// 设置轴向的字体
chartTheme.setLargeFont(FONT);
chartTheme.setSmallFont(FONT);
chartTheme.setTitlePaint(new Color(51, 51, 51));
chartTheme.setSubtitlePaint(new Color(85, 85, 85));
chartTheme.setLegendBackgroundPaint(Color.WHITE);
chartTheme.setLegendItemPaint(Color.BLACK);
chartTheme.setChartBackgroundPaint(Color.WHITE);
// 绘制颜色绘制颜色.轮廓供应商
// paintSequence,outlinePaintSequence,strokeSequence,outlineStrokeSequence,shapeSequence
Paint[] OUTLINEPAINTSEQUENCE = new Paint[]{Color.WHITE};
// 绘制器颜色源
DefaultDrawingSupplier drawingSupplier = new DefaultDrawingSupplier(CHART_COLORS, CHART_COLORS, OUTLINEPAINTSEQUENCE,
DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE, DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE);
chartTheme.setDrawingSupplier(drawingSupplier);
chartTheme.setPlotBackgroundPaint(Color.BLACK);// 绘制区域
chartTheme.setPlotOutlinePaint(Color.WHITE);// 绘制区域外边框
chartTheme.setLabelLinkPaint(new Color(8, 55, 114));// 链接标签颜色
chartTheme.setLabelLinkStyle(PieLabelLinkStyle.CUBIC_CURVE);
chartTheme.setAxisOffset(new RectangleInsets(5, 12, 5, 12));
chartTheme.setDomainGridlinePaint(new Color(192, 208, 224));// X坐标轴垂直网格颜色
chartTheme.setRangeGridlinePaint(new Color(0, 0, 0));// 用于标识Y轴刻度的横向线条颜色
chartTheme.setBaselinePaint(Color.WHITE);
chartTheme.setCrosshairPaint(Color.BLUE);// 不确定含义
chartTheme.setAxisLabelPaint(new Color(51, 51, 51));// 坐标轴标题文字颜色
chartTheme.setTickLabelPaint(new Color(67, 67, 72));// 刻度数字
chartTheme.setBarPainter(new StandardBarPainter());// 设置柱状图渲染
chartTheme.setXYBarPainter(new StandardXYBarPainter());// XYBar 渲染
chartTheme.setItemLabelPaint(Color.black);
chartTheme.setThermometerPaint(Color.white);// 温度计
ChartFactory.setChartTheme(chartTheme);
}
/**
* 创建折线图
*
* @param title 折线图标题
* @param xtitle x轴标题
* @param ytitle y轴标题
* @param categorie 横坐标类别
* @param series 数据集
* @return
* @throws Exception
*/
private ChartPanel createChart(String title, String xtitle, String ytitle, java.util.List categorie, List
在数学上,求一个点的导数是有公式的,假如曲线上有两个横坐标无限接近的点(n,w)和(n+x,w+y)
那么(n,w)点的导数就是(w+y-w)/(n+x-n)=y/w,同样的,我们上面已经得到了大量的点坐标,并且已经形成曲线,这就说明我们的点是离的够近的,我们可以用这种算法,将数据都循环计算一遍,从而得到一个曲线的导数的曲线。
注意:这样算是有误差的,但是曲线的形状基本上是对的,如果你追求非常精确的话,请再研究一下别的方法。
存疑:很奇怪的是,数学上是按照我刚才说的那么算,但是公司的算法部有个大佬告诉我,直接用w+y-w就是导数,而且我问他为什么这么做,他也不告诉我,如果有朋友知道的话麻烦告诉我一下,我的曲线是个sin正弦函数,可能是因为这个。