diff --git a/pdb-js/src/app/app.module.ts b/pdb-js/src/app/app.module.ts
index bec94db..b3be74c 100644
--- a/pdb-js/src/app/app.module.ts
+++ b/pdb-js/src/app/app.module.ts
@@ -19,6 +19,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import {MatProgressBarModule} from '@angular/material/progress-bar';
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
+import {MatRadioModule} from '@angular/material/radio';
import {MatSnackBarModule} from '@angular/material/snack-bar';
import {MatTooltipModule} from '@angular/material/tooltip';
import { YAxisDefinitionComponent } from './y-axis-definition/y-axis-definition.component';
@@ -56,6 +57,7 @@ import { ImageToggleComponent } from './image-toggle/image-toggle.component';
MatCheckboxModule,
MatFormFieldModule,
MatInputModule,
+ MatRadioModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatSelectModule,
diff --git a/pdb-js/src/app/plot-details/plot-details.component.html b/pdb-js/src/app/plot-details/plot-details.component.html
index d41dfb0..e8ee5c6 100644
--- a/pdb-js/src/app/plot-details/plot-details.component.html
+++ b/pdb-js/src/app/plot-details/plot-details.component.html
@@ -1,28 +1,59 @@
+
+ Time
+ Numbers
+
+
| Name |
Type |
Values |
Avg |
+ {{label}} |
+ Max |
| {{ stat.name }} |
|
{{ stat.values }} |
- {{ utils.formatMs(stat.average) }} |
+ {{ utils.format(stat.average, valueFormat) }} |
+ {{utils.format(stat.percentiles[percentilesToPlot.get(key)], valueFormat)}} |
+ {{ utils.format(stat.maxValue, valueFormat)}} |
-
-
- |
-
-
- |
-
-
- |
-
- {{ utils.toPercent(statsRow.average / statsCol.average) }}
- |
-
-
\ No newline at end of file
+ 1">
+
Compare Averages
+
+
+ |
+
+
+ |
+
+
+ |
+
+ {{ utils.toPercent(statsRow.average / statsCol.average) }}
+ |
+
+
+
+
Compare Percentiles
+
+
{{p}} percentile
+
+
+ |
+
+
+ |
+
+
+ |
+
+ {{ utils.toPercent(statsRow.percentiles[percentilesToPlot.get(p)] / statsCol.percentiles[percentilesToPlot.get(p)]) }}
+ |
+
+
+
+
\ No newline at end of file
diff --git a/pdb-js/src/app/plot-details/plot-details.component.scss b/pdb-js/src/app/plot-details/plot-details.component.scss
index 86a0545..25d86f2 100644
--- a/pdb-js/src/app/plot-details/plot-details.component.scss
+++ b/pdb-js/src/app/plot-details/plot-details.component.scss
@@ -27,4 +27,9 @@
.plot-details-plotType_e6e600 {background-position-y: -32px;}
.plot-details-plotType_e51e10 {background-position-y: -40px;}
.plot-details-plotType_57a1c2 {background-position-y: -48px;}
-.plot-details-plotType_bd36c2 {background-position-y: -56px;}
\ No newline at end of file
+.plot-details-plotType_bd36c2 {background-position-y: -56px;}
+
+
+.gallery-item-details td {
+ white-space: pre;
+}
\ No newline at end of file
diff --git a/pdb-js/src/app/plot-details/plot-details.component.ts b/pdb-js/src/app/plot-details/plot-details.component.ts
index 9ebdfc9..4c18ca1 100644
--- a/pdb-js/src/app/plot-details/plot-details.component.ts
+++ b/pdb-js/src/app/plot-details/plot-details.component.ts
@@ -12,10 +12,38 @@ export class PlotDetailsComponent {
@Input()
stats: PlotResponseStats;
+ hasPercentiles = false;
+
+ valueFormat = "time";
+
+ percentilesToPlot : Map = new Map();
+
constructor(public utils: UtilService){
}
+ ngOnInit() {
+ this.hasPercentiles = false;
+ this.percentilesToPlot.clear();
+ for (let i = 0; i < this.stats.dataSeriesStats.length; i++)
+ {
+ const stat = this.stats.dataSeriesStats[i];
+ if (stat.percentiles.hasOwnProperty("50.000"))
+ {
+ this.hasPercentiles = true;
+ this.percentilesToPlot.set('median','50.000');
+ this.percentilesToPlot.set('75th','75.000');
+ this.percentilesToPlot.set('95th','95.000');
+ this.percentilesToPlot.set('99th','99.000');
+ break;
+ }
+ }
+ }
+
+ percentile(value: number): string {
+ return this.utils.format(value, this.valueFormat);
+ }
+
pointTypeClass(typeAndColor: DashTypeAndColor): string {
return "plot-details-plotType"
+" plot-details-plotType_"+typeAndColor.pointType
diff --git a/pdb-js/src/app/plot-view/plot-view.component.scss b/pdb-js/src/app/plot-view/plot-view.component.scss
index 69ce25c..9f76637 100644
--- a/pdb-js/src/app/plot-view/plot-view.component.scss
+++ b/pdb-js/src/app/plot-view/plot-view.component.scss
@@ -19,4 +19,5 @@ img {
bottom: 5px;
background-color: white;
box-shadow: 5px 5px 10px 0px #e0e0e0;
+ overflow: auto;
}
\ No newline at end of file
diff --git a/pdb-js/src/app/plot.service.ts b/pdb-js/src/app/plot.service.ts
index 4d27932..0ed1d90 100644
--- a/pdb-js/src/app/plot.service.ts
+++ b/pdb-js/src/app/plot.service.ts
@@ -249,6 +249,7 @@ export class DataSeriesStats {
average : number;
plottedValues : number;
dashTypeAndColor: DashTypeAndColor;
+ percentiles: Map
}
export class DashTypeAndColor {
diff --git a/pdb-js/src/app/utils.service.ts b/pdb-js/src/app/utils.service.ts
index b22d184..34622a3 100644
--- a/pdb-js/src/app/utils.service.ts
+++ b/pdb-js/src/app/utils.service.ts
@@ -9,6 +9,14 @@ export class UtilService {
constructor() {
}
+ format(value: number, type: string) {
+ if (type == "time"){
+ return this.formatMs(value);
+ } else {
+ return ""+value;
+ }
+ }
+
formatMs(valueInMs):string {
const ms = Math.floor(valueInMs % 1000);
const s = Math.floor((valueInMs / 1000) % 60);
diff --git a/pdb-js/src/app/visualization-page/visualization-page.component.scss b/pdb-js/src/app/visualization-page/visualization-page.component.scss
index 09fc714..f205929 100644
--- a/pdb-js/src/app/visualization-page/visualization-page.component.scss
+++ b/pdb-js/src/app/visualization-page/visualization-page.component.scss
@@ -48,6 +48,7 @@
#filters {
grid-area: filters;
+ overflow: auto;
}
#filterpanel {
background-color: #f8f8f8;/*#fafafa;*/
diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/AggregatorCollection.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/AggregatorCollection.java
index 82c850e..ac9e0b5 100644
--- a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/AggregatorCollection.java
+++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/AggregatorCollection.java
@@ -3,6 +3,7 @@ package org.lucares.pdb.plot.api;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import org.lucares.pdb.api.Tags;
@@ -27,4 +28,15 @@ public class AggregatorCollection {
return Optional.ofNullable(aggregators.get(type));
}
+ @SuppressWarnings("unchecked")
+ public Optional getAggregator(final Class aggregatorType) {
+
+ for (final CustomAggregator aggregator : aggregators.values()) {
+ if (Objects.equals(aggregator.getClass(), aggregatorType)) {
+ return Optional.of((T) aggregator);
+ }
+ }
+
+ return Optional.empty();
+ }
}
diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/CumulativeDistributionCustomAggregator.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/CumulativeDistributionCustomAggregator.java
index 66a92b7..ac15c40 100644
--- a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/CumulativeDistributionCustomAggregator.java
+++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/CumulativeDistributionCustomAggregator.java
@@ -8,7 +8,7 @@ import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
-import java.util.LinkedHashMap;
+import java.util.Locale;
import org.lucares.collections.LongLongConsumer;
import org.lucares.collections.LongLongHashMap;
@@ -24,7 +24,7 @@ public class CumulativeDistributionCustomAggregator implements CustomAggregator
private long maxValue = 0;
- private final LinkedHashMap percentiles = new LinkedHashMap<>(POINTS);
+ private final Percentiles percentiles = new Percentiles(POINTS);
private final double stepSize;
@@ -49,7 +49,8 @@ public class CumulativeDistributionCustomAggregator implements CustomAggregator
if (newPercentile >= nextPercentile) {
double currentPercentile = lastPercentile + stepSize;
while (currentPercentile <= newPercentile) {
- percentiles.put(currentPercentile, duration);
+ final String percentile = String.format(Locale.US, "%.3f", currentPercentile);
+ percentiles.put(percentile, duration);
currentPercentile += stepSize;
}
nextPercentile = currentPercentile;
@@ -61,10 +62,15 @@ public class CumulativeDistributionCustomAggregator implements CustomAggregator
return maxValue;
}
- public LinkedHashMap getPercentiles() {
+ public Percentiles getPercentiles() {
return percentiles;
}
+ public void collect(final LongLongHashMap map) {
+ map.forEachOrdered(this);
+ percentiles.put("100.000", maxValue);
+ }
+
}
// the rather large initial capacity should prevent too many grow&re-hash phases
@@ -84,14 +90,27 @@ public class CumulativeDistributionCustomAggregator implements CustomAggregator
totalValues++;
}
+ public Percentiles getPercentiles() {
+ final long start = System.nanoTime();
+
+ final ToPercentiles toPercentiles = new ToPercentiles(totalValues);
+ toPercentiles.collect(map);
+
+ final Percentiles result = toPercentiles.getPercentiles();
+ System.out.println("getPercentiles took: " + (System.nanoTime() - start) / 1_000_000.0 + " ms");
+ return result;
+ }
+
@Override
public AggregatedData getAggregatedData() {
try {
final char separator = ',';
final char newline = '\n';
+ final long start = System.nanoTime();
final ToPercentiles toPercentiles = new ToPercentiles(totalValues);
- map.forEachOrdered(toPercentiles);
+ toPercentiles.collect(map);
+ System.out.println("getAggregated took: " + (System.nanoTime() - start) / 1_000_000.0 + " ms");
final File dataFile = File.createTempFile("data", ".dat", tmpDir.toFile());
try (final Writer output = new BufferedWriter(
@@ -107,12 +126,6 @@ public class CumulativeDistributionCustomAggregator implements CustomAggregator
data.append(value);
data.append(newline);
});
-
- final long maxValue = toPercentiles.getMaxValue();
- data.append(100);
- data.append(separator);
- data.append(maxValue);
- data.append(newline);
}
output.write(data.toString());
diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/Percentiles.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/Percentiles.java
new file mode 100644
index 0000000..53e39ac
--- /dev/null
+++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/Percentiles.java
@@ -0,0 +1,32 @@
+package org.lucares.pdb.plot.api;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Maps percentiles to their value. E.g.
+ *
+ *
+ * {"50.00": 123, "75.00": 567}
+ *
+ *
+ * This class uses Strings for the precentiles instead of doubles, because
+ * doubles are bad keys for maps.
+ */
+public class Percentiles extends LinkedHashMap {
+
+ private static final long serialVersionUID = 4957667781086113971L;
+
+ public Percentiles() {
+ super(0);
+ }
+
+ public Percentiles(final int initialSize) {
+ super(initialSize);
+ }
+
+ public Percentiles(final Map percentiles) {
+ super(percentiles.size());
+ putAll(percentiles);
+ }
+}
diff --git a/pdb-plotting/src/main/java/org/lucares/recommind/logs/DataSeries.java b/pdb-plotting/src/main/java/org/lucares/recommind/logs/DataSeries.java
index 0c9ddb3..e849872 100644
--- a/pdb-plotting/src/main/java/org/lucares/recommind/logs/DataSeries.java
+++ b/pdb-plotting/src/main/java/org/lucares/recommind/logs/DataSeries.java
@@ -8,6 +8,7 @@ import java.util.Map;
import org.lucares.pdb.plot.api.AggregatorCollection;
import org.lucares.pdb.plot.api.Limit;
+import org.lucares.pdb.plot.api.Percentiles;
public interface DataSeries {
public static final Comparator super DataSeries> BY_NUMBER_OF_VALUES = (a, b) -> {
@@ -35,6 +36,8 @@ public interface DataSeries {
public double getAverage();
+ public Percentiles getPercentiles();
+
public void setStyle(LineStyle style);
public LineStyle getStyle();
@@ -114,5 +117,4 @@ public interface DataSeries {
return result;
}
-
}
diff --git a/pdb-plotting/src/main/java/org/lucares/recommind/logs/FileBackedDataSeries.java b/pdb-plotting/src/main/java/org/lucares/recommind/logs/FileBackedDataSeries.java
index f9d56f3..046aed1 100644
--- a/pdb-plotting/src/main/java/org/lucares/recommind/logs/FileBackedDataSeries.java
+++ b/pdb-plotting/src/main/java/org/lucares/recommind/logs/FileBackedDataSeries.java
@@ -1,6 +1,8 @@
package org.lucares.recommind.logs;
import org.lucares.pdb.plot.api.AggregatorCollection;
+import org.lucares.pdb.plot.api.CumulativeDistributionCustomAggregator;
+import org.lucares.pdb.plot.api.Percentiles;
public class FileBackedDataSeries implements DataSeries {
@@ -55,11 +57,19 @@ public class FileBackedDataSeries implements DataSeries {
@Override
public double getAverage() {
- return csvSummary.getStatsAverage();
+ return Math.round(csvSummary.getStatsAverage() * 10.0) / 10.0;
}
@Override
public AggregatorCollection getAggregators() {
return csvSummary.getAggregators();
}
+
+ @Override
+ public Percentiles getPercentiles() {
+ return csvSummary.getAggregators()//
+ .getAggregator(CumulativeDistributionCustomAggregator.class)//
+ .map(CumulativeDistributionCustomAggregator::getPercentiles)//
+ .orElse(new Percentiles());
+ }
}
diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/domain/DataSeriesStats.java b/pdb-ui/src/main/java/org/lucares/pdbui/domain/DataSeriesStats.java
index 9f38e95..9e1061b 100644
--- a/pdb-ui/src/main/java/org/lucares/pdbui/domain/DataSeriesStats.java
+++ b/pdb-ui/src/main/java/org/lucares/pdbui/domain/DataSeriesStats.java
@@ -2,74 +2,82 @@ package org.lucares.pdbui.domain;
import java.util.Collection;
+import org.lucares.pdb.plot.api.Percentiles;
+
public class DataSeriesStats {
- private final int values;
- private final long maxValue;
- private final double average;
- private final String name;
- private final StyleAndColor dashTypeAndColor;
+ private final int values;
+ private final long maxValue;
+ private final double average;
+ private final String name;
+ private final StyleAndColor dashTypeAndColor;
+ private Percentiles percentiles;
- public DataSeriesStats(final int values, final long maxValue, final double average) {
- this.name = "";
- this.dashTypeAndColor = new StyleAndColor("000", 0);
- this.values = values;
- this.maxValue = maxValue;
- this.average = average;
+ public DataSeriesStats(final int values, final long maxValue, final double average) {
+ this.name = "";
+ this.dashTypeAndColor = new StyleAndColor("000", 0);
+ this.values = values;
+ this.maxValue = maxValue;
+ this.average = average;
+ }
+
+ public DataSeriesStats(final String name, final StyleAndColor dashTypeAndColor, final int values, final long maxValue,
+ final double average, final Percentiles percentiles) {
+ this.name = name;
+ this.dashTypeAndColor = dashTypeAndColor;
+ this.values = values;
+ this.maxValue = maxValue;
+ this.average = average;
+ this.percentiles = percentiles;
+ }
+
+ /**
+ * The number of values in the date range, without applying the y-range.
+ *
+ * @return total number of values
+ */
+ public int getValues() {
+ return values;
+ }
+
+ public StyleAndColor getDashTypeAndColor() {
+ return dashTypeAndColor;
+ }
+
+ public long getMaxValue() {
+ return maxValue;
+ }
+
+ public double getAverage() {
+ return average;
+ }
+
+ public Percentiles getPercentiles() {
+ return percentiles;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return "[name=" + name + ", dashTypeAndColor=" + dashTypeAndColor + ", values=" + values + ", maxValue=" + maxValue
+ + ", average=" + average + "]";
+ }
+
+ public static double average(final Collection stats) {
+ long n = 0;
+ double average = 0;
+
+ for (final DataSeriesStats stat : stats) {
+ final int newValues = stat.getValues();
+ final double newAverage = stat.getAverage();
+ if (newValues > 0) {
+ average = (average * n + newAverage * newValues) / (n + newValues);
+ n += newValues;
+ }
}
- public DataSeriesStats(final String name, final StyleAndColor dashTypeAndColor, final int values,
- final long maxValue, final double average) {
- this.name = name;
- this.dashTypeAndColor = dashTypeAndColor;
- this.values = values;
- this.maxValue = maxValue;
- this.average = average;
- }
-
- /**
- * The number of values in the date range, without applying the y-range.
- *
- * @return total number of values
- */
- public int getValues() {
- return values;
- }
-
- public StyleAndColor getDashTypeAndColor() {
- return dashTypeAndColor;
- }
-
- public long getMaxValue() {
- return maxValue;
- }
-
- public double getAverage() {
- return average;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public String toString() {
- return "[name=" + name + ", dashTypeAndColor=" + dashTypeAndColor + ", values=" + values + ", maxValue="
- + maxValue + ", average=" + average + "]";
- }
-
- public static double average(final Collection stats) {
- long n = 0;
- double average = 0;
-
- for (final DataSeriesStats stat : stats) {
- final int newValues = stat.getValues();
- final double newAverage = stat.getAverage();
- if (newValues > 0) {
- average = (average * n + newAverage * newValues) / (n + newValues);
- n += newValues;
- }
- }
-
- return average;
- }
+ return average;
+ }
}
diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/domain/PlotResponseStats.java b/pdb-ui/src/main/java/org/lucares/pdbui/domain/PlotResponseStats.java
index ee59781..caa73a3 100644
--- a/pdb-ui/src/main/java/org/lucares/pdbui/domain/PlotResponseStats.java
+++ b/pdb-ui/src/main/java/org/lucares/pdbui/domain/PlotResponseStats.java
@@ -6,84 +6,84 @@ import java.util.List;
import org.lucares.recommind.logs.DataSeries;
public class PlotResponseStats {
- private long maxValue;
+ private long maxValue;
- private int values;
+ private int values;
- private double average;
+ private double average;
- private List dataSeriesStats;
+ private List dataSeriesStats;
- public PlotResponseStats() {
- super();
+ public PlotResponseStats() {
+ super();
+ }
+
+ public PlotResponseStats(final long maxValue, final int values, final double average,
+ final List dataSeriesStats) {
+
+ this.maxValue = maxValue;
+ this.values = values;
+ this.average = average;
+ this.dataSeriesStats = dataSeriesStats;
+ }
+
+ public long getMaxValue() {
+ return maxValue;
+ }
+
+ public void setMaxValue(final long maxValue) {
+ this.maxValue = maxValue;
+ }
+
+ public int getValues() {
+ return values;
+ }
+
+ public void setValues(final int values) {
+ this.values = values;
+ }
+
+ public double getAverage() {
+ return average;
+ }
+
+ public void setAverage(final double average) {
+ this.average = average;
+ }
+
+ public List getDataSeriesStats() {
+ return dataSeriesStats;
+ }
+
+ public void setDataSeriesStats(final List dataSeriesStats) {
+ this.dataSeriesStats = dataSeriesStats;
+ }
+
+ @Override
+ public String toString() {
+ return "PlotResponseStats [maxValue=" + maxValue + ", values=" + values + ", average=" + average
+ + ", dataSeriesStats=" + dataSeriesStats + "]";
+ }
+
+ public static PlotResponseStats fromDataSeries(final List dataSeries) {
+
+ int values = 0;
+ long maxValue = 0;
+ final List dataSeriesStats = new ArrayList<>();
+
+ for (final DataSeries dataSerie : dataSeries) {
+ values += dataSerie.getValues();
+ maxValue = Math.max(maxValue, dataSerie.getMaxValue());
+
+ final StyleAndColor lineStyle = new StyleAndColor(dataSerie.getStyle().getColor().getColor(),
+ dataSerie.getStyle().getPointType());
+
+ dataSeriesStats.add(new DataSeriesStats(dataSerie.getTitle(), lineStyle, dataSerie.getValues(),
+ dataSerie.getMaxValue(), dataSerie.getAverage(), dataSerie.getPercentiles()));
}
- public PlotResponseStats(final long maxValue, final int values, final double average,
- final List dataSeriesStats) {
+ final double average = Math.round(DataSeriesStats.average(dataSeriesStats));
- this.maxValue = maxValue;
- this.values = values;
- this.average = average;
- this.dataSeriesStats = dataSeriesStats;
- }
-
- public long getMaxValue() {
- return maxValue;
- }
-
- public void setMaxValue(final long maxValue) {
- this.maxValue = maxValue;
- }
-
- public int getValues() {
- return values;
- }
-
- public void setValues(final int values) {
- this.values = values;
- }
-
- public double getAverage() {
- return average;
- }
-
- public void setAverage(final double average) {
- this.average = average;
- }
-
- public List getDataSeriesStats() {
- return dataSeriesStats;
- }
-
- public void setDataSeriesStats(final List dataSeriesStats) {
- this.dataSeriesStats = dataSeriesStats;
- }
-
- @Override
- public String toString() {
- return "PlotResponseStats [maxValue=" + maxValue + ", values=" + values + ", average=" + average
- + ", dataSeriesStats=" + dataSeriesStats + "]";
- }
-
- public static PlotResponseStats fromDataSeries(final List dataSeries) {
-
- int values = 0;
- long maxValue = 0;
- final List dataSeriesStats = new ArrayList<>();
-
- for (final DataSeries dataSerie : dataSeries) {
- values += dataSerie.getValues();
- maxValue = Math.max(maxValue, dataSerie.getMaxValue());
-
- final StyleAndColor lineStyle = new StyleAndColor(dataSerie.getStyle().getColor().getColor(),
- dataSerie.getStyle().getPointType());
-
- dataSeriesStats.add(new DataSeriesStats(dataSerie.getTitle(), lineStyle, dataSerie.getValues(),
- dataSerie.getMaxValue(), dataSerie.getAverage()));
- }
-
- final double average = Math.round(DataSeriesStats.average(dataSeriesStats));
-
- return new PlotResponseStats(maxValue, values, average, dataSeriesStats);
- }
+ return new PlotResponseStats(maxValue, values, average, dataSeriesStats);
+ }
}