Predefined Data Classes
Describes the various classes available in the
ilog.views.chart.data package and its subpackages, and how to use them to display your application data.
Describes the various data set classes and how to use them.
Describes the various data source classes and how to use them.
Data set classes
This section describes the various data set classes and explains how to use them.
Data set classes hierarchy
Illustrates the data set class hierarchy.
Data Set Classes Hierarchy
Abstract implementation
The
IlvAbstractDataSet class provides default implementations for most of the methods in the
IlvDataSet interface. For example, it provides support for listeners, properties handling, access to data limits, and spatial requests.
To create a concrete data set as a subclass of IlvAbstractDataSet, you need to provide an implementation for the following methods:
public abstract int getDataCount();
public abstract double getXData(int idx);
public abstract double getYData(int idx);
In other words, you have to provide the indexed access to data points. As
IlvAbstractDataSet defines no-op methods for writing operations, the
setData and
addData methods need to be overridden as if you want your data set to be editable.
The IlvAbstractDataSet class is usually the preferred choice to write a custom data set, as it greatly simplifies the work that needs to be done. However, there may be cases with more suitable alternatives, for example:
You need to control the implementation of all methods defined in the
IlvDataSet interface so that the result matches more closely the structure of your original data.
The data set that you want to implement can be expressed as a combination of values stored in existing data sets. In that case the
IlvCombinedDataSet class can be the best choice. More information on the
IlvCombinedDataSet class can be found in section
Data set combination.
Your data set is just an extension of one of the provided concrete implementations (for example
IlvDefaultDataSet ).
In-memory implementation
The
IlvDefaultDataSet class provides a concrete data set implementation, where data points are stored in memory with arrays of double primitives. This class supports writing operations such as appending a new data point or changing values of an existing data point.
By using the IlvDefaultDataSet class, you can specify whether x-values should be stored in memory or computed according to the indices of data points (such data sets are also called category data sets, because x-values correspond to a category number). You can also specify whether the array provided to initialize the data set contents should be copied.
Here are several examples of in-memory data sets creation.
// Create an empty data set that stores x-values.
IlvDataSet ds1 = new IlvDefaultDataset("DS1");
// Create a category data set and initialize it with a copy of
// the specified y-values.
double[] yValues = new double[] {3., 1., 4.5, 2., 7., 6.3};
IlvDataSet ds2 = new IlvDefaultDataset("DS2", yValues);
// Create a set and initialize the specified x-values and y-values
// arrays.
double[] xValues = new double[] {1., 2., 4., 6., 7., 8.};
double[] yValues = new double[] {3., 1., 4.5, 2., 7., 6.3};
IlvDataSet ds3 = new IlvDefaultDataset("DS3", xValues, yValues, false);
Alternatively, you can create data sets from an
N-dimensional array of doubles with the
create method:
double[][] data = new double[][]
{
{1.8, 2., 2.7, 4.5, 4.8, 2.8, 2., 2.2, 3.3, 3.5, 2.2, 1.8},
{2.1, 1., 6.6, 6.8, 8.0, 2.4, 3., 1.5, 1.5, 0.7, 0.7, 2.2},
{0.9, 0.9, 2.3, 3., 2.1, 3.4, 3.8, 5.1, 1.5, 6., 5.5, 0.4},
{1.4, 0.4, 3.8, 2.7, 6.9, 1., 0.7, 1., 2.3, 2.2, 2.4, 2.5}
};
String[] names = { "Norm", "1998", "1999", "2000"};String[] dataLabels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
// Create data sets from the specified data values, data labels,
// and data set names.
IlvDataSet[] dataSets = IlvDefaultDataSet.create(data, -1, names, dataLabels);
Fixed-size storage
The
IlvCyclicDataSet class is a subclass of
IlvDefaultDataSet that allows only a limited number of data points to be stored in memory. When new data is appended beyond this limit, the oldest values are removed so that the cardinality remains the same.
This class is particularly useful for real-time charting where new data comes in a constant stream, and only a restricted history of past values should be kept.
The following restrictions apply when using the IlvCyclicDataSet class:
The
visible range of the
x-axis of any chart displaying a cyclic data set must be contained within the
x-limits of this data set.
Data indices are mutable in a cyclic data set. This means that objects like rendering hints or
annotations cannot refer to a data point by its index (more information on rendering hints and annotations can be found in
Handling chart renderers).
Example: Using Cyclic Data Sets
The following code extract initializes an IlvCyclicDataSet with a buffer size equals to the value of the VISI_COUNT constant:
// Create the data sets. The data sets containing the random values are
// instances of IlvCyclicDataSet with a buffer size equal to VISI_COUNT and
// no x values storage.
inputData = new IlvCyclicDataSet("Input", VISI_COUNT, false);
chart = createChart();
IlvSingleChartRenderer r = createRenderer(chart);
chart.addRenderer(r, inputData);
The code below shows how new data points are added to the CyclicDataSet. In order to minimize the number of notifications, the addData() calls are wrapped between a startBatch()/endBatch() sequence:
void addData()
{
inputData.startBatch();
for (int j=0; j<UPDATE_COUNT; ++j) {
inputData.addData(0, RandomGenerator.rand(counter));
++counter;
}
inputData.endBatch();
}
Data set combination
The
IlvCombinedDataSet abstract class allows you to define a data set that can be expressed as a combination of one or several values from one or several data sets. Here are two examples.
Example: Creating a Data Set as the Moving Average of Another Data Set
The moving average of a data set is implemented by the
IlvMovingAvgDataSet class. The following code shows how to create a data set as the moving average of another data set using this predefined class:
IlvDataSet ds = ...; // original data set
IlvDataSet movingAvg = new IlvMovingAvgDataSet(ds, 10);
Example: Displaying the Average of Two Data Sets
For this example, two solutions are proposed:
First solution
Compute the corresponding average data points and store them in an in-memory data set (for example
IlvDefaultDataSet). Then, we need to explicitly register listeners to the original data sets so that we can update our in-memory data set (modify data points or append new ones).
Combine Data Set (1)
Second solution
Create a subclass of
IlvCombinedDataSet that references the original data sets and dynamically computes the average whenever the values of data points are queried.
Combine Data Set (2) illustrates the second solution:
Combine Data Set (2)
The following code extract shows an implementation of such a solution. The IlvCombinedDataSet subclass overrides the getYData(int idx) method to compute the value taking into account the points of the specified index of all datasets handled by this combined data set.
/**
* Returns the data resulting from an operation on the specified series.
*/
abstract protected double getData(double[] values);
/**
* Returns the y value of the data point at the specified index.
*/
public double getYData(int idx)
{
int count = getDataSetCount();
double[] values = new double[count];
for (int i=0; i<count; ++i)
values[i] = getDataSet(i).getYData(idx);
return getData(values);
}
This implementation actually delegates the value calculation to the abstract getData(double[] values) method that subclass should implement.
For example, to compute the average of the values, the implementation would be;
protected double getData(double[] values)
{
double total = 0.;
for (int i=0; i<values.length; ++i) {
total += values[i];
}
return total/values.length;
}
Compared to the first solution, the advantage of using a combined data set is twofold:
The data set combinations implicitly listen to the changes on the original data sets, so that they can send appropriate change events.
The generated data is dynamically evaluated, which saves memory.
The use of IlvCombinedDataSet is only suitable when the data can be calculated from the original data sets. For example, this is not the case if we want to represent the maximum value taken by data points across time.
In this situation, we have to keep track of former values and cannot rely only on the values available at a given time.
When the choice does exist between the two solutions, the following issues must be considered:
The tradeoff between saving memory and the overhead of computing the values dynamically. Sometimes, the expense of computing the values for complex operations outweighs the savings in memory.
Is the context dynamic or static? If the contents of the original data sets changes, you benefit from the implicit subscription made by
IlvCombinedDataSet. In this case, the use of dynamic evaluation is also justified, rather than storing pre-computed values. Likewise, using
IlvCombinedDataSet has an advantage if the behavior of the created data set should be dynamic (for example, it is implemented as a mutable function of the values in the original data sets).
Function Implementation
The
IlvFunctionDataSet abstract class is designed to represent a data set whose
y-values are computed by a function call.
To create a concrete data set as a subclass of
IlvFunctionDataSet, the
callFunction method must be implemented to perform the desired calculation. Function data sets are then instantiated by providing a definition domain and a number of examples.
Example: Data Set Representing the Cosine Function With a Point Every Degree
The complete source code of this example can be found in
<installdir>/jviews-charts/samples/logarithm/index.html.
Data Set Representing the Cosine Function With a Point Every Degree
IlvDataSet ds =
new IlvFunctionDataSet(0, 2*Math.PI, 361){
public double callFunction(double val){
return Math.cos(val);
}
};
The IlvFunctionDataSet class is primarily intended to represent mathematical functions, and has the advantage of not storing values into memory.
Load-On-Demand Data Set
The
IlvLODDataSet class implements a data set whose contents is loaded on demand. For more information on this feature, please refer to
Using Load-On-Demand.
Data Source Classes
This section describes the various data source classes and explains how to use them.
Data source classes hierarchy
Illustrates the data source class hierarchy.
Data Source Classes Hierarchy
Abstract implementation
The
IlvAbstractDataSource class stores the list of accessible data sets, and provides the reading methods to access this collection. It also manages a list of listeners that are notified of changes in the data source contents.
NOTE No method of this class is abstract. Concrete subclasses will usually implement the data set creation, and use the
initDataSets protected method to initialize the data source contents. Another alternative is to modify directly the list returned by the
getDataSetList protected method. All the writing methods have an empty implementation that needs to be overridden if the contents is editable from the outside.
Editable data source
The
IlvDefaultDataSource class is a direct subclass of
IlvAbstractDataSource that provides implementations for editing operations. It behaves as an editable data source where data sets can be added or removed explicitly, and can be used to access data that comes from different sources. This class is used by default by the chart renderers.
For more information, refer to
Creating the data model.
Reading data from an input source
The JViews Charts library defines
IlvInputDataSource as a general-purpose class for reading data from an input source. An input source can be of two forms:
generic
java.io.InputStream object
URL
A data reader (defined by the
IlvDataReader interface) is used to decode the data stored in the input source. This data reader is provided as parameter to the two
load methods of the
IlvInputDataSource class:
public void load(InputStream in, IlvDataReader reader) throws Exception
public void load(String url, IlvDataReader reader) throws Exception
By calling one of these load methods, you reinitialize the contents of the data source with the data sets extracted by the reader. The IlvDataReader interface defines the following methods to load data from the input source:
public IlvDataSet[] read(InputStream in) throws Exception
public IlvDataSet[] read(String url) throws Exception
You use IlvDataInputSource by writing a reader for each specific data format.
The JViews Charts library provides the following examples of custom data readers:
Example: stock
This example shows how to define a reader that reads quote values in CSV (Comma Separated Value) format.
Example: load-on-demand
This example shows how to read data stored as 32-bit integers from a binary stream.
I n this example, you create an instance of your reader and use it with either an InputStream or a URL description. Both parameters are provided to the IlvInputDataSource constructor, which loads the data automatically.
The following code is extracted from the Load-On-Demand example and shows how to use a custom reader with an
IlvInputDataSource.
Using a Custom Reader with an IlvInputDataSource
InputStream in = null;
try {
// Create the reader.
IlvDataReader reader = new BinaryInt32Reader();
// Create an InputStream from a file.
in = new BufferedInputStream(
new FileInputStream(
new File(System.getProperty("user.dir"),
"sampleData.dat")));
IlvInputDataSource sampleDataSource = new IlvInputDataSource(in, reader);
} catch (Exception x) {
x.printStackTrace();
System.err.println(x.getMessage());
} finally {
if (in != null) try {in.close();} catch (Exception x) {}
}
NOTE The InputStream object must be explicitly closed after the loading is performed, whereas connection and disconnection are automatically handled when using a URL.
Reading and writing data from an XML source
The JViews Charts library lets you export or import data in a predefined XML-based format. The
ilog.views.chart.data.xml package contains all the classes that are related to XML serialization:
IlvXMLDataReader, creates the data sets by interpreting the contents of an XML file.
In order to use the ilog.views.chart.data.xml package with Java™ SE 5, you need Apache™ Xerces 2.4.0 or higher in your CLASSPATH. A copy of Apache Xerces can be found in the <installdir>/jviews-framework/lib/ directory.
Reading data from an XML document
The
IlvXMLDataReader class implements the
IlvDataReader interface and can be used with the general-purpose
IlvInputDataSource class.
The following code shows how to read the contents of an XML file, and make it available for charting through an
IlvXMLDataSource:
// Create the data source.
IlvXMLDataSource ds = new IlvXMLDataSource();
// Create the XML reader.
IlvXMLDataReader reader = new IlvXMLDataReader();
// Optional: Specify that the parser should validate the contents of the file
reader.setValidating(true);
// Load the data.
ds.load(new org.xml.sax.InputSource("data.xml"), reader);
Writing data to an XML document
The
IlvXMLDataWriter class allows you to write data sets into an XML document, as shown in the following code:
import javax.xml.parsers.*;
import org.w3c.dom.Document;
...
IlvDataSet[] dataSets = ...;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.newDocument();
IlvXMLDataWriter writer = new IlvXMLDataWriter();
writer.write(document, dataSets);
You can also directly serialize the data sets into an output stream, as shown in the next example:
IlvDataSet[] dataSets = ...;
IlvXMLDataWriter writer = new IlvXMLDataWriter();
writer.write(new FileOutputStream("chartmodel.xml"), dataSets);
Example: serializing data
Description of the format
The expected format is an application of the W3C XML language. You can find the full Document Type Definition of this format in
Document Type Definition for XML data file in
Using the Designer. For more information see
XML file format.
The data is described with the following elements:
The chartData element, which belongs to the ilvchart namespace:
<!ELEMENT chartData (data+)>
<!ATTLIST chartData xmlns:ilvchart CDATA #FIXED
"http://www.ilog.com/products/jviews/chart"
version CDATA #REQUIRED>
This root element contains a set of child data elements:
<!ELEMENT data (labels?,series+)>
<!ATTLIST data xSeries IDREF #IMPLIED>
Each data element can be seen as a table where rows are represented by one or more series elements. One of these series can be identified as the one holding the x-values. In this case, the other series are assumed to hold the y-values of the considered data.
Series data points might be associated with labels by means of the labels element. Labels can be either defined common to all the series of a data element, or individually for each series. In this case, the labels are specified at the series element level, and override labels that may have been set on the data element.
The series element has the following description:
<!ELEMENT series ((valueOperator | (value | valuesList)*),labels?,property*)>
<!ATTLIST series dateFormat CDATA #IMPLIED
type (double | date) #REQUIRED
id ID #REQUIRED>
Each series is identified by a unique ID and the type of data it contains (either double values or dates). The dateFormat attribute can be any pattern that conforms to the syntax used by the java.text.SimpleDateFromat class. Values can be expressed with elementary value elements, or as a list with the valuesList element:
<!ELEMENT value (#PCDATA)>
<!ATTLIST valuesList delimiter CDATA #IMPLIED>
The delimiter attribute specifies the separating character in the values list. The default character is a comma. Here is an example of a series element:
<series id="Series_1" type="double">
<value>0.5</value>
<valuesList>2.0,8.0,6.0,13.0,22.0,21.0,19.0,28.0,27.0
</valuesList>
<value>32.5</value>
</series>
You can also express the values of a series as an operation on the values of other series. This is performed by means of the valueOperator element:
<!ELEMENT valueOperator (seriesRef|property)*>
<!ATTLIST valueOperator class NMTOKEN #REQUIRED>
For example, the following series is defined as the moving average of the "Series_1" series:
<series id="Series_1_Mov._Avg." type="double">
<valueOperator class="ilog.views.chart.data.IlvMovingAvgDataSet">
<seriesRef ref="Series_1"/>
<property name="period">5</property>
</valueOperator>
</series>
The class attribute refers to the class name of the data set that implements the operation. The seriesRef element refers to a valid series identifier within the same data element.
A property element is defined as follows:
<!ENTITY % propertyExt "">
<!ELEMENT property (#PCDATA %propertyExt;)*>
<!ATTLIST property name CDATA #REQUIRED
javaClass CDATA #IMPLIED>
By default, a property element consists of text data. A property is defined by its name (the name attribute) and optionally by the Java class name of the Java object it refers (the javaClass attribute). The use of the javaClass attribute is explained in the next section.
The entity propertyExt can be defined in the internal DTD subset to add custom subelement, or custom attributes to the property element within a given document.
For example, the following lines extend the property element with additional child elements myelement:
<!DOCTYPE chartData SYSTEM 'chartxml.dtd'
[
<!ENTITY % propertyExt "|myproperty">
<!ELEMENT myproperty (myelement)*>
<!ELEMENT myelement .... myelement definition goes there ".>
]>
The properties can be used with
valueOperator and
series elements. A default mechanism allows you to specify simple properties for
valueOperator elements. This mechanism uses reflection to determine which method should be called on the data set instance, as well as the expected parameter type. The method is found according to the JavaBean naming convention. For example, in the definition of your moving average operator, the
setPeriod method is called:
<valueOperator class="ilog.views.chart.data.IlvMovingAvgDataSet">
<seriesRef ref="Series_1"/>
<property name="period">5</property>
</valueOperator>
Extending the XML Reader
In this section you will see how to extend the reader to deal with series properties, as well as with complex or extended properties. The
IlvXMLDataReader class allows you to register readers that will be used to interpret custom properties within the XML file.
A property reader must implement the
IlvXMLPropertyReader interface, which defines the following methods:
readProperty, used to read the property from the specified DOM element.
setProperty, used to associate the property with the corresponding data set.
By default, a predefined reader is used to decode the property value. This predefined reader decodes the property value according to the following rules:
if the
javaClass attribute is set, then the XML property value is converted into the corresponding Java class using a
java.beans.PropertyEditor.
if the
javaClass attribute is missing, or if the above conversation has failed, then the Java property value is the string representation of the XML property value.
You can override this default mechanism by registering your own property reader. A reader is registered by means of the IlvXMLDataReader.registerPropertyReader (for readers to be shared between all instances) and IlvXMLDataReader.setPropertyReader (for readers specific to an instance) methods.
For example:
to register a specific property, use the following code:
and
aReader.setPropertyReader(aPropertyName, aReader);
to register a default reader that is used to interpret properties with no associated reader, use the following code:
aReader.registerPropertyReader(null, aReader);
When a property is read, the
IlvXMLDataReader searches for the corresponding property reader in the following order:
in the reader repository of the reader instance, then
in the reader repository of the
IlvXMLDataReader class.
If no reader has been registered for a property, then the IlvXMLDataReader searches for a default property reader in the following order:
the default property reader of the reader instance, then
the default property reader of the
IlvXMLDataReader class.
If no property reader has been found, then the predefined reader is used as a fallback.
The following are examples of properties element read by the predefined readers:
<property name="product">JViews Charts</property>
property name="color" javaClass="java.awt.Color">red</property>
<property name="dataLabels">
Main classes,renderer,data,interactor,swing,servlet,java2d,util,graphic,other
</property>
They are respectively interpreted as the “JViews Charts” string, the java.awt.Color.red, and the last one is as the data labels of the data set.
The following example shows how to use this mechanism. The complete source code can be found in
<installdir>/jviews-charts/codefragments/chart/xml-extension/src/XMLExtension.java.
You want to associate a URL for each point of a data set. These URLs will be specified in the XML file as a property of the series. To support this new custom property, you first have to extend the JViews Charts DTD:
<!DOCTYPE chartData PUBLIC '-//ILOG//JVIEWS/Chart 1.0' 'chartxml.dtd'
[
<!ENTITY % propertyExt "| hrefs">
<!ELEMENT hrefs (#PCDATA)>
]>
This extension means that the property element now contains a hrefs element that consists of PCDATA.
Then, you add the property to the series:
<chartData version="1.0">
<data>
<series id="Series1" type="double">
<valuesList>353.2,191.6,160.7,54.5,36.6,34.3,31.3,28.1,25.5,45.2
</valuesList>
...
<property name="hrefs">
<hrefs>
../../../../doc/refman/ilog/views/chart/package-summary.html;
../../../../doc/refman/ilog/views/chart/renderer/package-summary.html;
../../../../doc/refman/ilog/views/chart/data/package-summary.html;
../../../../doc/refman/ilog/views/chart/interactor/package-summary.html;
../../../../doc/refman/ilog/views/chart/swing/package-summary.html;
../../../../doc/refman/ilog/views/chart/servlet/package-summary.html;
../../../../doc/refman/ilog/views/chart/java2d/package-summary.html;
../../../../doc/refman/ilog/views/chart/util/package-summary.html;
../../../../doc/refman/ilog/views/chart/graphic/package-summary.html;
../../../../doc/refman/ilog/views/chart/package-summary.html
</hrefs>
</property>
</series>
</data>
</chartData>
The next step is to implement an IlvXMLPropertyReader to read your custom property: class HREFPropertyReader implements IlvXMLPropertyReader.
{
/** The <code>hrefs</code> property element tag. */
public static final String HREFS_TAG = "hrefs";
/**
* Reads the specified property element.
* This method reads an <code>hrefs</code>
* element associated with a series and stores its contents in a
* <code>List</code>.
*/
public Object readProperty(org.w3c.dom.Element propertyElt)
{
Node child = propertyElt.getFirstChild();
while (child != null) {
if (child.getNodeType() == Node.ELEMENT_NODE &&
child.getNodeName().equals(HREFS_TAG)) {
Element hrefElt = (Element)child;
StringTokenizer tokenizer =
new StringTokenizer(hrefElt.getFirstChild().getNodeValue(),
";\n\t ");
List hrefs = new LinkedList();
while (tokenizer.hasMoreTokens())
hrefs.add(tokenizer.nextToken());
return hrefs;
}
child = child.getNextSibling();
}
return null;
}
/**
* Sets the property on the specified data set. This method sets the
* <code>href</code>s <code>List</code> as a property
* of the specified data set.
*/
public void setProperty(IlvDataSet dataSet,
String propertyName,
Object value)
{
dataSet.putProperty(HREFPropertyReader.HREFS_TAG, value, false);
}
}
Finally, you register this property reader on your IlvXMLDataReader:
// Register our own XMLPropertyReader
reader.setPropertyReader(HREFPropertyReader.HREFS_TAG,
new HREFPropertyReader());
The XML reader can also be extended to create instances of custom data sets. This is performed by overriding the
createDataSet method. By default, this method returns an instance of the
IlvDefaultDataSet class.
Database access through JDBC
JDBC technology offers a platform and server independent way to retrieve data stored in a database. The requests are expressed through the JDBC API, and are usually performed in three steps:
Establish the connection to the server.
Execute a database statement (SQL query).
Process the result of the request. This result is available through a
java.sql.ResultSet object, which presents a tabular structure.
Database processing is actually performed by a driver, which depends on the type of the database server. You can find more information about JDBC on the JavaSoft site at:
http://java.sun.com/products/jdbc. This site also contains information about driver availability for the most popular database vendors.
The JViews Charts library supports the use of the JDBC interface to retrieve data values from database servers. This support is provided by the
IlvJDBCDataSource class, which extracts data sets from the result of a database query.
You can specify the information related to the database request as follows:
Provide directly the result of the query in the form of a JDBC
ResultSet, either in the constructor of the data source, or with the
setResultSet method.
Provide the connection parameters as well as the SQL query statement. This can be done either in the constructor of the data source, or with the corresponding
getter and
setter methods. If you use this methodology, you must call the
executeQuery method to produce the resulting
ResultSet.
You can control how data sets are extracted from the ResultSet by means of two parameters:
The index of the column that holds the
x-series.
The index of the column that holds the data labels.
If this index is set to -1, no data label is defined.
By default, the
IlvJDBCDataSource class creates data sets that store the result of the query into memory without any binding to the database. In other words, this means that the data accessible from these data sets is not bound to the data stored in the database. For example, modifying the value of a data point with the
IlvDataSet.setData method does not send an update statement to the database.
Since JViews 6.5, in addition to this read-only mode, the IlvJDBCDataSource also support a read-write mode in which any changes on the data model are committed to the data base. This read-write mode must be enabled at construction time by means of the following constructors:
IlvJDBCDataSource(boolean readOnly)
and
IlvJDBCDataSource(String databaseURL,
String user,
String passwd,
String driverName,
String query,
int xColumnIndex,
int dataLabelsColumnIndex,
boolean readOnly)
Example: Importing the content of a CSV (Comma Separated Value) file through the CSV JDBC Driver
/**
* This method initializes and configures the connection and calls <code>executeQuery()</code>.
*/
protected void connect() {
if (jdbcDs == null) {
// The data source is initialized. The connection string
// is set to "jdbc:relique:csv:data", where 'data' is the directory
// which contains csv files. The user and password are left blank,
// the driver to use is the CSV-JDBC driver ("org.relique.jdbc.csv.CsvDriver"),
// the query is to be initialized later, and there are no x series
// or data labels to read (-1 = no x series column).
jdbcDs = new IlvJDBCDataSource("jdbc:relique:csv:data", "", "", "org.relique.jdbc.csv.CsvDriver", null, -1, 3);
// We specified the separator used in the csv files (the default separator for the driver is ','
Properties props = new Properties();
props.put("separator", ";");
jdbcDs.addProperties(props);
}
executeQuery();
}
/**
* Executes the queries.
*/
protected void executeQuery() {
if (jdbcDs != null) {
// First load the csvdemo1 data file.
String query = "select * from csvdemo1";
// Set the query.
jdbcDs.setQuery(query);
// Execute the query and initialize the
// data source data sets.
try {
jdbcDs.endConnection();
jdbcDs.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
System.err.println("A database access error occurs");
return;
}
// Initialize the data sets of the area renderer (for the radar chart).
renderer.getDataSource().setDataSets(jdbcDs.getDataSets());
renderer.setStyles(palettes);
renderer.getChart().getXScale().setCategory(jdbcDs.getDataSet(0), false);
// Load the csvdemo2 data file.
query = "select * from csvdemo2";
// Set the query.
jdbcDs.setQuery(query);
// Execute the query and initialize the
// data source data sets.
try {
jdbcDs.endConnection();
jdbcDs.executeQuery();
} catch (SQLException e) {
System.err.println("A database access error occurs");
return;
}
// The first column (that is, the first data set) is rendered through
// stockRenderer.
stockRenderer.getDataSource().setDataSets(new IlvDataSet[] { jdbcDs.getDataSet(0) });
// The second and third columns (data sets of index 1 and 2) are
// rendered through ioRenderer.
ioRenderer.getDataSource().setDataSets(new IlvDataSet[] { jdbcDs.getDataSet(1), jdbcDs.getDataSet(2) });
stockRenderer.getChart().getXScale().setCategory(jdbcDs.getDataSet(0), true);
}
}
Connecting to a Swing TableModel
The Swing
TableModel interface defines a tabular data model that can be represented with a
javax.swing.JTable in the GUI of your application. The
IlvSwingTableDataSource class allows you to create a data source from an existing
TableModel.
1. The
IlvSwingTableDataSource acts as an adapter between both data models, which means that the original data accessible from the table model is not copied.
2. Both data models are bound, which means that modifications done through a data set are forwarded to the table model. Likewise, modifying the table model fires a change event for the corresponding data set.
There are several ways to indicate how data sets should be extracted from the table model:
By specifying the series type (
ROW_SERIES,
COLUMN_SERIES ), which indicates whether data sets are extracted in rows or columns.
By specifying optional rows or columns that hold the
x-series and the data point labels.
By providing
data converters to map objects stored in the table into double values. This feature is only used when series are extracted by column as it is based on the information provided by the
TableModel.getColumnClass method. To register a data converter for a given Object class, use the
setDefaultConverter static method. By default, converters exist for
Date and
Double.
Example: Connecting to a TableModel
// Create the chart.
IlvChart chart = createChart();
// Create the swing TableModel containing the data.
AbstractTableModel swingModel = null;
try {
swingModel = createSwingTableModel();
} catch (ParseException e) {
swingModel = new DefaultTableModel();
}
// Bind an IlvSwingTableDataSource to this swing table model. The series
// being arranged by column, the data source is of type COLUMN_SERIES.
// Since a specific column is used for the abscissa (the Year column) for
// all the series, the index in the table model of the year column
// is also specified (0).
IlvSwingTableDataSource tableDs =
new IlvSwingTableDataSource(swingModel,
IlvSwingTableDataSource.COLUMN_SERIES,
0,
// the column index for the x-values
-1);
// no datalabels
// At this time, the data sets corresponding to the table model series
// have been created.
// Connect the data source to a polyline chart renderer.
// The IlvPolylineChartRenderer will create a renderer for each data set
// of its data source and hold them in an internal list. These sub-
// renderers are called child renderers and can be parsed using an
// Iterator (see below).
IlvPolylineChartRenderer r = new IlvPolylineChartRenderer();
r.setDataSource(tableDs);
chart.addRenderer(r);
Converting Data
To be properly merged into a chart data model, data imported from a database or a table model needs to be mapped into double values. This conversion is handled by means of data converters, instances of the
IlvDataConverter interface.
A data converter handles the conversion between a particular Object class and its double representation, by means of the following methods:
public Object toObject(double value)
public double toValue(Object object)
For example, a data converter implementation that handles conversions between a String object and a double representation would be:
public Object toObject(double value)
{
return Double.toString(value);
}
public double toValue(Object object)
{
if (!(object instanceof String))
throw new IllegalArgumentException("IlvStringConverter: object not a java.lang.String instance.");
try {
return Double.parseDouble((String)object);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("IlvStringConverter: Cannot parse object.");
}
}
The
IlvJDBCDataSource and
IlvSwingTableDataSource classes handle a set of data converters common to all instances of these classes. These common converters are called default converters, and are registered using the
setDefaultConverter and
setDefaultConverter static methods.
By default, the IlvJDBCDataSource and IlvSwingTableDataSource classes register converters for Date, String, Short, Integer, Long, Float and Double objects.
NOTE The IlvJDBCDataSource also registers default converters for Time and Timestamp SQL data types.
The
data converters are retrieved using the
getDataConverter and
getDataConverter methods. The default implementation of these methods returns the default converter for the object type of the specified column. If none exists, it returns the first default converter able to convert it:
For the
IlvSwingTableDataSource, it returns the default converter associated with the column class (see
TableModel.getColumnClass ).
For the
IlvJDBCDataSource, it returns the default converter associated with the Java-equivalent type of the database column type as defined by the JDBC specification.
You can override this method to change the default implementation, for example if you need to define a per-instance registering mechanism.
The JViews Charts package provides three default implementations of the IlvDataConverter interface:
Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.