Monday, January 14, 2008

JFreeChart 1.0.9 Released

Dave Gilbert recently announced the release of JFreeChart 1.0.9. The release notes for this release are conveniently available in the General JFreeChart Forum.

I am pleased to report that the sample code associated with the Oracle Technology Network (OTN) article Visualize Your Oracle Database Data with JFreeChart works properly using this new release.

11 comments:

cuevasgp said...

Dustin, just saw your article on OTN. Great job! I plan to try out some of the examples.
Glenda Sutphen

Dustin said...

Glenda,

It's nice to hear from you. I hope you enjoy JFreeChart.

Manvendra said...

Dustin,
I saw your article on OTN and then googled your name to come here. If you have a few minutes...

I am not a java developer but would like to generate chart images from within the database as a part of a batch process.

To this effect, I followed this oracle forum thread:

http://forums.oracle.com/forums/thread.jspa?messageID=1272903

But get a nullpointer exception at the line:

BufferedImage bufferedImage = chart.createBufferedImage(width, height);

Would you have any advice as to what I might do next, or any reference to sample code that you know of?

thanks very much,
MSJ.

Dustin said...

MSJ,

I quickly looked at the forum thread you referenced and noted the following from that entry:

/* Create JFreeChart! */
//JFreeChart chart = SeriesDataset(dataset);
JFreeChart chart = null; // really import part missing! how to make chart??
/* Create BufferedImage */
BufferedImage bufferedImage = chart.createBufferedImage(width, height);

I added bold marking to the offending pieces of code. You are seeing the NullPointerException because the chart variable is initialized as null, is never changed to actually point to anything real, and then an attempt is made to call a method on this value that is still only null.

You will need to get an actual JFreeChart instance. The easiest way to do this is to use ChartFactory and call one of its createXXXChart methods. For example, Listing 1 in the Visualize Your Oracle Database Data with JFreeChart demonstrates creating a pie chart with the ChartFactory.createPieChart method.

The thread you referenced seems to be using a Category Dataset, so a likely method that could be used with that to create a JFreeChart is ChartFactory.createBarChart, though any method on the ChartFactory class that accepts a CategoryDataset could be used.

An example of creating a bar chart with a CategoryDataset and ChartFactory.createBarChart is contained in Listing 4 of the article.

Manvendra said...

Dustin,
thank you very much!

MSJ

Manvendra said...

Hi Dustin,
I got a chart to render in the db jvm and save it to a blob. Thanks for your help. One more question if you have a few minutes...

I think the answer is no as I have searched the jfreechart forums...

Would it be possible to hack up a chart to look like this timeline?

http://www.timelinemaker.com/product-samplecharts-skiaccident.html

thanks,
msj

Dustin said...

MSJ,

While nearly anything is possible with JFreeChart with enough hacking and customization, a chart as detailed and specific as the one you reference would not be a trivial task to implement with JFreeChart unless there was already something available close to it and I am not aware of any such chart.

Manvendra said...

Once again, Thanks!

Greg said...

Thanks for you work on the OTN Article. It gave me some inspiration.

While trying to work with JFreeChart I ran into this error. I am working in the Oracle DB JVM.

These lines:

ChartUtilities.saveChartAsPNG
BufferedImage bufferedImage = chart.createBufferedImage

Always give me a null pointer exception. The chart is created.

This has caused me some grief so any help would be appreciated.



create or replace java source named ???????.LASER_MH_EVENTS_GRAPH_JV as
import java.sql.*;
import java.util.*;
import java.net.*;
import oracle.jdbc.*;
import oracle.sql.*;

import java.io.File;
import javax.sql.*;


import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.title.TextTitle;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.data.jdbc.JDBCPieDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.chart.encoders.ImageFormat;
import org.jfree.chart.encoders.EncoderUtil;



import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import oracle.sql.BLOB; //output picture
import oracle.sql.CLOB; //input xml
import java.sql.SQLException;

