
com.mgmtp.perfload.perfalyzer.reportpreparation.PlotCreator Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2013-2015 mgm technology partners GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mgmtp.perfload.perfalyzer.reportpreparation;
import com.mgmtp.perfload.perfalyzer.annotations.IntFormat;
import com.mgmtp.perfload.perfalyzer.util.Marker;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.LogarithmicAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.block.LineBorder;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.IntervalMarker;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.ui.Layer;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleInsets;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.List;
import java.util.ResourceBundle;
import static com.google.common.io.Files.createParentDirs;
import static com.mgmtp.perfload.perfalyzer.util.PerfAlyzerUtils.selectDisplayData;
/**
* @author rnaegele
*/
@Singleton
public class PlotCreator {
private static final StandardChartTheme CHART_THEME = new StandardChartTheme("JFree");
static {
CHART_THEME.setDrawingSupplier(new PerfAlyzerDrawingSupplier());
}
public static enum AxisType {
LINEAR,
LOGARITHMIC
}
public static enum RendererType {
LINES {
@Override
XYItemRenderer createRenderer() {
return new XYLineAndShapeRenderer(true, false);
}
},
SHAPES {
@Override
XYItemRenderer createRenderer() {
return new XYLineAndShapeRenderer(false, true);
}
},
LINES_AND_SHAPES {
@Override
XYItemRenderer createRenderer() {
return new XYLineAndShapeRenderer(true, true);
}
};
abstract XYItemRenderer createRenderer();
}
public static enum ChartDimensions {
DEFAULT(640, 400),
LARGE(1115, 800),
WIDE(1115, 400);
private final int width;
private final int height;
private ChartDimensions(final int width, final int height) {
this.width = width;
this.height = height;
}
/**
* @return the width
*/
public int getWidth() {
return width;
}
/**
* @return the height
*/
public int getHeight() {
return height;
}
}
private final NumberFormat numberFormat;
private final ResourceBundle resourceBundle;
private final List displayDataList;
private final List markers;
@Inject
public PlotCreator(@IntFormat final NumberFormat numberFormat, final ResourceBundle resourceBundle,
final List displayDataList, final List markers) {
this.numberFormat = numberFormat;
this.resourceBundle = resourceBundle;
this.displayDataList = displayDataList;
this.markers = markers;
}
public JFreeChart createPlot(final AxisType xAxisType, final AxisType yAxisType, final RendererType rendererType,
final DisplayData displayData, final DataRange dataRange, boolean showMarkers, final NumberDataSet... dataSets) {
NumberAxis xAxis = createAxis(xAxisType, resourceBundle.getString(displayData.getUnitX()));
XYPlot plot;
if (dataSets.length == 1) {
NumberAxis yAxis = createAxis(yAxisType, resourceBundle.getString(displayData.getUnitY()));
plot = new XYPlot(dataSets[0], xAxis, yAxis, rendererType.createRenderer());
} else {
CombinedDomainXYPlot combinedPlot = new CombinedDomainXYPlot(xAxis);
for (int i = 0; i < dataSets.length; ++i) {
NumberDataSet dataSet = dataSets[i];
// no range for y-axis!
NumberAxis yAxis = createAxis(yAxisType, resourceBundle.getString(displayData.getUnitYList().get(i)));
XYPlot subPlot = new XYPlot(dataSet, null, yAxis, rendererType.createRenderer());
combinedPlot.add(subPlot);
formatPlot(subPlot);
}
plot = combinedPlot;
}
JFreeChart chart = new JFreeChart(plot);
CHART_THEME.apply(chart);
formatPlot(plot);
if (showMarkers) {
for (Marker marker : markers) {
IntervalMarker im = new IntervalMarker(marker.getLeftMillis() / 1000L, marker.getRightMillis() / 1000L);
im.setLabel(marker.getName());
im.setLabelFont(new Font("Sans Serif", Font.ITALIC | Font.BOLD, 14));
im.setLabelAnchor(RectangleAnchor.TOP);
im.setLabelOffset(new RectangleInsets(8d, 0d, 0d, 0d));
im.setLabelPaint(Color.BLACK);
im.setAlpha(.2f);
im.setPaint(Color.WHITE);
im.setOutlinePaint(Color.BLACK);
im.setOutlineStroke(new BasicStroke(1.0f));
plot.addDomainMarker(im, Layer.BACKGROUND);
}
}
LegendTitle legend = chart.getLegend();
legend.setBackgroundPaint(new Color(229, 229, 229));
legend.setFrame(new LineBorder(new Color(213, 213, 213), new BasicStroke(1.0f), legend.getFrame().getInsets()));
// only for non-logarithmic axes
// range must be set after plot is created, otherwise nothing is drawn
if (dataRange != null && !xAxisType.equals(AxisType.LOGARITHMIC)) {
xAxis.setRange(dataRange.getLowerSeconds(), dataRange.getUpperSeconds());
}
return chart;
}
private NumberAxis createAxis(final AxisType axisType, final String axisLabel) {
NumberAxis numberAxis =
axisType.equals(AxisType.LOGARITHMIC) ? new LogarithmicAxis(axisLabel) : new NumberAxis(axisLabel);
numberAxis.setNumberFormatOverride((NumberFormat) numberFormat.clone());
return numberAxis;
}
private void formatPlot(final Plot plot) {
plot.setBackgroundPaint(new GradientPaint(0f, 0f, new Color(213, 213, 213), 0f, 0f, new Color(156, 156, 156)));
plot.setOutlinePaint(new Color(221, 221, 221));
}
public void writePlotFile(final File file, final AxisType xAxisType, final AxisType yAxisType,
final RendererType rendererType, final DisplayData displayData, final ChartDimensions dimensions,
final DataRange dataRange, boolean showMarkers, final NumberDataSet... dataSets) throws IOException {
createParentDirs(file);
for (NumberDataSet dataSet : dataSets) {
dataSet.sortSeries();
}
JFreeChart chart = createPlot(xAxisType, yAxisType, rendererType, displayData, dataRange, showMarkers, dataSets);
BufferedImage chartImage = chart.createBufferedImage(dimensions.getWidth(), dimensions.getHeight());
ImageIO.write(chartImage, "png", file);
}
public void writePlotFile(final File file, final AxisType xAxisType, final AxisType yAxisType,
final RendererType rendererType, final ChartDimensions dimensions, final DataRange dataRange, boolean showMarkers,
final NumberDataSet... dataSets) throws IOException {
DisplayData displayData = selectDisplayData(file, displayDataList);
writePlotFile(file, xAxisType, yAxisType, rendererType, displayData, dimensions, dataRange, showMarkers, dataSets);
}
static class PerfAlyzerDrawingSupplier extends DefaultDrawingSupplier {
public PerfAlyzerDrawingSupplier() {
super(DEFAULT_PAINT_SEQUENCE, DEFAULT_FILL_PAINT_SEQUENCE, DEFAULT_OUTLINE_PAINT_SEQUENCE,
new Stroke[]{new BasicStroke(1.5f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL)},
DEFAULT_OUTLINE_STROKE_SEQUENCE, createStandardSeriesShapes());
}
/**
* Creates an array of standard shapes to display for the items in series on charts.
*
* @return The array of shapes.
*/
public static Shape[] createStandardSeriesShapes() {
Shape[] result = new Shape[10];
double size = 4.0;
double delta = size / 2.0;
// square
result[0] = new Rectangle2D.Double(-delta, -delta, size, size);
// circle
result[1] = new Ellipse2D.Double(-delta, -delta, size, size);
// up-pointing triangle
int[] xpoints = intArray(0.0, delta, -delta);
int[] ypoints = intArray(-delta, delta, delta);
result[2] = new Polygon(xpoints, ypoints, 3);
// diamond
xpoints = intArray(0.0, delta, 0.0, -delta);
ypoints = intArray(-delta, 0.0, delta, 0.0);
result[3] = new Polygon(xpoints, ypoints, 4);
// horizontal rectangle
result[4] = new Rectangle2D.Double(-delta, -delta / 2, size, size / 2);
// down-pointing triangle
xpoints = intArray(-delta, +delta, 0.0);
ypoints = intArray(-delta, -delta, delta);
result[5] = new Polygon(xpoints, ypoints, 3);
// horizontal ellipse
result[6] = new Ellipse2D.Double(-delta, -delta / 2, size, size / 2);
// right-pointing triangle
xpoints = intArray(-delta, delta, -delta);
ypoints = intArray(-delta, 0.0, delta);
result[7] = new Polygon(xpoints, ypoints, 3);
// vertical rectangle
result[8] = new Rectangle2D.Double(-delta / 2, -delta, size / 2, size);
// left-pointing triangle
xpoints = intArray(-delta, delta, delta);
ypoints = intArray(0.0, -delta, +delta);
result[9] = new Polygon(xpoints, ypoints, 3);
return result;
}
/**
* Helper method to avoid lots of explicit casts in getShape(). Returns an array containing
* the provided doubles cast to ints.
*
* @param a
* x
* @param b
* y
* @param c
* z
* @return int[3] with converted params.
*/
private static int[] intArray(final double a, final double b, final double c) {
return new int[]{(int) a, (int) b, (int) c};
}
/**
* Helper method to avoid lots of explicit casts in getShape(). Returns an array containing
* the provided doubles cast to ints.
*
* @param a
* x
* @param b
* y
* @param c
* z
* @param d
* t
* @return int[4] with converted params.
*/
private static int[] intArray(final double a, final double b, final double c, final double d) {
return new int[]{(int) a, (int) b, (int) c, (int) d};
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy