use of com.serotonin.m2m2.util.chart.PointTimeSeriesCollection in project ma-modules-public by infiniteautomation.
the class ReportChartCreator method createContent.
/**
* Uses the given parameters to create the data for the fields of this class. Once the content has been created the
* getters for the fields can be used to retrieve.
*
* @param host - Mango's hostname
* @param port - Mango's port
* @param reportInstance
* @param reportDao
* @param inlinePrefix
* if this is non-null, it implies that the content should be inline.
* @param createExportFile
*/
public void createContent(String host, int port, ReportInstance reportInstance, ReportDao reportDao, String inlinePrefix, boolean createExportFile) {
this.inlinePrefix = inlinePrefix;
reportInstance.setTranslations(translations);
// Use a stream handler to get the report data from the database.
StreamHandler handler = new StreamHandler(host, port, reportInstance.getXidMap(), reportInstance.getReportStartTime(), reportInstance.getReportEndTime(), IMAGE_WIDTH, createExportFile, translations);
// Process the report content with the handler.
if (Common.databaseProxy.getNoSQLProxy() == null)
reportDao.reportInstanceDataSQL(reportInstance.getId(), handler);
else
reportDao.reportInstanceDataNoSQL(reportInstance.getId(), handler);
pointStatistics = handler.getPointStatistics();
devices = handler.getDevices();
pointMap = handler.getStatisticsMap();
UsedImagesDirective inlineImages = new UsedImagesDirective();
SubjectDirective subjectDirective = new SubjectDirective(translations);
// Prepare the model for the content rendering.
Map<String, Object> model = new HashMap<String, Object>();
model.put("fmt", new MessageFormatDirective(translations));
model.put("subject", subjectDirective);
model.put("img", inlineImages);
model.put("instance", reportInstance);
model.put("timezone", timeZone.getID());
model.put("points", pointStatistics);
model.put("inline", inlinePrefix == null ? "" : "cid:");
model.put("devices", devices);
model.put("mapped", pointMap);
model.put("ALPHANUMERIC", DataTypes.ALPHANUMERIC);
model.put("BINARY", DataTypes.BINARY);
model.put("MULTISTATE", DataTypes.MULTISTATE);
model.put("NUMERIC", DataTypes.NUMERIC);
model.put("IMAGE", DataTypes.IMAGE);
// Create the individual point charts
for (PointStatistics pointStat : pointStatistics) {
PointTimeSeriesCollection ptsc = new PointTimeSeriesCollection(timeZone);
if (pointStat.getNumericTimeSeries() != null)
ptsc.addNumericTimeSeries(pointStat.getNumericTimeSeries());
else if (pointStat.getDiscreteTimeSeries() != null)
ptsc.addDiscreteTimeSeries(pointStat.getDiscreteTimeSeries());
if (ptsc.hasData()) {
if (inlinePrefix != null)
model.put("chartName", inlinePrefix + pointStat.getChartName());
pointStat.setImageData(ImageChartUtils.getChartData(ptsc, POINT_IMAGE_WIDTH, POINT_IMAGE_HEIGHT, reportInstance.getReportStartTime(), reportInstance.getReportEndTime()));
}
// in the report I'll add it here while we are already iterating over the points that are included in the report
if (pointStat.getDataType() == DataTypes.IMAGE) {
ValueChangeCounter pointStatisticsGenerator = (ValueChangeCounter) pointStat.getStats();
ImageValue img = (ImageValue) (pointStatisticsGenerator.getLastValue());
if (img != null) {
try {
pointStat.setImageData(img.getImageData());
if (inlinePrefix != null)
model.put("chartName", inlinePrefix + pointStat.getChartName());
else {
// serve up the image using the reportImageChart servlet instead of the imageValueServlet that is used on flipbook page
// The path comes from the servlet path definition in web.xml.
model.put("chartName", IMAGE_SERVLET + pointStat.getChartName());
}
} catch (IOException e) {
LOG.error("failed to retrieve image data", e);
}
}
}
}
// consolidated chart
PointTimeSeriesCollection ptsc = handler.getPointTimeSeriesCollection();
if (ptsc.hasData()) {
if (inlinePrefix != null)
model.put("chartName", inlinePrefix + IMAGE_CONTENT_ID);
else {
chartName = "r" + reportInstance.getId() + ".png";
// The path comes from the servlet path definition in web.xml.
model.put("chartName", IMAGE_SERVLET + chartName);
}
imageData = ImageChartUtils.getChartData(ptsc, true, IMAGE_WIDTH, IMAGE_HEIGHT, reportInstance.getReportStartTime(), reportInstance.getReportEndTime());
}
List<EventInstance> events = null;
if (reportInstance.getIncludeEvents() != ReportVO.EVENTS_NONE) {
events = reportDao.getReportInstanceEvents(reportInstance.getId());
model.put("includeEvents", true);
model.put("events", events);
} else
model.put("includeEvents", false);
List<ReportUserComment> comments = null;
if (reportInstance.isIncludeUserComments()) {
comments = reportDao.getReportInstanceUserComments(reportInstance.getId());
// Only provide the list of point comments to the report. The event comments have already be correlated
// into the events list.
List<ReportUserComment> pointComments = new ArrayList<ReportUserComment>();
for (ReportUserComment c : comments) {
if (c.getCommentType() == UserCommentVO.TYPE_POINT)
pointComments.add(c);
}
model.put("includeUserComments", true);
model.put("userComments", pointComments);
} else
model.put("includeUserComments", false);
// Create the template.
Template ftl;
StringWriter writer = new StringWriter();
FileReader reader = null;
try {
File templateFile = ReportCommon.instance.getTemplateFile(reportInstance.getTemplateFile());
reader = new FileReader(templateFile);
ftl = new Template(reportInstance.getName(), reader, Common.freemarkerConfiguration);
ftl.process(model, writer);
} catch (FileNotFoundException e) {
LOG.error("Unable to find report template file: " + reportInstance.getName());
} catch (IOException e) {
// Couldn't load the template?
throw new ShouldNeverHappenException(e);
} catch (Exception e) {
// Error processing the FTL?
throw new ShouldNeverHappenException(e);
} finally {
if (reader != null)
try {
reader.close();
} catch (IOException e) {
LOG.error("Error closing template file reader: " + e.getMessage(), e);
}
}
// Save the content
html = writer.toString();
subject = subjectDirective.getSubject();
inlineImageList = inlineImages.getImageList();
// Save the export file (if any)
exportFile = handler.exportFile;
if (createExportFile && events != null) {
try {
eventFile = File.createTempFile("tempEventCSV", ".csv");
new EventCsvStreamer(new PrintWriter(new FileWriter(eventFile)), events, translations);
} catch (IOException e) {
LOG.error("Failed to create temp event file", e);
}
}
if (createExportFile && comments != null) {
try {
commentFile = File.createTempFile("tempCommentCSV", ".csv");
new UserCommentCsvStreamer(new PrintWriter(new FileWriter(commentFile)), comments, translations);
} catch (IOException e) {
LOG.error("Failed to create temp comment file", e);
}
}
}
use of com.serotonin.m2m2.util.chart.PointTimeSeriesCollection in project ma-core-public by infiniteautomation.
the class ImageChartUtils method writeChart.
public static void writeChart(PointTimeSeriesCollection pointTimeSeriesCollection, boolean showLegend, OutputStream out, int width, int height, long from, long to) throws IOException {
JFreeChart chart = ChartFactory.createTimeSeriesChart(null, null, null, null, showLegend, false, false);
chart.setBackgroundPaint(SystemSettingsDao.getColour(SystemSettingsDao.CHART_BACKGROUND_COLOUR));
XYPlot plot = chart.getXYPlot();
((DateAxis) plot.getDomainAxis()).setTimeZone(pointTimeSeriesCollection.getTimeZone());
plot.setBackgroundPaint(SystemSettingsDao.getColour(SystemSettingsDao.PLOT_BACKGROUND_COLOUR));
Color gridlines = SystemSettingsDao.getColour(SystemSettingsDao.PLOT_GRIDLINE_COLOUR);
plot.setDomainGridlinePaint(gridlines);
plot.setRangeGridlinePaint(gridlines);
((NumberAxis) plot.getRangeAxis()).setAutoRangeStickyZero(false);
double numericMin = 0;
double numericMax = 1;
int numericSeriesCount = pointTimeSeriesCollection.getNumericSeriesCount();
if (pointTimeSeriesCollection.hasNumericData()) {
for (int i = 0; i < numericSeriesCount; i++) {
NumericTimeSeries nts = pointTimeSeriesCollection.getNumericTimeSeries(i);
AbstractXYItemRenderer renderer;
if (nts.getPlotType() == DataPointVO.PlotTypes.STEP)
renderer = new XYStepRenderer();
else if (nts.getPlotType() == DataPointVO.PlotTypes.LINE)
renderer = new XYLineAndShapeRenderer(true, false);
else {
// XYCardinalSplineRenderer spline = new XYCardinalSplineRenderer(.5d, 16);
// XYSmoothLineAndShapeRenderer spline = new XYSmoothLineAndShapeRenderer();
// XYSplineRenderer spline = new XYSplineRenderer();
// spline.setBaseShapesVisible(false);
// renderer = spline;
renderer = new XYLineAndShapeRenderer(true, false);
}
if (nts.getPaint() != null)
renderer.setSeriesPaint(0, nts.getPaint(), false);
if (nts.getStroke() != null)
renderer.setSeriesStroke(0, nts.getStroke(), false);
plot.setDataset(i, new TimeSeriesCollection(nts.getTimeSeries()));
plot.setRenderer(i, renderer);
}
numericMin = plot.getRangeAxis().getLowerBound();
numericMax = plot.getRangeAxis().getUpperBound();
if (!pointTimeSeriesCollection.hasMultiplePoints()) {
// If this chart displays a single point, check if there should be a range description.
TimeSeries timeSeries = pointTimeSeriesCollection.getNumericTimeSeries(0).getTimeSeries();
String desc = timeSeries.getRangeDescription();
if (!StringUtils.isBlank(desc)) {
// Replace any HTML entities with Java equivalents
desc = StripEntities.stripHTMLEntities(desc, ' ');
plot.getRangeAxis().setLabel(desc);
}
}
} else
plot.getRangeAxis().setVisible(false);
if (pointTimeSeriesCollection.getRangeMarkers() != null) {
boolean rangeAdjusted = false;
for (Marker marker : pointTimeSeriesCollection.getRangeMarkers()) {
plot.addRangeMarker(marker);
if (marker instanceof ValueMarker) {
ValueMarker vm = (ValueMarker) marker;
if (numericMin > vm.getValue()) {
numericMin = vm.getValue();
rangeAdjusted = true;
}
if (numericMax < vm.getValue()) {
numericMax = vm.getValue();
rangeAdjusted = true;
}
}
}
if (rangeAdjusted) {
double adj = (numericMax - numericMin);
plot.getRangeAxis().setLowerBound(numericMin - adj * plot.getRangeAxis().getLowerMargin());
plot.getRangeAxis().setUpperBound(numericMax + adj * plot.getRangeAxis().getUpperMargin());
}
}
int discreteValueCount = pointTimeSeriesCollection.getDiscreteValueCount();
double interval = (numericMax - numericMin) / (discreteValueCount + 1);
int intervalIndex = 1;
if (pointTimeSeriesCollection.hasDiscreteData()) {
for (int i = 0; i < pointTimeSeriesCollection.getDiscreteSeriesCount(); i++) {
DiscreteTimeSeries dts = pointTimeSeriesCollection.getDiscreteTimeSeries(i);
XYStepRenderer renderer = new XYStepRenderer();
TimeSeries ts = new TimeSeries(dts.getName(), null, null);
for (IValueTime vt : dts.getValueTimes()) addMillisecond(ts, vt.getTime(), numericMin + (interval * (dts.getValueIndex(vt.getValue()) + intervalIndex)));
if (dts.getPaint() != null)
renderer.setSeriesPaint(0, dts.getPaint(), false);
if (dts.getStroke() != null)
renderer.setSeriesStroke(0, dts.getStroke(), false);
plot.setDataset(numericSeriesCount + i, new TimeSeriesCollection(ts, pointTimeSeriesCollection.getTimeZone()));
plot.setRenderer(numericSeriesCount + i, renderer);
intervalIndex += dts.getDiscreteValueCount();
}
}
if (from > 0)
plot.getDomainAxis().setLowerBound(from);
if (to > 0)
plot.getDomainAxis().setUpperBound(to);
if (pointTimeSeriesCollection.hasDiscreteData()) {
// Add the value annotations.
double annoX = plot.getDomainAxis().getLowerBound();
intervalIndex = 1;
for (int i = 0; i < pointTimeSeriesCollection.getDiscreteSeriesCount(); i++) {
DiscreteTimeSeries dts = pointTimeSeriesCollection.getDiscreteTimeSeries(i);
for (int j = 0; j < dts.getDiscreteValueCount(); j++) {
XYTextAnnotation anno = new XYTextAnnotation(" " + dts.getValueText(j), annoX, numericMin + (interval * (j + intervalIndex)));
if (!pointTimeSeriesCollection.hasNumericData() && intervalIndex + j == discreteValueCount)
// This prevents the top label from getting cut off
anno.setTextAnchor(TextAnchor.TOP_LEFT);
else
anno.setTextAnchor(TextAnchor.BOTTOM_LEFT);
anno.setPaint(((AbstractRenderer) plot.getRenderer(numericSeriesCount + i)).lookupSeriesPaint(0));
plot.addAnnotation(anno);
}
intervalIndex += dts.getDiscreteValueCount();
}
}
// Return the image.
ChartUtilities.writeChartAsPNG(out, chart, width, height);
}
use of com.serotonin.m2m2.util.chart.PointTimeSeriesCollection in project ma-core-public by infiniteautomation.
the class AsyncImageChartServlet method getImageData.
private byte[] getImageData(String imageInfo, HttpServletRequest request) throws IOException {
// Hex colour definitions need to be prefixed with '0x' instead of '#'.
try {
// Remove the / and the .png
imageInfo = imageInfo.substring(1, imageInfo.length() - 4);
// Split by underscore.
String[] imageBits = imageInfo.split("_");
// Get the data.
long from, to;
int pointIdStart;
if (imageBits[0].equals("ft")) {
from = Long.parseLong(imageBits[2]);
to = Long.parseLong(imageBits[3]);
pointIdStart = 4;
} else {
from = Common.timer.currentTimeMillis() - Long.parseLong(imageBits[1]);
to = -1;
pointIdStart = 2;
}
int width = getIntRequestParameter(request, "w", 200);
int height = getIntRequestParameter(request, "h", 100);
TimeZone timeZone = Common.getUserTimeZone(Common.getUser(request));
// Create the datasets
Synchronizer<PointDataRetriever> tasks = new Synchronizer<PointDataRetriever>();
List<Integer> dataPointIds = new ArrayList<Integer>();
for (int i = pointIdStart; i < imageBits.length; i++) {
if (imageBits[i].startsWith("w"))
width = NumberUtils.toInt(imageBits[i].substring(1), width);
else if (imageBits[i].startsWith("h"))
height = NumberUtils.toInt(imageBits[i].substring(1), height);
else {
String dataPointStr = imageBits[i];
Color colour = null;
int dataPointId;
int pipe = dataPointStr.indexOf('|');
if (pipe == -1)
dataPointId = Integer.parseInt(dataPointStr);
else {
try {
String colourStr = dataPointStr.substring(pipe + 1);
if (colourStr.startsWith("0x"))
colourStr = "#" + colourStr.substring(2);
colour = ColorUtils.toColor(colourStr);
} catch (InvalidArgumentException e) {
throw new IOException(e);
}
dataPointId = Integer.parseInt(dataPointStr.substring(0, pipe));
}
dataPointIds.add(dataPointId);
PointDataRetriever pdr = new PointDataRetriever(dataPointId, colour, width * 3, timeZone);
tasks.addTask(pdr);
}
}
if (tasks.getSize() == 0)
return null;
long start = from;
long end = to;
if (from == -1 && to == -1) {
LongPair sae = pointValueDao.getStartAndEndTime(dataPointIds);
start = sae.getL1();
end = sae.getL2();
} else if (from == -1)
start = pointValueDao.getStartTime(dataPointIds);
else if (to == -1)
end = pointValueDao.getEndTime(dataPointIds);
for (PointDataRetriever pdr : tasks.getTasks()) pdr.setRange(start, end);
// Get the timer
tasks.executeAndWait(Providers.get(TimerProvider.class).getTimer());
PointTimeSeriesCollection ptsc = new PointTimeSeriesCollection(timeZone);
for (PointDataRetriever pdr : tasks.getTasks()) pdr.addToCollection(ptsc);
return ImageChartUtils.getChartData(ptsc, width, height, from, to);
} catch (StringIndexOutOfBoundsException e) {
// no op
} catch (NumberFormatException e) {
// no op
} catch (ArrayIndexOutOfBoundsException e) {
// no op
}
return null;
}
use of com.serotonin.m2m2.util.chart.PointTimeSeriesCollection in project ma-core-public by infiniteautomation.
the class ImageChartServlet method getImageData.
private byte[] getImageData(String imageInfo, HttpServletRequest request) throws IOException {
// Hex colour definitions need to be prefixed with '0x' instead of '#'.
try {
// Remove the / and the .png
imageInfo = imageInfo.substring(1, imageInfo.length() - 4);
// Split by underscore.
String[] imageBits = imageInfo.split("_");
// Get the data.
long from, to;
int pointIdStart;
if (imageBits[0].equals("ft")) {
from = Long.parseLong(imageBits[2]);
to = Long.parseLong(imageBits[3]);
pointIdStart = 4;
} else {
from = Common.timer.currentTimeMillis() - Long.parseLong(imageBits[1]);
to = -1;
pointIdStart = 2;
}
int width = getIntRequestParameter(request, "w", 200);
int height = getIntRequestParameter(request, "h", 100);
String useCacheString = request.getParameter("useCache");
boolean useCache = false;
if (useCacheString != null && Boolean.valueOf(useCacheString))
useCache = true;
TimeZone timeZone = Common.getUserTimeZone(Common.getUser(request));
// Create the datasets
DataPointVO markerPoint = null;
int pointCount = 0;
PointTimeSeriesCollection ptsc = new PointTimeSeriesCollection(timeZone);
for (int i = pointIdStart; i < imageBits.length; i++) {
if (imageBits[i].startsWith("w"))
width = NumberUtils.toInt(imageBits[i].substring(1), width);
else if (imageBits[i].startsWith("h"))
height = NumberUtils.toInt(imageBits[i].substring(1), height);
else {
String dataPointStr = imageBits[i];
Color colour = null;
int dataPointId;
int pipe = dataPointStr.indexOf('|');
if (pipe == -1)
dataPointId = Integer.parseInt(dataPointStr);
else {
try {
String colourStr = dataPointStr.substring(pipe + 1);
if (colourStr.startsWith("0x"))
colourStr = "#" + colourStr.substring(2);
colour = ColorUtils.toColor(colourStr);
} catch (InvalidArgumentException e) {
throw new IOException(e);
}
dataPointId = Integer.parseInt(dataPointStr.substring(0, pipe));
}
// Get the data.
DataPointVO dp = DataPointDao.instance.getDataPoint(dataPointId);
if (dp != null && dp.getName() != null) {
pointCount++;
markerPoint = dp;
// Get the Color if there wasn't one provided
if (colour == null) {
try {
if (dp.getChartColour() != null)
colour = ColorUtils.toColor(dp.getChartColour());
} catch (InvalidArgumentException e) {
// Munch it
}
}
PointValueFacade pointValueFacade = new PointValueFacade(dataPointId, useCache);
List<PointValueTime> data;
if (from == -1 && to == -1)
data = pointValueFacade.getPointValuesBetween(0, Common.timer.currentTimeMillis(), true, true);
else if (from == -1)
data = pointValueFacade.getPointValuesBetween(0, to, true, true);
else if (to == -1)
data = pointValueFacade.getPointValuesBetween(from, Common.timer.currentTimeMillis(), true, true);
else
data = pointValueFacade.getPointValuesBetween(from, to, true, true);
if (dp.getPointLocator().getDataTypeId() == DataTypes.NUMERIC) {
TimeSeries ts;
if (dp.isUseRenderedUnit()) {
// This works because we enforce that all Units default to the ONE Unit if not used
UnitConverter converter = null;
if (dp.getRenderedUnit() != dp.getUnit())
converter = dp.getUnit().getConverterTo(dp.getRenderedUnit());
ts = new TimeSeries(dp.getExtendedName(), null, dp.getTextRenderer().getMetaText());
double value;
for (PointValueTime pv : data) {
if (pv.getValue() != null) {
if (converter != null)
value = converter.convert(pv.getDoubleValue());
else
value = pv.getDoubleValue();
ImageChartUtils.addMillisecond(ts, pv.getTime(), value);
}
}
} else {
// No renderer, don't need it
ts = new TimeSeries(dp.getExtendedName(), null, dp.getTextRenderer().getMetaText());
for (PointValueTime pv : data) {
if (pv.getValue() != null)
ImageChartUtils.addMillisecond(ts, pv.getTime(), pv.getValue().numberValue());
}
}
ptsc.addNumericTimeSeries(new NumericTimeSeries(dp.getPlotType(), ts, colour, null));
} else {
DiscreteTimeSeries ts = new DiscreteTimeSeries(dp.getExtendedName(), dp.getTextRenderer(), colour, null);
for (PointValueTime pv : data) if (pv.getValue() != null)
ts.addValueTime(pv);
ptsc.addDiscreteTimeSeries(ts);
}
}
}
}
if (pointCount == 1) {
// Only one point. Check for limits to draw as markers.
UnitConverter uc;
if (markerPoint.getUnit() != null && markerPoint.getRenderedUnit() != null)
uc = markerPoint.getUnit().getConverterTo(markerPoint.getRenderedUnit());
else
uc = Unit.ONE.getConverterTo(Unit.ONE);
for (AbstractPointEventDetectorVO<?> ped : markerPoint.getEventDetectors()) {
if (ped.getDefinition().getEventDetectorTypeName().equals(AnalogLowLimitEventDetectorDefinition.TYPE_NAME))
ptsc.addRangeMarker(new ValueMarker(uc.convert(((AnalogLowLimitDetectorVO) ped).getLimit()), lowLimitPaint, limitStroke));
else if (ped.getDefinition().getEventDetectorTypeName().equals(AnalogHighLimitEventDetectorDefinition.TYPE_NAME))
ptsc.addRangeMarker(new ValueMarker(uc.convert(((AnalogHighLimitDetectorVO) ped).getLimit()), highLimitPaint, limitStroke));
}
}
return ImageChartUtils.getChartData(ptsc, width, height, from, to);
} catch (StringIndexOutOfBoundsException e) {
// no op
} catch (NumberFormatException e) {
// no op
} catch (ArrayIndexOutOfBoundsException e) {
// no op
}
return null;
}
Aggregations