Code: Select all
this.upperDataSet.addSeries( this.priceTimeSeries );
this.lowerDataSet.addSeries( this.volumeTimeSeries );
XYToolTipGenerator toolTipGenerator =
StandardXYToolTipGenerator.getTimeSeriesInstance();
// Create the renderer for the upper plot
XYLineAndShapeRenderer upperRenderer = new XYLineAndShapeRenderer();
upperRenderer.setBaseToolTipGenerator( toolTipGenerator );
upperRenderer.setSeriesLinesVisible( 0, true );
upperRenderer.setSeriesShapesVisible( 0, true );
upperRenderer.setSeriesShapesFilled( 0, true );
upperRenderer.setSeriesShape( 0, new Rectangle2D.Double( -1.0, -1.0, 2.0, 2.0 ) );
// Create the upper plot
NumberAxis upperRangeAxis = new NumberAxis( "Price" );
upperRangeAxis.setAutoRange( true );
upperRangeAxis.setAutoRangeIncludesZero( false );
XYPlot upperPlot = new XYPlot( this.upperDataSet, null, upperRangeAxis,
upperRenderer );
upperPlot.setBackgroundPaint( Color.lightGray );
upperPlot.setDomainGridlinePaint( Color.white );
upperPlot.setRangeGridlinePaint( Color.white );
// Create the renderer for the lower plot.
XYBarRenderer lowerRenderer = new XYBarRenderer() {
public Paint getItemPaint( int series, int item ) {
return Color.black;
}
};
lowerRenderer.setSeriesPaint( 0, Color.black );
lowerRenderer.setDrawBarOutline( false );
lowerRenderer.setBaseToolTipGenerator( toolTipGenerator );
// Create the lower plot
this.lowerRangeAxis = new NumberAxis();
this.lowerRangeAxis.setAutoRange( true );
this.lowerRangeAxis.setLabel( "Volume" );
XYPlot lowerPlot = new XYPlot( this.lowerDataSet, null, this.lowerRangeAxis,
lowerRenderer );
lowerPlot.setBackgroundPaint( Color.lightGray );
lowerPlot.setDomainGridlinePaint( Color.white );
lowerPlot.setRangeGridlinePaint( Color.white );
// Create the domain axis that will be used by both plots.
DateAxis domainAxis = new DateAxis( "Date Time" );
domainAxis.setLowerMargin( 0.0 );
domainAxis.setUpperMargin( 0.02 );
domainAxis.setDateFormatOverride( this.dateFormat );
// Create the combined domain plot with the common domain axis, the upper plot
// and the lower plot.
CombinedDomainXYPlot cplot = new CombinedDomainXYPlot( domainAxis );
cplot.add( upperPlot, 3 );
cplot.add( lowerPlot, 1 );
cplot.setGap( 8.0 );
cplot.setDomainGridlinePaint( Color.white );
cplot.setDomainGridlinesVisible( true );
cplot.setDomainPannable( false );
// Create the new chart
this.chart = new JFreeChart( "Contract Name", cplot );
ChartUtilities.applyCurrentTheme( this.chart );
upperRenderer.setSeriesPaint( 0, Color.blue );
lowerRenderer.setBarPainter( new StandardXYBarPainter() );
lowerRenderer.setShadowVisible( false );
// Put the chart in a new ChartPanel, set the panel attributes and return it.
ChartPanel combinedChartPanel = new ChartPanel( this.chart );
combinedChartPanel.setBorder( new EtchedBorder( EtchedBorder.RAISED ) );
combinedChartPanel.setPreferredSize( this.combinedChartPanelDim );
Code: Select all
Millisecond millisecondTime;
try {
this.priceTimeSeries.clear();
for ( int i = 0; i < this.dataNumValues; i++ ) {
GregorianCalendar timestamp = this.dataTimestamps[ i ];
millisecondTime = new Millisecond( timestamp.get( Calendar.MILLISECOND ),
timestamp.get( Calendar.SECOND ),
timestamp.get( Calendar.MINUTE ),
timestamp.get( Calendar.HOUR_OF_DAY ),
timestamp.get( Calendar.DAY_OF_MONTH ),
timestamp.get( Calendar.MONTH ) + 1,
timestamp.get( Calendar.YEAR ) );
this.priceTimeSeries.add( millisecondTime, this.dataPrices[ i ], false );
}
this.priceTimeSeries.fireSeriesChanged();
}
I have been stepping through the code and I've only found one thing so far that explains the behavior and this only explains why the first display is missing. I found the problem in the AbstractXYItemRenderer while executing findRangeBounds. When it executes xAxis = plot.getDomainAxisForDataset(index) it comes back with a domain set to December 31, 1969 at 5:00 for both the minimum and maximum. Where it gets those values is beyond me because all of my Calendar dates are in 2008. After I pan or zoom the domain range comes back appropriate. Indeed, it does so for the lower bar chart on the first display.
I hope someone with a deep understanding of this code understands why the domain and range calculations have problems when the SeriesChangeEvent flag is fired only after loading all of the data into the TimeSeries object. I'm at my wits end. thanx