The program will receive data every second and draw them on time Series chart. However, once I create two series, I cannot add new value to it. It displays a straight line only.
How do I append data to a specified series? I.e. YYY. Based on this example, here's what I'm doing:
...
// Data set.
final DynamicTimeSeriesCollection dataset =
new DynamicTimeSeriesCollection( 2, COUNT, new Second() );
dataset.setTimeBase( new Second( 0, 0, 0, 1, 1, 2011 ) );
dataset.addSeries( gaussianData(), 0, "XXX" );
dataset.addSeries( gaussianData(), 1, "YYY" );
// Chart.
JFreeChart chart = createChart( dataset );
this.add( new ChartPanel( chart ), BorderLayout.CENTER );
// Timer.
timer = new Timer( 1000, new ActionListener() {
#Override
public void actionPerformed ( ActionEvent e ) {
dataset.advanceTime();
dataset.appendData( new float[] { randomValue() } );
}
} );
...
private JFreeChart createChart ( final XYDataset dataset ) {
final JFreeChart result = ChartFactory.createTimeSeriesChart(
TITLE, "", "", dataset, true, true, false );
final XYPlot plot = result.getXYPlot();
ValueAxis domain = plot.getDomainAxis();
domain.setAutoRange( true );
ValueAxis range = plot.getRangeAxis();
range.setRange( -MINMAX, MINMAX );
return result;
}
Assuming you started from here, you've specified a dataset with two series, but you're only appending one value with each tick of the Timer. You need two values for each tick. Here's how I modified the original to get the picture below:
final DynamicTimeSeriesCollection dataset =
new DynamicTimeSeriesCollection(2, COUNT, new Second());
...
dataset.addSeries(gaussianData(), 0, "Human");
dataset.addSeries(gaussianData(), 1, "Alien");
...
timer = new Timer(FAST, new ActionListener() {
// two values appended with each tick
float[] newData = new float[2];
#Override
public void actionPerformed(ActionEvent e) {
newData[0] = randomValue();
newData[1] = randomValue();
dataset.advanceTime();
dataset.appendData(newData);
}
});
Related
I have a chart where I display the values of a table (stock and date). The stock is displayed in the y axis and the dates in the x axis.
As long as the query returns 2 entries, it is shown normally as a line, but if the query returns only one entry, nothing is shown (there should be a point there).
Any suggestions on how to fix this would be highly appreciated.
2 entries: enter image description here
1 entry: enter image description here
Code (the chart is built in an action listener):
historyButton.addActionListener(e -> {
// stock list and dates list retrieved from database
int articleNr = Integer.parseInt(articleIDText.getText());
List<Integer> displayStockHistory;
List<String> displayDatesStockHistory;
try {
displayStockHistory = business.displayStockHistory(articleNr);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
try {
displayDatesStockHistory = business.displayDatesStockHistory(articleNr);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
// add db values to the dataset
for(int i = 0; i < displayStockHistory.size(); i++){
dataset.addValue(displayStockHistory.get(i), "Articles in Stock", displayDatesStockHistory.get(i));
}
// compose chart
JFreeChart chart = ChartFactory.createLineChart(
"Stock History",
"Date",
"Stock",
dataset,
PlotOrientation.VERTICAL,
true,
true,
false);
chart.setBackgroundPaint(c2);
chart.getTitle().setPaint(c3);
CategoryPlot p = chart.getCategoryPlot();
p.setForegroundAlpha(0.9f);
CategoryItemRenderer renderer = p.getRenderer();
//renderer.setSeriesPaint(0, c4);
renderer.setSeriesStroke( 0, new BasicStroke( 5 ) );
chart.getCategoryPlot().setBackgroundPaint(c1);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setBackground(c2);
chartScrollPane.getViewport().add(chartPanel);
chartPanel.setPreferredSize(new Dimension(2000, 270));
ChartFrame frame1 = new ChartFrame("Line graph", chart);
frame1.setVisible(true);
frame1.setSize(500, 400);
});
}
Your chosen chart factory instantiates a LineAndShapeRenderer, so one approach is to make the renderer's shapes visible for all series, as shown here; note that the API has changed:
CategoryPlot plot = (CategoryPlot) chart.getPlot();
LineAndShapeRenderer r = (LineAndShapeRenderer) plot.getRenderer();
r.setDefaultShapesVisible(true);
To enable shapes only for series having a single, non-null value, you'll have to iterate through the data explicitly:
DefaultCategoryDataset data = new DefaultCategoryDataset();
data.addValue(3, "Data1", LocalDate.now());
data.addValue(2, "Data2", LocalDate.now());
data.addValue(1, "Data2", LocalDate.now().plusDays(1));
…
for (int row = 0; row < data.getRowCount(); row++) {
int count = 0;
for (int col = 0; col < data.getColumnCount(); col++) {
count += data.getValue(row, col) != null ? 1 : 0;
}
if (count == 1) {
r.setSeriesShapesVisible(row, true);
}
}
In the chart factory and I use there SlidingGanttCategoryDataset. But the scrolling does not appear. What am I missing?
public JFreeChartGanttChart(String applicationTitle, String chartTitle) {
super(applicationTitle);
// based on the dataset we create the chart
Map<Integer, Map<Integer, String>> labels = new LinkedHashMap<>();
JFreeChart chart = ChartFactory.createGanttChart(chartTitle,
"Vessels",
"Time",
createDataset(labels),
true,
true,
true);
// Adding chart into a chart pane
CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.getDomainAxis().setUpperMargin(0.001);
plot.getRangeAxis().setLowerMargin(0.01);
plot.getRangeAxis().setUpperMargin(0.01);
plot.getDomainAxis().setLowerMargin(0.001);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(1000, 1500));
setContentPane(chartPanel);
CategoryItemRenderer renderer = plot.getRenderer();
renderer.setDefaultItemLabelGenerator(new IntervalCategoryItemLabelGenerator(){
#Override
public String generateRowLabel(CategoryDataset dataset, int row) {
return "Text ... " + row ; // not needed here
}
#Override
public String generateColumnLabel(CategoryDataset dataset, int column) {
return " Text ... " + column; // not needed here
}
#Override
public String generateLabel(CategoryDataset dataset, int row, int column) {
return labels.get(row).get(column) ; // row+ " " + column
}
});
renderer.setDefaultItemLabelsVisible(true);
renderer.setDefaultItemLabelPaint(Color.BLACK);
renderer.setDefaultItemLabelFont(new Font("arial", Font.PLAIN, 6), false);
// setDefaultPositiveItemLabelPosition - text will be inside label
renderer.setDefaultNegativeItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.INSIDE6,
TextAnchor.BOTTOM_LEFT));
}
}
While it is technically possible to add a ChartPanel to a JScrollPane, rendering and scrolling hundreds or thousands of tasks scales poorly; the typical appearance is shown here. Instead, use a SlidingGanttCategoryDataset, which "presents a subset of the categories in an underlying dataset." Given an arbitrary number, N, of tasks to to be displayed MAX at a time, construct the corresponding dataset:
private static final int N = 1000;
private static final int MAX = 12;
…
private final SlidingGanttCategoryDataset dataset = new
SlidingGanttCategoryDataset(taskSeriesCollection, 0, MAX);
Then add a suitable control adjacent to the ChartPanel and listen for changes; update the dataset's first displayed index accordingly:
JSlider slider = new JSlider(JSlider.VERTICAL, 0, N - MAX, 0);
slider.addChangeListener((ChangeEvent e) -> {
dataset.setFirstCategoryIndex(slider.getValue());
});
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries validKoordinates = new XYSeries("Not dangerous");
for (SimulationResult sr : validSR.values()) {
validKoordinates.add(sr.getMinTTC(), sr.getMinTHW()); //x,y
}
dataset.addSeries(validKoordinates);
JFreeChart chart = chart = ChartFactory.createScatterPlot(
"Distribution of THW and TTC Values",
"TTC", "THW", dataset);
//Changes background color
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(255, 228, 196));
plot.getRendererForDataset(plot.getDataset(0)).setSeriesPaint(0, Color.GRAY);
XYSeriesCollection dataset2 = new XYSeriesCollection();
XYSeries warningKoordinates = new XYSeries("Very critical");
for (SimulationResult sr : criticalSR.values()) {
warningKoordinates.add(sr.getMinTTC(), sr.getMinTHW()); //x,y
}
dataset2.addSeries(warningKoordinates);
plot.setDataset(1, dataset2);
plot.getRendererForDataset(plot.getDataset(1)).setSeriesPaint(0, Color.RED);
So I have two different datasets (dataset 1 and dataset 2). Each dataset contains different values. My aim is to change the color of the dataset 1 to gray and the color of the second one to red. (BUT the shape should same the SAME). At the beginning I only had one dataset with 2 XYSeries. The problem at that time was that the shape was different for each XYSeries. Now I have the opposite problem. The shape stays but the color does not change.
This is what my table looks right now:
As you can see right now I cant seperate which one is very critical and whitch not.
It is found that only one dataSet is required, all series should be added to the dataSet. And using the first parameter of setSeriesPaint to configure color of the series. Since the version of jfreeChart is not provide, I used 1.0.12. The code is edited for testing.
public static void main(String[] args) throws IOException {
XYSeriesCollection dataset = new XYSeriesCollection();
int[][] sr = new int[3][2];
for (int i = 0; i < sr.length; i++) {
sr[i][0] = i + 3;
sr[i][1] = 2 * (i + 1) + 1;
}
XYSeries validKoordinates = new XYSeries("Not dangerous");
XYSeries warningKoordinates = new XYSeries("Very critical");
System.out.println(sr.length);
for (int i = 0; i < sr.length; i++) {
validKoordinates.add(sr[i][0], sr[i][1]);
}
for (int i = 0; i < sr.length; i++) {
warningKoordinates.add(sr[i][0]+1, sr[i][1]+1);
}
// Add dataset for all series
dataset.addSeries(validKoordinates);
dataset.addSeries(warningKoordinates);
// Only reference one dataset
JFreeChart chart = ChartFactory.createScatterPlot("Distribution of THW and TTC Values", "TTC", "THW", dataset,
PlotOrientation.HORIZONTAL, true, true, true);
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(255, 228, 196));
// Change the index of setSeriesPaint to set color
plot.getRendererForDataset(dataset).setSeriesPaint(0, Color.GRAY);
plot.getRendererForDataset(dataset).setSeriesPaint(1, Color.RED);
BufferedImage objBufferedImage = chart.createBufferedImage(600, 800);
ByteArrayOutputStream bas = new ByteArrayOutputStream();
try {
ImageIO.write(objBufferedImage, "png", bas);
} catch (IOException e) {
e.printStackTrace();
}
byte[] byteArray = bas.toByteArray();
InputStream in = new ByteArrayInputStream(byteArray);
BufferedImage image = ImageIO.read(in);
File outputfile = new File("testimage.png");
ImageIO.write(image, "png", outputfile);
}
The image generated by the above method
Well basically what my program does is that I have a csv file that reads in the
milliseconds (which I converted) and a letter that represents a zone. I am trying to display it as a bar chart but I have different tabs that each letter (zone) goes to. My
issue is trying to send the letter (from file) to the specific zone which I made in tabs. Maybe I am missing something but I am not sure. Any help will be much appreciated.
Here is my code:
#SuppressWarnings({ "serial", "deprecation" })
public class InductionTreeGraph extends JFrame {
static TimeSeries ts = new TimeSeries("data", Millisecond.class);
public static void add(JTabbedPane jtp, String label, int mnemonic, AbstractButton button1)
{
int count = jtp.getTabCount();
JButton button = new JButton(label);
button.setBackground(Color.WHITE);
jtp.addTab(label, null, button, null);
jtp.setMnemonicAt(count, mnemonic);
}
public InductionTreeGraph() throws Exception {
final XYDataset dataset = (XYDataset) createDataset();
final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(1000, 400));
setContentPane(chartPanel);
JFrame frame = new JFrame("Induction Zone Chart");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTabbedPane jtp = new JTabbedPane();
jtp.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
String zones[] = {"Zone A", "Zone B", "Zone C", "Zone S",
"Zone SH","Zone W"};
int mnemonic[] = {KeyEvent.VK_A, KeyEvent.VK_B, KeyEvent.VK_C,
KeyEvent.VK_S, KeyEvent.VK_H,KeyEvent.VK_W};
for (int i = 0, n=zones.length; i<n; i++)
{
AbstractButton button1 = null;
InductionTreeGraph.add(jtp, zones[i], mnemonic[i], button1);
}
final JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT));
p.add(new JButton(new AbstractAction("Update") {
public void actionPerformed(ActionEvent e) {
chartPanel.repaint();
}
}));
frame.add(jtp, BorderLayout.NORTH);
frame.add(p, BorderLayout.SOUTH);
frame.getContentPane().add(chartPanel);
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
#SuppressWarnings("deprecation")
private XYDataset createDataset() {
final TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(ts);
TreeMap<String,TreeMap<Integer,Integer[]>> zoneMap = getInductions("","");
// Iterate through all zones and print induction rates for every minute into
// every hour by zone...
Iterator<String> zoneIT = zoneMap.keySet().iterator();
while (zoneIT.hasNext())
{
String zone = zoneIT.next();
TreeMap<Integer,Integer[]> hourCountsInZoneMap = zoneMap.get(zone);
System.out.println("ZONE " + zone + " : ");
Iterator<Integer> hrIT = hourCountsInZoneMap.keySet().iterator();
while (hrIT.hasNext())
{
int hour = hrIT.next();
Integer [] indRatePerMinArray = hourCountsInZoneMap.get(hour);
for (int i=0; i< indRatePerMinArray.length; i++)
{
System.out.print(hour + ":");
System.out.print(i < 10 ? "0" + i : i);
System.out.println(" = " + indRatePerMinArray[i] + " induction(s)");
}
}
}
return dataset;
}
#SuppressWarnings("deprecation")
private JFreeChart createChart(XYDataset dataset) {
final JFreeChart chart = ChartFactory.createXYBarChart(
"Induction Zone Chart",
"Hour",
true,
"Inductions Per Minute",
(IntervalXYDataset) dataset,
PlotOrientation.VERTICAL,
false,
true,
false
);
XYPlot plot = (XYPlot)chart.getPlot();
XYBarRenderer renderer = (XYBarRenderer)plot.getRenderer();
renderer.setBarPainter(new StandardXYBarPainter());
renderer.setDrawBarOutline(false);
ValueAxis axis = plot.getDomainAxis();
axis.setAutoRange(true);
axis.setFixedAutoRange(60000.0);
// Set an Induction target of 30 per minute
Marker target = new ValueMarker(30);
target.setPaint(java.awt.Color.blue);
target.setLabel("Induction Rate Target");
plot.addRangeMarker(target);
return chart;
}
private TreeMap<String, TreeMap<Integer, Integer[]>> getInductions(String mills, String zone) {
// TreeMap of Inductions for Every Minute in Day Per Zone...
// Key = Zone
// Value = TreeMap of Inductions per Minute per Hour:
// Key = Hour
// Value = Array of 60 representing Induction Rate Per Minute
// (each element is the induction rate for that minute)
TreeMap<String, TreeMap<Integer, Integer[]>> zoneMap = new TreeMap<String, TreeMap<Integer, Integer[]>>();
// Input file name...
String fileName = "/home/a002384/ECLIPSE/IN070914.CSV";
try
{
BufferedReader br = new BufferedReader(new FileReader(fileName));
String line;
try
{
// Read a line from the csv file until it reaches to the end of the file...
while ((line = br.readLine()) != null)
{
// Parse a line of text in the CSV...
String [] indData = line.split("\\,");
long millisecond = Long.parseLong(indData[0]);
String zone1 = indData[1];
// The millisecond value is the number of milliseconds since midnight.
// From this, we can derive the hour and minute of the day as follows:
int secOfDay = (int)(millisecond / 1000);
int hrOfDay = secOfDay / 3600;
int minInHr = secOfDay % 3600 / 60;
// Obtain the induction rate TreeMap for the current zone.
// If this is a "newly-encountered" zone, create a new TreeMap.
TreeMap<Integer, Integer[]> hourCountsInZoneMap;
if (zoneMap.containsKey(zone1))
hourCountsInZoneMap = zoneMap.get(zone1);
else
hourCountsInZoneMap = new TreeMap<Integer, Integer[]>();
// Obtain the induction rate array for the current hour in the current zone.
// If this is a new hour in the current zone, create a new array,
// and initialize this array with all zeroes.
// The array is size 60, because there are 60 minutes in the hour.
// Each element in the array represents the induction rate for that minute.
Integer [] indRatePerMinArray;
if (hourCountsInZoneMap.containsKey(hrOfDay))
indRatePerMinArray = hourCountsInZoneMap.get(hrOfDay);
else
{
indRatePerMinArray = new Integer[60];
Arrays.fill(indRatePerMinArray, 0);
}
// Increment the induction rate for the current minute by one.
// Each line in the csv file represents a single induction at a
// single point in time.
indRatePerMinArray[minInHr]++;
// Add everything back into the TreeMaps if these are newly-created.
if (!hourCountsInZoneMap.containsKey(hrOfDay))
hourCountsInZoneMap.put(hrOfDay, indRatePerMinArray);
if (!zoneMap.containsKey(zone1))
zoneMap.put(zone1, hourCountsInZoneMap);
}
}
finally
{
br.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
return zoneMap;
}
#SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
try {
InductionTreeGraph dem = new InductionTreeGraph();
dem.pack();
dem.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while(true) {
double millisecond = 2;
double num = millisecond;
System.out.println(num);
ts.addOrUpdate(new Millisecond(), num);
try {
Thread.sleep(20);
} catch (InterruptedException ex) {
System.out.println(ex);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
My very first suggestion is about this line:
setContentPane(chartPanel);
Don't mess with content pane. Use this line instead:
getContentPane().add(chartPanel);
The prooblem I see in your code is that InductionTreeGraph extends from JFrame and you are setting this chartPanel as this frame's content pane, but then you use a new JFrame local variable (called frame) and add this chartPanel to this frame as well:
JFrame frame = new JFrame("Induction Zone Chart");
...
frame.getContentPane().add(chartPanel);
Swing components are intended to be used "as is" so it's preferable composition over inheritance. Having said this you should consider remove extends JFrame on your class declaration and add all your components (chart panel, buttons, etc) to this local frame instead.
Related
You may want to take a look to the example shown in this Q&A. This or any #trashgod's examples in Stack Overflow about JFreeChart (f.e. this one) might help you to better structure your code.
I am using JFreeChart to populate a graph from a csv file, i have managed to create multiple datasets from the file and graphed the data.
The SVG images are being re-written to the "file.svg", so nothing looks pretty at all. Question is, how can i create a single SVG image from the multiple datasets and If only i knew how to get each chart, plot it orderly and draw all of them to a SVG file.
package freechart;
import java.util.*;
import java.text.*;
import java.io.*;
import java.awt.*;
import java.util.StringTokenizer;
import javax.swing.*;
import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.data.time.*;
import org.jfree.ui.*;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
public class StockHistoryChart extends JPanel
{
private static final long serialVersionUID = 1L;
// Holds the data
public TimeSeriesCollection dataset = new TimeSeriesCollection();
public TimeSeriesCollection datasetPhysical = new TimeSeriesCollection();
public TimeSeriesCollection datasetS = new TimeSeriesCollection();
public TimeSeriesCollection datasetMM = new TimeSeriesCollection();
public TimeSeriesCollection datasetIF = new TimeSeriesCollection();
public TimeSeriesCollection datasetWP = new TimeSeriesCollection();
// Create a chart
#SuppressWarnings("unused")
private JFreeChart chart;
// Create a panels that can show our chart
#SuppressWarnings("unused")
private ChartPanel panel;
private String stockSymbol;
private String CurrentMonth;
#SuppressWarnings({ "deprecation", "resource", "unused" })
public StockHistoryChart( String filename )
{
try
{
// Get Stock Symbol
this.stockSymbol = filename.substring( 0, filename.indexOf( '.' ) );
// Create time series
TimeSeries PVC = new TimeSeries( "Physical Count", Day.class );
//TimeSeries PV = new TimeSeries( "Physical", Day.class );
TimeSeries STKC = new TimeSeries( "S Count", Day.class );
//TimeSeries STKTP = new TimeSeries( "S", Day.class );
TimeSeries MMTPC = new TimeSeries( "MM Count", Day.class );
//TimeSeries MMTP = new TimeSeries( "MM", Day.class );
TimeSeries IFSC = new TimeSeries( "IF Count", Day.class );
//TimeSeries IFSTP = new TimeSeries( "IF", Day.class );
TimeSeries WPC = new TimeSeries( "WP Count", Day.class );
//TimeSeries WPTP = new TimeSeries( "WP", Day.class );
BufferedReader br = new BufferedReader( new FileReader( filename ) );
String key = br.readLine();
String line = br.readLine();
while( line != null &&
!line.startsWith( "<!--" ) )
{
StringTokenizer st = new StringTokenizer( line, ",", false );
Day day = getDay( st.nextToken() );
double PVCValue = Double.parseDouble( st.nextToken() );
double PVValue = Double.parseDouble( st.nextToken() );
double STKCValue = Double.parseDouble( st.nextToken() );
double STKTPValue = Double.parseDouble( st.nextToken() );
double MMTPCValue = Double.parseDouble( st.nextToken() );
double MMTPValue = Double.parseDouble( st.nextToken() );
double IFSCValue = Double.parseDouble( st.nextToken() );
double IFSTPValue = Double.parseDouble( st.nextToken() );
double WPCValue = Double.parseDouble( st.nextToken() );
double WPTPValue = Double.parseDouble( st.nextToken() );
double TTCValue = Double.parseDouble( st.nextToken() );
double TTAValue = Double.parseDouble( st.nextToken() );
// Add this value to our series'
PVC.addOrUpdate( day, PVCValue );
//PV.addOrUpdate( day, PVValue );
STKC.addOrUpdate( day, STKCValue );
//STKTP.addOrUpdate( day, STKTPValue );
MMTPC.addOrUpdate( day, MMTPCValue );
//MMTP.addOrUpdate( day, MMTPValue );
IFSC.addOrUpdate( day, IFSCValue );
//IFSTP.addOrUpdate( day, IFSTPValue );
WPC.addOrUpdate( day, WPCValue );
//WPTP.addOrUpdate( day, WPTPValue );
TTC.addOrUpdate( day, TTCValue );
//TTA.addOrUpdate( day, TTAValue );
// Read the next day
line = br.readLine();
}
// Build the datasets
dataset.addSeries( PVC );
//dataset.addSeries( PV );
dataset.addSeries( STKC );
//dataset.addSeries( STKTP );
dataset.addSeries(MMTPC);
//dataset.addSeries(MMTP);
dataset.addSeries(IFSC);
//dataset.addSeries(IFSTP);
dataset.addSeries(WPC);
//dataset.addSeries(WPTP);
dataset.addSeries(TTC);
//dataset.addSeries(TTA);
datasetPhysical.addSeries(PVC);
//datasetPhysical.addSeries(PV);
datasetS.addSeries(STKC);
//datasetS.addSeries(STKTP);
datasetMM.addSeries(MMTPC);
//datasetMM.addSeries(MMTP);
datasetIF.addSeries(IFSC);
//datasetIF.addSeries(IFSTP);
datasetWP.addSeries(WPC);
//datasetWP.addSeries(WPTP);
dataset.setDomainIsPointsInTime(true);
//datasetPhysical.setDomainIsPointsInTime(true);
datasetS.setDomainIsPointsInTime(true);
//datasetS.setDomainIsPointsInTime(true);
datasetMM.setDomainIsPointsInTime(true);
//datasetMM.setDomainIsPointsInTime(true);
datasetIF.setDomainIsPointsInTime(true);
//datasetIF.setDomainIsPointsInTime(true);
datasetWP.setDomainIsPointsInTime(true);
//datasetWP.setDomainIsPointsInTime(true);
JFreeChart summary = buildChart( dataset, "Figures Summary Chart", true );
JFreeChart Physical = buildChart( datasetPhysicalVouchers, "Physical Vouchers count", false );
JFreeChart S = buildChart( datasetSTK, "S count", false );
JFreeChart MM = buildChart( datasetMM, "MM count", true );
JFreeChart IF = buildChart( datasetIFS, "IF (count & values)", false );
JFreeChart WP = buildChart( datasetWebPortal, "WP count", true );
// Create this panel
this.setLayout( new GridLayout( 2, 2 ) );
this.add( new ChartPanel( summary ) );
this.add( new ChartPanel( Physical ) );
this.add( new ChartPanel( S ) );
this.add( new ChartPanel( MM ) );
this.add( new ChartPanel( IF ) );
this.add( new ChartPanel( WP ) );
}
catch( Exception e )
{
e.printStackTrace();
} }
private JFreeChart buildChart( TimeSeriesCollection dataset, String title, boolean endPoints )
{
// Create the chart
JFreeChart chart = ChartFactory.createTimeSeriesChart(
title,
"Date", "Totals",
dataset,
true,
true,
false
);
// Setup the appearance of the chart
chart.setBackgroundPaint(Color.white);
XYPlot plot = (XYPlot) chart.getXYPlot();
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
plot.setDomainCrosshairVisible(true);
plot.setRangeCrosshairVisible(true);
// Display data points or just the lines?
if( endPoints )
{
XYItemRenderer renderer = plot.getRenderer();
if (renderer instanceof StandardXYItemRenderer) {
StandardXYItemRenderer rr = (StandardXYItemRenderer) renderer;
rr.setBaseShapesVisible(true);
rr.setBaseShapesFilled(true);
rr.setDrawSeriesLineAsPath(true);
rr.setSeriesPaint(0, Color.blue.brighter());
rr.setSeriesVisible(0, true); // default
rr.setSeriesVisibleInLegend(0, true); // default
}
}
// Tell the chart how we would like dates to read
DateAxis axis = (DateAxis) plot.getDomainAxis();
axis.setDateFormatOverride(new SimpleDateFormat("dd-MMM-yy"));
// creating SVG
File svgFile = new File("file.svg");
Rectangle2D r2d = new Rectangle2D.Double (
100.0,
100.0,
30.0,
200.0
);
// write it to file
try {
exportChartAsSVG(chart, r2d.getBounds(), svgFile);
// TODO: notify the user the file has been saved (e.g. status bar)
System.out.println("Figured saved as " + svgFile.getAbsolutePath());
} catch (IOException e) {
System.err.println("Error saving file:\n" + e.getMessage());
}
return chart;
}
void exportChartAsSVG(JFreeChart chart, Rectangle bounds, File svgFile) throws IOException {
// Get a DOMImplementation and create an XML document
DOMImplementation domImpl =
GenericDOMImplementation.getDOMImplementation();
Document document = domImpl.createDocument(null, "svg", null);
// Create an instance of the SVG Generator
SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
// draw the chart in the SVG generator
chart.draw(svgGenerator, bounds);
// Write svg file
OutputStream outputStream = new FileOutputStream(svgFile);
Writer out = new OutputStreamWriter(outputStream, "UTF-8");
svgGenerator.stream(out, true /* use css */);
outputStream.flush();
outputStream.close();
}
// Main method
public static void main( String[] args )
{
StockHistoryChart shc = new StockHistoryChart("file.csv");
JFrame frame = new JFrame(shc.CurrentMonth());
frame.getContentPane().add( shc, BorderLayout.CENTER );
frame.setSize( 640, 480 );
frame.setVisible( true );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
}
I resolved this problem I was facing (not able to create a SVG file with all charts), by removing the exportChartAsSVG() and calling the SVG Generator from the main function like so;
// Get a DOMImplementation.
DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
// Create an instance of org.w3c.dom.Document.
String svgNS = "http://www.w3.org/2000/svg";
Document document = domImpl.createDocument(svgNS, "svg", null);
// Create an instance of the SVG Generator.
SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
// Ask the shc to render into the SVG Graphics2D implementation.
shc.paint(svgGenerator);
// Create a SVG file to populate our Frame
File svgFile = new File ("svgfile.svg");
FileOutputStream fos = new FileOutputStream(svgFile);
// Finally, stream out SVG to the standard output using
// UTF-8 encoding.
boolean useCSS = true; // we want to use CSS style attributes
Writer out = new OutputStreamWriter(fos, "UTF-8");
svgGenerator.stream(out, useCSS);
out.flush();