package com.ibm.nmon.gui.chart.builder;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import com.ibm.nmon.analysis.AnalysisRecord;
import com.ibm.nmon.data.DataSet;
import com.ibm.nmon.data.DataType;
import com.ibm.nmon.data.DataTuple;
import com.ibm.nmon.data.definition.DataDefinition;
import com.ibm.nmon.chart.definition.IntervalChartDefinition;
import com.ibm.nmon.gui.chart.data.DataTupleCategoryDataset;
import com.ibm.nmon.util.TimeFormatCache;
public final class IntervalChartBuilder extends BaseChartBuilder<IntervalChartDefinition> {
public IntervalChartBuilder() {
super();
}
@Override
protected JFreeChart createChart() {
// note that IntervalChartDefinition is a line chart but this class creates a JFreeChart
// category plot
// interval charts use a non-numeric x-axis (1 value per interval) which requires a category
// axis and plot; the chart will still draw a line however via the LineAndShapeRenderer
CategoryAxis categoryAxis = new CategoryAxis();
NumberAxis valueAxis = new NumberAxis();
valueAxis.setAutoRangeIncludesZero(true);
LineAndShapeRenderer renderer = new LineAndShapeRenderer();
renderer.setBaseSeriesVisible(true, false);
CategoryPlot plot = new CategoryPlot(new DataTupleCategoryDataset(true), categoryAxis, valueAxis, renderer);
if (definition.hasSecondaryYAxis()) {
// second Y axis uses a separate dataset and axis
plot.setDataset(1, new DataTupleCategoryDataset(true));
valueAxis = new NumberAxis();
valueAxis.setAutoRangeIncludesZero(true);
renderer = new LineAndShapeRenderer();
renderer.setBaseSeriesVisible(true, false);
plot.setRenderer(1, renderer);
plot.setRangeAxis(1, valueAxis);
plot.mapDatasetToRangeAxis(1, 1);
}
// null title font => it will be set in format
// legend will be decided by callers
return new JFreeChart("", null, plot, false);
}
@Override
protected void formatChart() {
super.formatChart();
chart.setTitle(definition.getTitle());
CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.getDomainAxis().setLabel(definition.getXAxisLabel());
plot.getRangeAxis().setLabel(definition.getYAxisLabel());
if (definition.usePercentYAxis()) {
setPercentYAxis();
}
for (int i = 0; i < plot.getRendererCount(); i++) {
LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer(i);
renderer.setBaseShapesVisible(true);
renderer.setBaseShapesFilled(true);
renderer.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator("{1} {0} - {2}", new DecimalFormat(
"#,##0.00")));
plot.getRangeAxis(i).setLabelFont(LABEL_FONT);
plot.getRangeAxis(i).setTickLabelFont(AXIS_FONT);
}
// position of first line start and last line end
// 1.5% of the chart area within the axis will be blank space on each end
plot.getDomainAxis().setLowerMargin(.015);
plot.getDomainAxis().setUpperMargin(.015);
plot.getDomainAxis().setLabelFont(LABEL_FONT);
plot.getDomainAxis().setTickLabelFont(AXIS_FONT);
// position of first point start and last line end
// 1.5% of the chart area within the axis will be blank space on each end
plot.getDomainAxis().setLowerMargin(.015);
plot.getDomainAxis().setUpperMargin(.015);
// let each interval name have as much room as possible
plot.getDomainAxis().setCategoryMargin(0);
// gray grid lines
plot.setRangeGridlinePaint(GRID_COLOR);
plot.setRangeGridlineStroke(GRID_LINES);
}
public void addLine(IntervalChartDefinition lineDefinition, List<AnalysisRecord> records) {
if (chart == null) {
throw new IllegalStateException("initChart() must be called first");
}
if (definition == null) {
throw new IllegalArgumentException("IntervalChartDefintion cannot be null");
}
if ((records == null) || records.isEmpty()) {
// => no intervals defined
return;
}
if (records.size() > 4) {
((CategoryPlot) chart.getPlot()).getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_45);
}
DataTupleCategoryDataset dataset = (DataTupleCategoryDataset) ((CategoryPlot) chart.getPlot())
.getDataset(lineDefinition.hasSecondaryYAxis() ? 1 : 0);
// assume all records are from the same DataSet
DataSet data = records.get(0).getDataSet();
Map<String, Integer> usedIntervalNames = new java.util.HashMap<String, Integer>(records.size());
for (DataDefinition definition : lineDefinition.getData()) {
if (definition.matchesHost(data)) {
for (DataType type : definition.getMatchingTypes(data)) {
List<String> fields = definition.getMatchingFields(type);
for (String field : fields) {
String name = lineDefinition.getLineNamingMode().getName(definition, data, type, field,
getGranularity());
for (AnalysisRecord record : records) {
double value = definition.getStatistic().getValue(record, type, field);
String intervalName = record.getInterval().getName();
if ("".equals(intervalName)) {
if (record.getInterval().getDuration() >= (86400 * 1000)) {
intervalName = TimeFormatCache.formatDateTime(record.getInterval().getStart())
+ '-' + TimeFormatCache.formatDateTime(record.getInterval().getEnd());
}
else {
intervalName = TimeFormatCache.formatTime(record.getInterval().getStart()) + '-'
+ TimeFormatCache.formatTime(record.getInterval().getEnd());
}
}
// prevent duplicate interval / data name combinations
Integer count = usedIntervalNames.get(intervalName);
if (count != null) {
int i = dataset.getColumnIndex(name);
if (i != -1) {
usedIntervalNames.put(intervalName, ++count);
intervalName += " " + count;
}
}
else {
usedIntervalNames.put(intervalName, 0);
}
dataset.addValue(value, name, intervalName);
dataset.associateTuple(name, intervalName, new DataTuple(record.getDataSet(), type, field));
}
}
}
}
}
if (chart.getLegend() == null) {
int rowCount = chart.getCategoryPlot().getDataset(0).getRowCount();
if (definition.hasSecondaryYAxis()) {
rowCount += chart.getCategoryPlot().getDataset(1).getRowCount();
}
if (rowCount > 1) {
addLegend();
}
}
}
public void setPercentYAxis() {
NumberAxis yAxis = (NumberAxis) ((CategoryPlot) chart.getPlot()).getRangeAxis();
yAxis.setRange(0, 100);
}
}