diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/PlotSettings.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/PlotSettings.java index d2caa00..85d1cf2 100644 --- a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/PlotSettings.java +++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/PlotSettings.java @@ -42,6 +42,8 @@ public class PlotSettings { private PlotType plotType; + private boolean generateThumbnail; + public String getQuery() { return query; } @@ -210,4 +212,12 @@ public class PlotSettings { public PlotType getPlotType() { return plotType; } + + public void setGenerateThumbnail(final boolean generateThumbnail) { + this.generateThumbnail = generateThumbnail; + } + + public boolean isGenerateThumbnail() { + return generateThumbnail; + } } diff --git a/pdb-plotting/src/main/java/org/lucares/recommind/logs/GnuplotFileGenerator.java b/pdb-plotting/src/main/java/org/lucares/recommind/logs/GnuplotFileGenerator.java index f380291..f9f886a 100644 --- a/pdb-plotting/src/main/java/org/lucares/recommind/logs/GnuplotFileGenerator.java +++ b/pdb-plotting/src/main/java/org/lucares/recommind/logs/GnuplotFileGenerator.java @@ -13,31 +13,29 @@ public class GnuplotFileGenerator { appendfln(result, "set terminal %s noenhanced size %d,%d", settings.getTerminal(), settings.getWidth(), settings.getHeight()); - - appendfln(result, "set datafile separator \"%s\"", settings.getDatafileSeparator()); - + settings.getAggregate().addGnuplotDefinitions(result, settings.getDatafileSeparator(), dataSeries); - + appendfln(result, "set timefmt '%s'", settings.getTimefmt()); final XAxisSettings xAxis = settings.getxAxisSettings(); - if (xAxis.isxDataTime()){ + if (xAxis.isxDataTime()) { appendfln(result, "set xdata time"); } + appendfln(result, "set xtics nomirror rotate by %d", xAxis.getRotateXAxisLabel()); appendfln(result, "set format x \"%s\"", xAxis.getFormatX()); appendfln(result, "set xlabel \"%s\"", xAxis.getXlabel()); - appendfln(result, "set xtics nomirror rotate by %d", xAxis.getRotateXAxisLabel()); appendfln(result, "set xrange [\"%s\":\"%s\"]", xAxis.getFrom(), xAxis.getTo()); - + appendfln(result, "set x2label \"Percentile\""); appendln(result, "set format x2 \"%.0f%%\""); appendfln(result, "set x2tics"); appendfln(result, "set x2range [\"0\":\"100\"]"); - + final long graphOffset = settings.getYAxisScale() == AxisScale.LINEAR ? 0 : 1; - appendfln(result, "set yrange [\""+graphOffset+"\":]"); - + appendfln(result, "set yrange [\"" + graphOffset + "\":]"); + appendfln(result, "set ylabel \"%s\"", settings.getYlabel()); switch (settings.getYAxisScale()) { case LINEAR: @@ -52,20 +50,33 @@ public class GnuplotFileGenerator { appendfln(result, "set grid"); appendfln(result, "set output \"%s\"", settings.getOutput().toAbsolutePath().toString().replace("\\", "/")); - + // marker lines that show which area will be zoomed final long minDate = Long.parseLong(settings.getxAxisSettings().getFrom()); final long maxDate = Long.parseLong(settings.getxAxisSettings().getTo()); - appendfln(result, "set arrow from "+(minDate + (maxDate-minDate)*0.25)+","+graphOffset+" rto graph 0,1 lt 3 lc rgb \"#EEEEEE\" nohead"); - appendfln(result, "set arrow from "+(minDate + (maxDate-minDate)*0.75)+","+graphOffset+" rto graph 0,1 lc rgb \"#EEEEEE\" nohead"); - - if (settings.isKeyOutside()){ + appendfln(result, "set arrow from " + (minDate + (maxDate - minDate) * 0.25) + "," + graphOffset + + " rto graph 0,1 lt 3 lc rgb \"#EEEEEE\" nohead"); + appendfln(result, "set arrow from " + (minDate + (maxDate - minDate) * 0.75) + "," + graphOffset + + " rto graph 0,1 lc rgb \"#EEEEEE\" nohead"); + + if (settings.isKeyOutside()) { appendfln(result, "set key outside"); } appendfln(result, "set key font \",10\""); - + + if (!settings.isRenderLabels()) { + appendfln(result, "set format x \"\"", xAxis.getFormatX()); + appendfln(result, "set xlabel \"\"", xAxis.getXlabel()); + appendfln(result, "set x2label \"\""); + appendln(result, "set format x2 \"\""); + + appendfln(result, "set ylabel \"\"", settings.getYlabel()); + appendln(result, "set format y \"\""); + appendln(result, "set nokey"); + } + appendf(result, "plot "); - + for (final DataSeries dataSerie : dataSeries) { appendfln(result, dataSerie.getGnuplotPlotDefinition()); } @@ -77,10 +88,9 @@ public class GnuplotFileGenerator { private void appendfln(final StringBuilder builder, final String format, final Object... args) { builder.append(String.format(format + "\n", args)); } - private void appendln(final StringBuilder builder, final String string) { - builder.append(string+"\n"); + builder.append(string + "\n"); } private void appendf(final StringBuilder builder, final String format, final Object... args) { diff --git a/pdb-plotting/src/main/java/org/lucares/recommind/logs/GnuplotSettings.java b/pdb-plotting/src/main/java/org/lucares/recommind/logs/GnuplotSettings.java index cc4e7bd..954f653 100644 --- a/pdb-plotting/src/main/java/org/lucares/recommind/logs/GnuplotSettings.java +++ b/pdb-plotting/src/main/java/org/lucares/recommind/logs/GnuplotSettings.java @@ -11,11 +11,9 @@ public class GnuplotSettings { private int width = 1600; private String timefmt = "%s"; // time as unix epoch, but as double - // set datafile separator private String datafileSeparator = ","; - // set ylabel private String ylabel = "Duration in ms"; @@ -25,27 +23,22 @@ public class GnuplotSettings { private AxisScale yAxisScale; private AggregateHandler aggregate; private boolean keyOutside = false; - + private XAxisSettings xAxisSettings = new XAxisSettings(); + private boolean renderLabels = true; public GnuplotSettings(final Path output) { this.output = output; } - - public XAxisSettings getxAxisSettings() { return xAxisSettings; } - - - public void setxAxisSettings(XAxisSettings xAxisSettings) { + public void setxAxisSettings(final XAxisSettings xAxisSettings) { this.xAxisSettings = xAxisSettings; } - - public String getTerminal() { return terminal; } @@ -78,7 +71,6 @@ public class GnuplotSettings { this.timefmt = timefmt; } - public String getDatafileSeparator() { return datafileSeparator; } @@ -107,15 +99,15 @@ public class GnuplotSettings { return yAxisScale; } - public void setAggregate(AggregateHandler aggregate) { + public void setAggregate(final AggregateHandler aggregate) { this.aggregate = aggregate; } - + public AggregateHandler getAggregate() { return aggregate; } - - public void setKeyOutside(boolean keyOutside) { + + public void setKeyOutside(final boolean keyOutside) { this.keyOutside = keyOutside; } @@ -123,6 +115,14 @@ public class GnuplotSettings { return keyOutside; } + public void renderLabels(final boolean renderLabels) { + this.renderLabels = renderLabels; + } + + public boolean isRenderLabels() { + return renderLabels; + } + // plot 'sample.txt' using 1:2 title 'Bytes' with linespoints 2 } diff --git a/pdb-plotting/src/main/java/org/lucares/recommind/logs/ScatterPlot.java b/pdb-plotting/src/main/java/org/lucares/recommind/logs/ScatterPlot.java index 82fc533..e939a6a 100644 --- a/pdb-plotting/src/main/java/org/lucares/recommind/logs/ScatterPlot.java +++ b/pdb-plotting/src/main/java/org/lucares/recommind/logs/ScatterPlot.java @@ -1,7 +1,5 @@ package org.lucares.recommind.logs; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; @@ -23,8 +21,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; -import javax.imageio.ImageIO; - import org.lucares.pdb.api.Entry; import org.lucares.pdb.api.GroupResult; import org.lucares.pdb.api.Result; @@ -111,19 +107,36 @@ public class ScatterPlot implements ConcretePlotter { DataSeries.setColors(dataSeries); final Path outputFile = Files.createTempFile(outputDir, "", ".png"); - final Gnuplot gnuplot = new Gnuplot(tmpBaseDir); - final GnuplotSettings gnuplotSettings = new GnuplotSettings(outputFile); - gnuplotSettings.setHeight(height); - gnuplotSettings.setWidth(width); - defineXAxis(gnuplotSettings, plotSettings.dateFrom(), plotSettings.dateTo()); + { + final Gnuplot gnuplot = new Gnuplot(tmpBaseDir); + final GnuplotSettings gnuplotSettings = new GnuplotSettings(outputFile); + gnuplotSettings.setHeight(height); + gnuplotSettings.setWidth(width); + defineXAxis(gnuplotSettings, plotSettings.dateFrom(), plotSettings.dateTo()); - gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale()); - gnuplotSettings.setAggregate(plotSettings.getAggregate()); - gnuplotSettings.setKeyOutside(plotSettings.isKeyOutside()); - gnuplot.plot(gnuplotSettings, dataSeries); + gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale()); + gnuplotSettings.setAggregate(plotSettings.getAggregate()); + gnuplotSettings.setKeyOutside(plotSettings.isKeyOutside()); + gnuplot.plot(gnuplotSettings, dataSeries); + } - final Path thumbnail = createOptionalThumbnail(outputFile, plotSettings.getThumbnailMaxWidth(), - plotSettings.getThumbnailMaxHeight()); + final Path thumbnail; + if (plotSettings.isGenerateThumbnail()) { + thumbnail = Files.createTempFile(outputDir, "", ".png"); + final Gnuplot gnuplot = new Gnuplot(tmpBaseDir); + final GnuplotSettings gnuplotSettings = new GnuplotSettings(thumbnail); + gnuplotSettings.setHeight(plotSettings.getThumbnailMaxHeight()); + gnuplotSettings.setWidth(plotSettings.getThumbnailMaxWidth()); + defineXAxis(gnuplotSettings, plotSettings.dateFrom(), plotSettings.dateTo()); + + gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale()); + gnuplotSettings.setAggregate(plotSettings.getAggregate()); + gnuplotSettings.setKeyOutside(false); + gnuplotSettings.renderLabels(false); + gnuplot.plot(gnuplotSettings, dataSeries); + } else { + thumbnail = null; + } return new PlotResult(outputFile, dataSeries, thumbnail); } catch (final InterruptedException e) { @@ -137,43 +150,6 @@ public class ScatterPlot implements ConcretePlotter { } } - private static BufferedImage resizeImage(final BufferedImage originalImage, final Integer img_width, - final Integer img_height) { - final int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType(); - final BufferedImage resizedImage = new BufferedImage(img_width, img_height, type); - final Graphics2D g = resizedImage.createGraphics(); - g.drawImage(originalImage, 0, 0, img_width, img_height, null); - g.dispose(); - - return resizedImage; - } - - private Path createOptionalThumbnail(final Path originalImage, final int thumbnailMaxWidth, - final int thumbnailMaxHeight) { - - Path result; - if (thumbnailMaxWidth > 0 && thumbnailMaxHeight > 0 && Files.exists(originalImage)) { - try { - final long start = System.nanoTime(); - final BufferedImage image = ImageIO.read(originalImage.toFile()); - - final BufferedImage thumbnail = resizeImage(image, thumbnailMaxWidth, thumbnailMaxHeight); - final Path thumbnailPath = Files.createTempFile(outputDir, "", ".png"); - - ImageIO.write(thumbnail, "png", thumbnailPath.toFile()); - LOGGER.info("thumbnail creation: " + (System.nanoTime() - start) / 1_000_000.0 + "ms"); - result = thumbnailPath; - } catch (final IOException | RuntimeException e) { - LOGGER.warn("failed to scale image", e); - result = null; - } - } else { - result = null; - } - - return result; - } - private void defineXAxis(final GnuplotSettings gnuplotSettings, final OffsetDateTime minDate, final OffsetDateTime maxDate) { diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/PdbController.java b/pdb-ui/src/main/java/org/lucares/pdbui/PdbController.java index 57422e1..94a38eb 100644 --- a/pdb-ui/src/main/java/org/lucares/pdbui/PdbController.java +++ b/pdb-ui/src/main/java/org/lucares/pdbui/PdbController.java @@ -130,7 +130,7 @@ public class PdbController implements HardcodedValues, PropertyKeys { final String thumbnailUrl = result.getThumbnailPath() != null ? WEB_IMAGE_OUTPUT_PATH + "/" + result.getThumbnailName() - : imageUrl; + : "img/no-thumbnail.png"; final PlotResponseStats stats = PlotResponseStats.fromDataSeries(result.getDataSeries()); final PlotResponse plotResponse = new PlotResponse(stats, imageUrl, thumbnailUrl); @@ -184,6 +184,7 @@ public class PdbController implements HardcodedValues, PropertyKeys { plotSettings.setPlotType(plotType); plotSettings.setAggregate(PlotSettingsTransformer.toAggregateInternal(aggregate)); plotSettings.setKeyOutside(keyOutside); + plotSettings.setGenerateThumbnail(false); if (plotterLock.tryLock()) { try { diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/PlotSettingsTransformer.java b/pdb-ui/src/main/java/org/lucares/pdbui/PlotSettingsTransformer.java index fac9235..da067c0 100644 --- a/pdb-ui/src/main/java/org/lucares/pdbui/PlotSettingsTransformer.java +++ b/pdb-ui/src/main/java/org/lucares/pdbui/PlotSettingsTransformer.java @@ -26,6 +26,7 @@ class PlotSettingsTransformer { result.setKeyOutside(request.isKeyOutside()); result.setThumbnailMaxWidth(request.getThumbnailMaxWidth()); result.setThumbnailMaxHeight(request.getThumbnailMaxHeight()); + result.setGenerateThumbnail(request.isGenerateThumbnail()); return result; } diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/domain/PlotRequest.java b/pdb-ui/src/main/java/org/lucares/pdbui/domain/PlotRequest.java index 96f4e29..35d5037 100644 --- a/pdb-ui/src/main/java/org/lucares/pdbui/domain/PlotRequest.java +++ b/pdb-ui/src/main/java/org/lucares/pdbui/domain/PlotRequest.java @@ -35,6 +35,8 @@ public class PlotRequest { private boolean keyOutside; + private boolean generateThumbnail; + public String getQuery() { return query; } @@ -154,4 +156,13 @@ public class PlotRequest { public boolean isKeyOutside() { return keyOutside; } + + public boolean isGenerateThumbnail() { + return generateThumbnail; + } + + public void setGenerateThumbnail(final boolean generateThumbnail) { + this.generateThumbnail = generateThumbnail; + } + } diff --git a/pdb-ui/src/main/resources/resources/css/design.css b/pdb-ui/src/main/resources/resources/css/design.css index 92bc23f..b55e2d2 100644 --- a/pdb-ui/src/main/resources/resources/css/design.css +++ b/pdb-ui/src/main/resources/resources/css/design.css @@ -189,16 +189,18 @@ textarea { float: left; background: white; box-shadow: 5px 5px 10px 0px #aaa; + position: relative; } .dashboard-item img { max-width: 300px; - max-height: 180px; + max-height: 200px; display:block; /* removes 3 pixels extra height around the image */ } -.dashboard-item fieldValue{ - +.dashboard-item .fieldValue{ + position: absolute; + bottom: 0; } #result-view-dashboard-image-viewer { diff --git a/pdb-ui/src/main/resources/resources/js/ui.js b/pdb-ui/src/main/resources/resources/js/ui.js index 2ec9634..29d7f34 100644 --- a/pdb-ui/src/main/resources/resources/js/ui.js +++ b/pdb-ui/src/main/resources/resources/js/ui.js @@ -841,9 +841,9 @@ function plotCurrent() var splitByField = splitBy['field']; var splitByValue = splitBy['values'][splitBy['index']]; var query = createQuery(originalQuery, splitByField, splitByValue); - sendPlotRequest(query); + sendPlotRequest(query, false); }else{ - sendPlotRequest(data.searchBar.query); + sendPlotRequest(data.searchBar.query, false); } } @@ -869,7 +869,7 @@ function groupBy() return result; } -function createRequest(query){ +function createRequest(query, generateThumbnail){ var request = {}; request['query'] = query; request['height'] = Math.floor($('#result').height()); @@ -883,12 +883,13 @@ function createRequest(query){ request['plotType'] = data.searchBar.plotType; request['aggregate'] = data.searchBar.aggregate; request['keyOutside'] = data.searchBar.keyOutside; + request['generateThumbnail'] = generateThumbnail; return request; } -function sendPlotRequest(query){ - const request = createRequest(query); +function sendPlotRequest(query, generateThumbnail){ + const request = createRequest(query, generateThumbnail); const success = function(response){ data.resultView.imageUrl = response.imageUrl; @@ -970,7 +971,8 @@ function createDashboardItem(originalQuery, field, imageHeight, imageWidth) if (data.dashboard.toBeRendered.length > 0) { var fieldValue = data.dashboard.toBeRendered.pop(); const query = createQuery(originalQuery, field, fieldValue); - const request = createRequest(query); + const generateThumbnail = true; + const request = createRequest(query, generateThumbnail); request['height'] = imageHeight; request['width'] = imageWidth; request['thumbnailMaxWidth'] = 300;