diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/AggregateHandler.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/AggregateHandler.java index 48af7d4..a8c42f1 100644 --- a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/AggregateHandler.java +++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/AggregateHandler.java @@ -26,10 +26,6 @@ public interface AggregateHandler { return title.isPresent() ? "title '"+title.get()+"'": "notitle"; } -// void addPlotsBeforeScatter(StringBuilder result, Collection dataSeries); -// -// void addPlotsAfterScatter(StringBuilder result, Collection dataSeries); - void addPlot(StringBuilder result, AggregatedData aggregatedData, LineStyle lineStyle, Optional title); CustomAggregator createCustomAggregator(Path tmpDir, PlotSettings plotSettings, long fromEpochMilli, long toEpochMilli); 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 cddfe03..43e8415 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 @@ -1,22 +1,12 @@ package org.lucares.recommind.logs; -import static java.util.concurrent.TimeUnit.DAYS; -import static java.util.concurrent.TimeUnit.HOURS; -import static java.util.concurrent.TimeUnit.MINUTES; -import static java.util.concurrent.TimeUnit.SECONDS; - -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.List; -import java.util.concurrent.TimeUnit; import org.lucares.pdb.plot.api.AxisScale; public class GnuplotFileGenerator { private static final int KEY_FONT_SIZE = 10; - private static final int TICKS_FONT_SIZE = 12; public String generate(final GnuplotSettings settings, final Collection dataSeries) { @@ -60,14 +50,6 @@ public class GnuplotFileGenerator { appendfln(result, "set grid"); appendfln(result, "set output \"%s\"", settings.getOutput().toAbsolutePath().toString().replace("\\", "/")); - // TODO remove marker lines? - // marker lines that show which area will be zoomed - appendfln(result, "set arrow from graph 0.25,0 rto graph 0,1 lc rgb \"#EEEEEE\" nohead"); - appendfln(result, "set arrow from graph 0.75,0 rto graph 0,1 lc rgb \"#EEEEEE\" nohead"); - - // marker line for the 60 second threshold - appendfln(result, "set arrow from graph 0, first 60000 rto graph 1,0 lc rgb \"#EEEEEE\" nohead"); - if (settings.isKeyOutside()) { appendfln(result, "set key outside"); } @@ -94,11 +76,11 @@ public class GnuplotFileGenerator { appendln(result, "set tmargin 3"); // margin 3 -> 57px - marker (1) appendln(result, "set bmargin 4"); // margin 4 -> 76 - appendfln(result, "set tics font \",%d\"", TICKS_FONT_SIZE); - appendln(result, computeYTicks(settings, dataSeries)); + appendfln(result, "set tics font \",%d\"", YAxisTicks.TICKS_FONT_SIZE); + appendln(result, YAxisTicks.computeYTicks(settings, dataSeries)); } else { - appendfln(result, "set tics font \",%d\"", TICKS_FONT_SIZE); - appendln(result, computeYTicks(settings, dataSeries)); + appendfln(result, "set tics font \",%d\"", YAxisTicks.TICKS_FONT_SIZE); + appendln(result, YAxisTicks.computeYTicks(settings, dataSeries)); } appendf(result, "plot "); @@ -124,152 +106,5 @@ public class GnuplotFileGenerator { builder.append(String.format(format, args)); } - private String computeYTicks(final GnuplotSettings settings, final Collection dataSeries) { - String result = ""; - - final long yRangeMax; - final long yRangeMin; - if (settings.hasYRange()) { - yRangeMax = settings.getYRangeMax(); - yRangeMin = settings.getYRangeMin(); - } else { - yRangeMax = DataSeries.maxValue(dataSeries); - yRangeMin = 0; - } - final int height = settings.getHeight(); - - switch (settings.getYAxisScale()) { - case LINEAR: - result = computeLinearYTicks(height, yRangeMin, yRangeMax); - break; - case LOG10: - result = computeLog10YTicks(height, yRangeMin, yRangeMax); - break; - default: - // use the default - } - return result; - } - - private String computeLog10YTicks(final int height, final long yRangeMin, final long yRangeMax) { - final StringBuilder result = new StringBuilder(); - appendfln(result, "set ylabel \"%s\"", "Duration"); - - final List ticsLabels = Arrays.asList(// - "\"1ms\" 1", // - "\"2ms\" 2", // - "\"5ms\" 5", // - "\"10ms\" 10", // - "\"20ms\" 20", // - "\"50ms\" 50", // - "\"100ms\" 100", // - "\"200ms\" 200", // - "\"500ms\" 500", // - "\"1s\" 1000", // - "\"2s\" 2000", // - "\"5s\" 5000", // - "\"10s\" 10000", // - "\"30s\" 30000", // - "\"1m\" 60000", // - "\"2m\" 120000", // - "\"5m\" 300000", // - "\"10m\" 600000", // - "\"30m\" 1800000", // - "\"1h\" 3600000", // - "\"2h\" 7200000", // - "\"4h\" 14400000", // - "\"8h\" 28800000", // - "\"16h\" 57600000", // - "\"1d\" 86400000", // - "\"2d\" 172800000", // - "\"1 week\" 604800000", // - "\"2 week\" 1209600000.0", // - "\"4 week\" 2419200000.0" // - ); - - result.append("set ytics ("); - result.append(String.join(", ", ticsLabels)); - result.append(")\n"); - - return result.toString(); - } - - private String computeLinearYTicks(final long height, final long yRangeMin, final long yRangeMax) { - final StringBuilder result = new StringBuilder(); - appendfln(result, "set ylabel \"%s\"", "Duration"); - - final long plotHeight = height - GnuplotSettings.GNUPLOT_TOP_BOTTOM_MARGIN; // sum of top/bottom margin, see - // marker (1) - final long maxLabels = plotHeight / (TICKS_FONT_SIZE * 5); - - final long range = yRangeMax - yRangeMin; - final long msPerLabel = roundToLinearLabelSteps(range / maxLabels); - - final List ticsLabels = new ArrayList<>(); - for (long i = yRangeMin; i <= yRangeMax; i += msPerLabel) { - ticsLabels.add("\"" + msToTic(i, msPerLabel) + "\" " + i); - } - - result.append("set ytics ("); - result.append(String.join(", ", ticsLabels)); - result.append(")\n"); - return result.toString(); - } - - private long roundToLinearLabelSteps(final long msPerLabel) { - final List steps = Arrays.asList(2L, 5L, 10L, 20L, 50L, 100L, 200L, 500L, 1000L, 2000L, 5000L, 10_000L, - 20_000L, MINUTES.toMillis(1), MINUTES.toMillis(2), MINUTES.toMillis(5), MINUTES.toMillis(10), - MINUTES.toMillis(15), MINUTES.toMillis(30), HOURS.toMillis(1), HOURS.toMillis(2), HOURS.toMillis(5), - HOURS.toMillis(10), HOURS.toMillis(12), DAYS.toMillis(1), DAYS.toMillis(2), DAYS.toMillis(5), - DAYS.toMillis(7)); - - for (final Long step : steps) { - if (msPerLabel < step) { - return step; - } - } - - return msPerLabel; - } - - private String msToTic(final long ms, final double msPerLabel) { - - if (ms < 1000) { - return ms + "ms"; - } else if (ms < MINUTES.toMillis(1)) { - if (msPerLabel % 1000 == 0) { - return String.format("%ds", ms / 1_000); - } else { - return String.format("%.1fs", ms / 1_000.0); - } - } else if (ms < TimeUnit.HOURS.toMillis(1)) { - - final long sec = (ms % MINUTES.toMillis(1)) / SECONDS.toMillis(1); - final long min = ms / MINUTES.toMillis(1); - if (msPerLabel % MINUTES.toMillis(1) == 0) { - return min + "m "; - } else { - return min + "m " + sec + "s"; - } - } else if (ms < DAYS.toMillis(1)) { - // ms is a multiple of 1 hour, see roundToLinearLabelSteps - final long hour = (ms % DAYS.toMillis(1)) / HOURS.toMillis(1); - final long min = (ms % HOURS.toMillis(1)) / MINUTES.toMillis(1); - final long sec = (ms % MINUTES.toMillis(1)) / SECONDS.toMillis(1); - - if (msPerLabel % MINUTES.toMillis(1) == 0) { - return hour + "h " + min + "m "; - } else if (msPerLabel % HOURS.toMillis(1) == 0) { - return hour + "h "; - } else { - return hour + "h " + min + "m " + sec + "s"; - } - } else { - // ms is a multiple of 1 day, see roundToLinearLabelSteps - final long day = ms / DAYS.toMillis(1); - final long hour = (ms % DAYS.toMillis(1)) / HOURS.toMillis(1); - - return day + "d " + hour + "h "; - } - } + } diff --git a/pdb-plotting/src/main/java/org/lucares/recommind/logs/YAxisTicks.java b/pdb-plotting/src/main/java/org/lucares/recommind/logs/YAxisTicks.java new file mode 100644 index 0000000..edc2aad --- /dev/null +++ b/pdb-plotting/src/main/java/org/lucares/recommind/logs/YAxisTicks.java @@ -0,0 +1,166 @@ +package org.lucares.recommind.logs; + +import static java.util.concurrent.TimeUnit.DAYS; +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; + +class YAxisTicks { + + static final int TICKS_FONT_SIZE = 12; + + public static String computeYTicks(final GnuplotSettings settings, final Collection dataSeries) { + String result = ""; + + final long yRangeMax; + final long yRangeMin; + if (settings.hasYRange()) { + yRangeMax = settings.getYRangeMax(); + yRangeMin = settings.getYRangeMin(); + } else { + yRangeMax = DataSeries.maxValue(dataSeries); + yRangeMin = 0; + } + final int height = settings.getHeight(); + + switch (settings.getYAxisScale()) { + case LINEAR: + result = computeLinearYTicks(height, yRangeMin, yRangeMax); + break; + case LOG10: + result = computeLog10YTicks(height, yRangeMin, yRangeMax); + break; + default: + // use the default + } + return result; +} + +private static String computeLog10YTicks(final int height, final long yRangeMin, final long yRangeMax) { + final StringBuilder result = new StringBuilder(); + result.append("set ylabel \"Duration\"\n"); + + final List ticsLabels = Arrays.asList(// + "\"1ms\" 1", // + "\"2ms\" 2", // + "\"5ms\" 5", // + "\"10ms\" 10", // + "\"20ms\" 20", // + "\"50ms\" 50", // + "\"100ms\" 100", // + "\"200ms\" 200", // + "\"500ms\" 500", // + "\"1s\" 1000", // + "\"2s\" 2000", // + "\"5s\" 5000", // + "\"10s\" 10000", // + "\"30s\" 30000", // + "\"1m\" 60000", // + "\"2m\" 120000", // + "\"5m\" 300000", // + "\"10m\" 600000", // + "\"30m\" 1800000", // + "\"1h\" 3600000", // + "\"2h\" 7200000", // + "\"4h\" 14400000", // + "\"8h\" 28800000", // + "\"16h\" 57600000", // + "\"1d\" 86400000", // + "\"2d\" 172800000", // + "\"1 week\" 604800000", // + "\"2 week\" 1209600000.0", // + "\"4 week\" 2419200000.0" // + ); + + result.append("set ytics ("); + result.append(String.join(", ", ticsLabels)); + result.append(")\n"); + + return result.toString(); +} + +private static String computeLinearYTicks(final long height, final long yRangeMin, final long yRangeMax) { + final StringBuilder result = new StringBuilder(); + result.append("set ylabel \"Duration\"\n"); + + final long plotHeight = height - GnuplotSettings.GNUPLOT_TOP_BOTTOM_MARGIN; // sum of top/bottom margin, see + // marker (1) + final long maxLabels = plotHeight / (TICKS_FONT_SIZE * 5); + + final long range = yRangeMax - yRangeMin; + final long msPerLabel = roundToLinearLabelSteps(range / maxLabels); + + final List ticsLabels = new ArrayList<>(); + for (long i = yRangeMin; i <= yRangeMax; i += msPerLabel) { + ticsLabels.add("\"" + msToTic(i, msPerLabel) + "\" " + i); + } + + result.append("set ytics ("); + result.append(String.join(", ", ticsLabels)); + result.append(")\n"); + return result.toString(); +} + +private static long roundToLinearLabelSteps(final long msPerLabel) { + final List steps = Arrays.asList(2L, 5L, 10L, 20L, 50L, 100L, 200L, 500L, 1000L, 2000L, 5000L, 10_000L, + 20_000L, MINUTES.toMillis(1), MINUTES.toMillis(2), MINUTES.toMillis(5), MINUTES.toMillis(10), + MINUTES.toMillis(15), MINUTES.toMillis(30), HOURS.toMillis(1), HOURS.toMillis(2), HOURS.toMillis(5), + HOURS.toMillis(10), HOURS.toMillis(12), DAYS.toMillis(1), DAYS.toMillis(2), DAYS.toMillis(5), + DAYS.toMillis(7)); + + for (final Long step : steps) { + if (msPerLabel < step) { + return step; + } + } + + return msPerLabel; +} + +private static String msToTic(final long ms, final double msPerLabel) { + + if (ms < 1000) { + return ms + "ms"; + } else if (ms < MINUTES.toMillis(1)) { + if (msPerLabel % 1000 == 0) { + return String.format("%ds", ms / 1_000); + } else { + return String.format("%.1fs", ms / 1_000.0); + } + } else if (ms < TimeUnit.HOURS.toMillis(1)) { + + final long sec = (ms % MINUTES.toMillis(1)) / SECONDS.toMillis(1); + final long min = ms / MINUTES.toMillis(1); + if (msPerLabel % MINUTES.toMillis(1) == 0) { + return min + "m "; + } else { + return min + "m " + sec + "s"; + } + } else if (ms < DAYS.toMillis(1)) { + // ms is a multiple of 1 hour, see roundToLinearLabelSteps + final long hour = (ms % DAYS.toMillis(1)) / HOURS.toMillis(1); + final long min = (ms % HOURS.toMillis(1)) / MINUTES.toMillis(1); + final long sec = (ms % MINUTES.toMillis(1)) / SECONDS.toMillis(1); + + if (msPerLabel % MINUTES.toMillis(1) == 0) { + return hour + "h " + min + "m "; + } else if (msPerLabel % HOURS.toMillis(1) == 0) { + return hour + "h "; + } else { + return hour + "h " + min + "m " + sec + "s"; + } + } else { + // ms is a multiple of 1 day, see roundToLinearLabelSteps + final long day = ms / DAYS.toMillis(1); + final long hour = (ms % DAYS.toMillis(1)) / HOURS.toMillis(1); + + return day + "d " + hour + "h "; + } +} +}