import org.jfree.chart.JFreeChart;

import org.jfree.data.category.CategoryDataset;






public class LASER_REP_MH_EVENTS_BARGRAPH {

private static Connection _conn;
private static CallableStatement _htpPrintCall;




public static void buildGraph(String ps_eiacodxa) throws SQLException
{





_conn = DriverManager.getConnection("jdbc:default:connection:");
_htpPrintCall = _conn.prepareCall("{call htp.p(?)}");



DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.setValue(6, "Profit", "Jane");
dataset.setValue(7, "Profit", "Tom");
dataset.setValue(8, "Profit", "Jill");
dataset.setValue(5, "Profit", "John");
dataset.setValue(12, "Profit", "Fred");
JFreeChart chart = ChartFactory.createBarChart("Comparison between Salesman",
"Salesman", "Profit", dataset, PlotOrientation.VERTICAL, false,
true, false);
if(chart == null)
{
htpPrint("chart is null.");
}

htpPrint(chart.toString());

chart.setTitle("This is a title to end all titles.");


TextTitle tt = chart.getTitle();



htpPrint(tt.getText());




/* null pointer for bufferedImage */
BufferedImage bufferedImage = chart.createBufferedImage(500, 300);
Create Blob data!(byte[])
byte[] blobData;
try {
blobData = EncoderUtil.encode(bufferedImage, ImageFormat.JPEG);
} catch (IOException ex) {
htpPrint("Couldn't encode picture");
}



try {
ChartUtilities.saveChartAsPNG(new File("/oracle/mmis_graphs/chart2.jpg"), chart, 500,
300);

} catch (IOException e) {
htpPrint("Problem occurred creating chart.");
}
catch (NullPointerException npe) {
htpPrint("message " + npe.getMessage() + "here dude"+ npe.getLocalizedMessage());
}





}
public static void htpPrint(String str) throws SQLException {
_htpPrintCall.setString(1, str);
_htpPrintCall.execute();
}
}
/
alter java source ???????.LASER_MH_EVENTS_GRAPH_JV compile
/

CREATE OR REPLACE PROCEDURE ???????.HTP_LASER_MHEVENTS_GRAPH (
ps_query varchar2)
AS LANGUAGE JAVA
NAME 'LASER_REP_MH_EVENTS_BARGRAPH.buildGraph(java.lang.String)';

-- ***** START GRANTS ***** --

/
GRANT EXECUTE ON ???????.HTP_LASER_MHEVENTS_GRAPH TO ???????_READONLY_ROLE
/
GRANT EXECUTE ON ???????.HTP_LASER_MHEVENTS_GRAPH TO ???????_USER_ROLE
/

-- ***** END GRANTS ***** --


--***** START SYNONYM ***** --

CREATE OR REPLACE PUBLIC SYNONYM HTP_LASER_MHEVENTS_GRAPH
FOR ???????.HTP_LASER_MHEVENTS_GRAPH
/

--***** END SYNONYM ***** --

--***** START SYNONYM ***** --

CREATE OR REPLACE PUBLIC SYNONYM LASER_MH_EVENTS_GRAPH_JV
FOR ???????.LASER_MH_EVENTS_GRAPH_JV
/

--***** END SYNONYM ***** --

Dustin said...

Greg,

I can't see anything obvious in your code that would lead to this problem and quickly reviewing the underlying source code for this method doesn't shed any light on it for me either.

I agree with the assessment here that this appears to be a low-level AWT implementation issue, especially because nothing high-level looks like an obvious problem.

Greg said...

The source code works fine in other environments. The Oracle JVM needs to be set to AWT.headless=true. However, I have not been able to do this. I have found white papers that state you can do this with

-Djava.awt.headless=true

It does not seem to affect the system in anyway. I am trying to find other ways of doing this. If you know of any way I would be happy to try it.

I need to get the chart obejct into a blob field that I can get out to users on demand. Or write to the DB server file system.

Thanks for your help.