put y axis definition into its own object

This commit is contained in:
2020-02-09 17:16:27 +01:00
parent ed7cc9bee5
commit 859491e99e
28 changed files with 268 additions and 324 deletions

View File

@@ -208,9 +208,9 @@ export class PlotRequest {
export class YAxisDefinition { export class YAxisDefinition {
axisScale : string; axisScale : string;
yRangeMin : number; rangeMin : number;
yRangeMax : number; rangeMax : number;
yRangeUnit : string; rangeUnit : string;
} }
export class PlotResponse { export class PlotResponse {

View File

@@ -34,7 +34,8 @@
<pdb-limit-by #limitbycomponent></pdb-limit-by> <pdb-limit-by #limitbycomponent></pdb-limit-by>
<pdb-y-axis-definition #yAxisDefinitionComponent></pdb-y-axis-definition> <pdb-y-axis-definition #y1AxisDefinitionComponent yIndex="1"></pdb-y-axis-definition>
<mat-checkbox [(ngModel)]="enableGallery">Gallery</mat-checkbox> <mat-checkbox [(ngModel)]="enableGallery">Gallery</mat-checkbox>
@@ -77,7 +78,8 @@
#plotView #plotView
(zoomRange)="zoomRange($event)" (zoomRange)="zoomRange($event)"
(zoomWithDateAnchor)="zoomWithDateAnchor($event)"></pdb-plot-view> (zoomWithDateAnchor)="zoomWithDateAnchor($event)"></pdb-plot-view>
<pdb-gallery-view> <pdb-gallery-view
#galleryView>
</pdb-gallery-view> </pdb-gallery-view>
</div> </div>

View File

@@ -28,19 +28,23 @@ export class VisualizationPageComponent implements OnInit {
groupBy = new Array<TagField>(); groupBy = new Array<TagField>();
@ViewChild(LimitByComponent, {static: false}) @ViewChild('limitbycomponent', {static: false})
private limitbycomponent : LimitByComponent; private limitbycomponent : LimitByComponent;
@ViewChild(YAxisDefinitionComponent, {static: false})
private yAxisDefinitionComponent : YAxisDefinitionComponent;
@ViewChild(QueryAutocompleteComponent, {static: false}) @ViewChild('y1AxisDefinitionComponent', {static: false, read: YAxisDefinitionComponent})
private y1AxisDefinitionComponent : YAxisDefinitionComponent;
@ViewChild('y2AxisDefinitionComponent', {static: false, read: YAxisDefinitionComponent})
private y2AxisDefinitionComponent : YAxisDefinitionComponent;
@ViewChild('query', {static: false})
query: QueryAutocompleteComponent; query: QueryAutocompleteComponent;
@ViewChild(PlotViewComponent, {static: false}) @ViewChild('plotView', {static: false})
plotView: PlotViewComponent; plotView: PlotViewComponent;
@ViewChild(GalleryViewComponent, {static: false}) @ViewChild('galleryView', {static: false})
galleryView: GalleryViewComponent; galleryView: GalleryViewComponent;
enableGallery = false; enableGallery = false;
@@ -139,11 +143,8 @@ export class VisualizationPageComponent implements OnInit {
const aggregates = []; const aggregates = [];
this.selectedPlotType.forEach(a => aggregates.push(a.id)); this.selectedPlotType.forEach(a => aggregates.push(a.id));
const y1 = new YAxisDefinition(); const y1 = this.y1AxisDefinitionComponent.getAxisDefinition();
y1.axisScale = this.yAxisDefinitionComponent.yAxisScale; const y2 = this.y2AxisDefinitionComponent.getAxisDefinition();
y1.yRangeMin = this.yAxisDefinitionComponent.minYValue;
y1.yRangeMax = this.yAxisDefinitionComponent.maxYValue;
y1.yRangeUnit = this.yAxisDefinitionComponent.yAxisUnit;
const request = new PlotRequest(); const request = new PlotRequest();
request.query = this.query.query; request.query = this.query.query;
@@ -153,6 +154,7 @@ export class VisualizationPageComponent implements OnInit {
request.limitBy = this.limitbycomponent.limitBy; request.limitBy = this.limitbycomponent.limitBy;
request.limit = this.limitbycomponent.limit; request.limit = this.limitbycomponent.limit;
request.y1 = y1; request.y1 = y1;
request.y2 = y2;
request.dateRange = this.dateRangeAsString(); request.dateRange = this.dateRangeAsString();
request.aggregates = aggregates; request.aggregates = aggregates;
request.keyOutside = false; request.keyOutside = false;

View File

@@ -1,7 +1,6 @@
<div> <div>
<mat-form-field> <mat-form-field>
<mat-label>Y-Axis:</mat-label> <mat-label>Y{{yIndex}}-Axis:</mat-label>
<mat-select [(value)]="yAxisScale"> <mat-select [(value)]="yAxisScale">
<mat-option value="LOG10">Logarithm</mat-option> <mat-option value="LOG10">Logarithm</mat-option>
<mat-option value="LINEAR">Linear</mat-option> <mat-option value="LINEAR">Linear</mat-option>
@@ -9,7 +8,7 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="pdb-form-mid"> <mat-form-field class="pdb-form-mid">
<mat-label>Y-Axis Range:</mat-label> <mat-label>Y{{yIndex}}-Axis Range:</mat-label>
<mat-select [(value)]="yAxisUnit"> <mat-select [(value)]="yAxisUnit">
<mat-option value="AUTOMATIC">automatic</mat-option> <mat-option value="AUTOMATIC">automatic</mat-option>
<mat-option value="MILLISECONDS">millis</mat-option> <mat-option value="MILLISECONDS">millis</mat-option>

View File

@@ -1,4 +1,5 @@
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { YAxisDefinition } from '../plot.service';
@Component({ @Component({
selector: 'pdb-y-axis-definition', selector: 'pdb-y-axis-definition',
@@ -7,12 +8,23 @@ import { Component, Input } from '@angular/core';
}) })
export class YAxisDefinitionComponent { export class YAxisDefinitionComponent {
yAxisScale: string = "LOG10"; yAxisScale: string = "LOG10";
yAxisUnit: string = "SECONDS"; yAxisUnit: string = "SECONDS";
minYValue: number = 0; minYValue: number = 0;
maxYValue: number = 300; maxYValue: number = 300;
@Input()
yIndex: string = "";
constructor() { constructor() {
} }
getAxisDefinition() {
const result = new YAxisDefinition();
result.axisScale = this.yAxisScale;
result.rangeMin = this.minYValue;
result.rangeMax = this.maxYValue;
result.rangeUnit = this.yAxisUnit;
return result;
}
} }

View File

@@ -17,9 +17,9 @@ public class AggregatorCollection {
} }
} }
public void addValue(final Tags groupedBy, final boolean valueIsInYRange, final long epochMilli, final long value) { public void addValue(final Tags groupedBy, final long epochMilli, final long value) {
for (final CustomAggregator aggregator : aggregators.values()) { for (final CustomAggregator aggregator : aggregators.values()) {
aggregator.addValue(valueIsInYRange, epochMilli, value); aggregator.addValue(epochMilli, value);
} }
} }

View File

@@ -42,7 +42,7 @@ public class BarChartAggregator implements CustomAggregator, IndexedAggregator {
} }
@Override @Override
public void addValue(final boolean valueIsInYRange, final long epochMilli, final long value) { public void addValue(final long epochMilli, final long value) {
count++; count++;
} }

View File

@@ -58,13 +58,16 @@ public class BarChartHandler extends AggregateHandler {
@Override @Override
AxisSettings createYAxisSettings(final GnuplotSettings settings, final Collection<DataSeries> dataSeries) { AxisSettings createYAxisSettings(final GnuplotSettings settings, final Collection<DataSeries> dataSeries) {
final GnuplotAxis yAxis = getyAxis();
final AxisSettings result = new AxisSettings(); final AxisSettings result = new AxisSettings();
result.setLabel("Count"); result.setLabel("Count");
result.setType(Type.Number); result.setType(Type.Number);
result.setAxis(getyAxis()); result.setAxis(yAxis);
result.setTicsEnabled(true); result.setTicsEnabled(true);
result.setFrom("0"); result.setFrom("0");
result.setLogscale(settings.getYAxisScale() == AxisScale.LOG10); result.setLogscale(settings.getYAxisDefinition(yAxis).isLogscale());
return result; return result;
} }

View File

@@ -79,7 +79,7 @@ public class CumulativeDistributionCustomAggregator implements CustomAggregator
} }
@Override @Override
public void addValue(final boolean valueIsInYRange, final long epochMilli, final long value) { public void addValue(final long epochMilli, final long value) {
map.compute(value, 0, l -> l + 1); map.compute(value, 0, l -> l + 1);
totalValues++; totalValues++;
} }

View File

@@ -2,7 +2,7 @@ package org.lucares.pdb.plot.api;
public interface CustomAggregator { public interface CustomAggregator {
void addValue(boolean valueIsInYRange, long epochMilli, long value); void addValue(long epochMilli, long value);
AggregatedData getAggregatedData(); AggregatedData getAggregatedData();

View File

@@ -51,7 +51,7 @@ public class HistogramAggregator implements CustomAggregator {
} }
@Override @Override
public void addValue(final boolean valueIsInYRange, final long epochMilli, final long value) { public void addValue(final long epochMilli, final long value) {
map.compute(value, 0, l -> l + 1); map.compute(value, 0, l -> l + 1);
min = min < value ? min : value; min = min < value ? min : value;
max = max > value ? max : value; max = max > value ? max : value;

View File

@@ -41,7 +41,7 @@ public class ParallelRequestsAggregator implements CustomAggregator {
} }
@Override @Override
public void addValue(final boolean valueIsInYRange, final long epochMilli, final long value) { public void addValue(final long epochMilli, final long value) {
final int endPos = (int) (epochMilli - fromEpochMilli); final int endPos = (int) (epochMilli - fromEpochMilli);
increments[endPos]--; increments[endPos]--;

View File

@@ -8,6 +8,7 @@ import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.lucares.pdb.api.DateTimeRange; import org.lucares.pdb.api.DateTimeRange;
import org.lucares.recommind.logs.GnuplotAxis;
import org.lucares.utils.Preconditions; import org.lucares.utils.Preconditions;
public class PlotSettings { public class PlotSettings {
@@ -32,14 +33,11 @@ public class PlotSettings {
private String dateRangeAsString; private String dateRangeAsString;
private AxisScale yAxisScale; private YAxisDefinition y1;
private YAxisDefinition y2;
private AggregateHandlerCollection aggregates; private AggregateHandlerCollection aggregates;
private int yRangeMin;
private int yRangeMax;
private TimeRangeUnit yRangeUnit = TimeRangeUnit.AUTOMATIC;
private boolean keyOutside; private boolean keyOutside;
private boolean generateThumbnail; private boolean generateThumbnail;
@@ -128,21 +126,12 @@ public class PlotSettings {
} }
public void setYAxisScale(final AxisScale axisScale) {
this.yAxisScale = axisScale;
}
public AxisScale getYAxisScale() {
return yAxisScale;
}
@Override @Override
public String toString() { public String toString() {
return "PlotSettings [query=" + query + ", height=" + height + ", width=" + width + ", thumbnailMaxWidth=" return "PlotSettings [query=" + query + ", height=" + height + ", width=" + width + ", thumbnailMaxWidth="
+ thumbnailMaxWidth + ", thumbnailMaxHeight=" + thumbnailMaxHeight + ", groupBy=" + groupBy + thumbnailMaxWidth + ", thumbnailMaxHeight=" + thumbnailMaxHeight + ", groupBy=" + groupBy
+ ", limitBy=" + limitBy + ", limit=" + limit + ", dateRangeAsString=" + dateRangeAsString + ", limitBy=" + limitBy + ", limit=" + limit + ", dateRangeAsString=" + dateRangeAsString + ", y1="
+ ", yAxisScale=" + yAxisScale + ", aggregates=" + aggregates + ", yRangeMin=" + yRangeMin + y1 + " y2=" + y2 + ", aggregates=" + aggregates + ", keyOutside=" + keyOutside
+ ", yRangeMax=" + yRangeMax + ", yRangeUnit=" + yRangeUnit + ", keyOutside=" + keyOutside
+ ", generateThumbnail=" + generateThumbnail + "]"; + ", generateThumbnail=" + generateThumbnail + "]";
} }
@@ -170,28 +159,31 @@ public class PlotSettings {
return generateThumbnail; return generateThumbnail;
} }
public int getYRangeMin() { public YAxisDefinition getY1() {
return yRangeMin; return y1;
} }
public void setYRangeMin(final int yRangeMin) { public void setY1(final YAxisDefinition y1) {
this.yRangeMin = yRangeMin; this.y1 = y1;
} }
public int getYRangeMax() { public YAxisDefinition getY2() {
return yRangeMax; return y2;
} }
public void setYRangeMax(final int yRangeMax) { public void setY2(final YAxisDefinition y2) {
this.yRangeMax = yRangeMax; this.y2 = y2;
} }
public TimeRangeUnit getYRangeUnit() { public YAxisDefinition getyAxisDefinition(final GnuplotAxis yAxis) {
return yRangeUnit; switch (yAxis) {
} case Y1:
return y1;
case Y2:
return y2;
default:
throw new IllegalArgumentException("Unexpected value: " + yAxis);
}
public void setYRangeUnit(final TimeRangeUnit yRangeUnit) {
this.yRangeUnit = yRangeUnit;
} }
} }

View File

@@ -60,7 +60,7 @@ public class ScatterAggregateHandler extends AggregateHandler {
public CustomAggregator createCustomAggregator(final Path tmpDir, final PlotSettings plotSettings, public CustomAggregator createCustomAggregator(final Path tmpDir, final PlotSettings plotSettings,
final long fromEpochMilli, final long toEpochMilli) { final long fromEpochMilli, final long toEpochMilli) {
return new ScatterAggregator(tmpDir, plotSettings, fromEpochMilli, toEpochMilli); return new ScatterAggregator(tmpDir, plotSettings, getyAxis(), fromEpochMilli, toEpochMilli);
} }
@Override @Override

View File

@@ -13,6 +13,7 @@ import java.util.concurrent.TimeUnit;
import org.lucares.collections.Sparse2DLongArray; import org.lucares.collections.Sparse2DLongArray;
import org.lucares.pdb.api.RuntimeIOException; import org.lucares.pdb.api.RuntimeIOException;
import org.lucares.recommind.logs.GnuplotAxis;
import org.lucares.recommind.logs.GnuplotSettings; import org.lucares.recommind.logs.GnuplotSettings;
import org.lucares.recommind.logs.LambdaFriendlyWriter; import org.lucares.recommind.logs.LambdaFriendlyWriter;
import org.lucares.recommind.logs.LongUtils; import org.lucares.recommind.logs.LongUtils;
@@ -32,8 +33,8 @@ public class ScatterAggregator implements CustomAggregator {
private final Path tmpDir; private final Path tmpDir;
public ScatterAggregator(final Path tmpDir, final PlotSettings plotSettings, final long fromEpochMilli, public ScatterAggregator(final Path tmpDir, final PlotSettings plotSettings, final GnuplotAxis yAxis,
final long toEpochMilli) { final long fromEpochMilli, final long toEpochMilli) {
this.tmpDir = tmpDir; this.tmpDir = tmpDir;
useMillis = (toEpochMilli - fromEpochMilli) < TimeUnit.MINUTES.toMillis(5); useMillis = (toEpochMilli - fromEpochMilli) < TimeUnit.MINUTES.toMillis(5);
@@ -41,17 +42,18 @@ public class ScatterAggregator implements CustomAggregator {
plotAreaHeightInPx = plotSettings.getHeight() - GnuplotSettings.GNUPLOT_TOP_BOTTOM_MARGIN; plotAreaHeightInPx = plotSettings.getHeight() - GnuplotSettings.GNUPLOT_TOP_BOTTOM_MARGIN;
epochMillisPerPixel = Math.max(1, (toEpochMilli - fromEpochMilli) / plotAreaWidthInPx); epochMillisPerPixel = Math.max(1, (toEpochMilli - fromEpochMilli) / plotAreaWidthInPx);
minValue = plotSettings.getYRangeUnit() == TimeRangeUnit.AUTOMATIC ? 0 final YAxisDefinition yAxisDefinition = plotSettings.getyAxisDefinition(yAxis);
: plotSettings.getYRangeUnit().toMilliSeconds(plotSettings.getYRangeMin());
maxValue = plotSettings.getYRangeUnit() == TimeRangeUnit.AUTOMATIC ? Long.MAX_VALUE minValue = yAxisDefinition.getRangeUnit() == TimeRangeUnit.AUTOMATIC ? 0 : yAxisDefinition.getRangeMinInMs();
: plotSettings.getYRangeUnit().toMilliSeconds(plotSettings.getYRangeMax()); maxValue = yAxisDefinition.getRangeUnit() == TimeRangeUnit.AUTOMATIC ? Long.MAX_VALUE
durationMillisPerPixel = plotSettings.getYAxisScale() == AxisScale.LINEAR : yAxisDefinition.getRangeMaxInMs();
durationMillisPerPixel = yAxisDefinition.getAxisScale() == AxisScale.LINEAR
? Math.max(1, (maxValue - minValue) / plotAreaHeightInPx) ? Math.max(1, (maxValue - minValue) / plotAreaHeightInPx)
: 1; : 1;
} }
@Override @Override
public void addValue(final boolean valueIsInYRange, final long epochMilli, final long value) { public void addValue(final long epochMilli, final long value) {
final long roundedEpochMilli = epochMilli - epochMilli % epochMillisPerPixel; final long roundedEpochMilli = epochMilli - epochMilli % epochMillisPerPixel;
final long roundedValue = value - value % durationMillisPerPixel; final long roundedValue = value - value % durationMillisPerPixel;
matrix2d.put(roundedEpochMilli, roundedValue, 1); matrix2d.put(roundedEpochMilli, roundedValue, 1);

View File

@@ -1,41 +1,58 @@
package org.lucares.pdb.plot.api; package org.lucares.pdb.plot.api;
public class YAxisDefinition { public class YAxisDefinition {
private AxisScale yAxisScale = AxisScale.LINEAR; private AxisScale axisScale = AxisScale.LINEAR;
private int yRangeMin = 0; private int rangeMin = 0;
private int yRangeMax = 300; private int rangeMax = 300;
private TimeRangeUnit yRangeUnit = TimeRangeUnit.AUTOMATIC; private TimeRangeUnit rangeUnit = TimeRangeUnit.AUTOMATIC;
public AxisScale getAxisScale() { public AxisScale getAxisScale() {
return yAxisScale; return axisScale;
} }
public void setAxisScale(final AxisScale yAxis) { public void setAxisScale(final AxisScale axisScale) {
this.yAxisScale = yAxis; this.axisScale = axisScale;
} }
public int getyRangeMin() { public long getRangeMinInMs() {
return yRangeMin; return rangeUnit.toMilliSeconds(rangeMin);
} }
public void setyRangeMin(final int yRangeMin) { public long getRangeMaxInMs() {
this.yRangeMin = yRangeMin; return rangeUnit.toMilliSeconds(rangeMax);
} }
public int getyRangeMax() { public int getRangeMin() {
return yRangeMax; return rangeMin;
} }
public void setyRangeMax(final int yRangeMax) { public boolean hasRange() {
this.yRangeMax = yRangeMax; return rangeUnit != TimeRangeUnit.AUTOMATIC && rangeMin >= 0 && rangeMax >= 0 && rangeMin < rangeMax;
} }
public TimeRangeUnit getyRangeUnit() { public void setRangeMin(final int rangeMin) {
return yRangeUnit; this.rangeMin = rangeMin;
} }
public void setyRangeUnit(final TimeRangeUnit yRangeUnit) { public int getRangeMax() {
this.yRangeUnit = yRangeUnit; return rangeMax;
} }
public void setRangeMax(final int rangeMax) {
this.rangeMax = rangeMax;
}
public TimeRangeUnit getRangeUnit() {
return rangeUnit;
}
public void setRangeUnit(final TimeRangeUnit rangeUnit) {
this.rangeUnit = rangeUnit;
}
public boolean isLogscale() {
return axisScale == AxisScale.LOG10;
}
} }

View File

@@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit;
import org.lucares.collections.LongList; import org.lucares.collections.LongList;
import org.lucares.pdb.api.DateTimeRange; import org.lucares.pdb.api.DateTimeRange;
import org.lucares.pdb.plot.api.AxisScale; import org.lucares.pdb.plot.api.AxisScale;
import org.lucares.pdb.plot.api.YAxisDefinition;
import org.lucares.recommind.logs.AxisSettings.Type; import org.lucares.recommind.logs.AxisSettings.Type;
public class AxisTime { public class AxisTime {
@@ -40,25 +41,30 @@ public class AxisTime {
} }
public static AxisSettings createYAxis(final GnuplotSettings settings, final Collection<DataSeries> dataSeries) { public static AxisSettings createYAxis(final GnuplotSettings settings, final Collection<DataSeries> dataSeries) {
final GnuplotAxis yAxis = GnuplotAxis.Y1; // TODO get yAxis as parameter
final AxisSettings result = new AxisSettings(); final AxisSettings result = new AxisSettings();
result.setLabel("Duration"); result.setLabel("Duration");
result.setType(Type.Duration); result.setType(Type.Duration);
result.setAxis(GnuplotAxis.Y1); result.setAxis(yAxis);
result.setTicsEnabled(true); result.setTicsEnabled(true);
final int graphOffset = settings.getYAxisScale() == AxisScale.LINEAR ? 0 : 1; final YAxisDefinition yAxisDefinition = settings.getYAxisDefinition(yAxis);
if (settings.hasYRange()) {
final int min = Math.max(settings.getYRangeMin(), graphOffset); final int graphOffset = yAxisDefinition.getAxisScale() == AxisScale.LINEAR ? 0 : 1;
final int max = settings.getYRangeMax(); if (yAxisDefinition.hasRange()) {
final long min = Math.max(yAxisDefinition.getRangeMinInMs(), graphOffset);
final long max = yAxisDefinition.getRangeMaxInMs();
result.setFrom(String.valueOf(min)); result.setFrom(String.valueOf(min));
result.setTo(String.valueOf(max)); result.setTo(String.valueOf(max));
} else { } else {
result.setFrom(String.valueOf(graphOffset)); result.setFrom(String.valueOf(graphOffset));
} }
result.setLogscale(settings.getYAxisScale() == AxisScale.LOG10); result.setLogscale(yAxisDefinition.isLogscale());
result.setTics(YAxisTicks.computeYTicks(settings, dataSeries)); result.setTics(YAxisTicks.computeYTicks(settings, yAxis, dataSeries));
return result; return result;
} }

View File

@@ -7,13 +7,11 @@ class CsvSummary {
private final long maxValue; private final long maxValue;
private final AggregatorCollection aggregators; private final AggregatorCollection aggregators;
private final double statsAverage; private final double statsAverage;
private final int plottedValues;
public CsvSummary(final int values, final int plottedValues, final long maxValue, final double statsAverage, public CsvSummary(final int values, final long maxValue, final double statsAverage,
final AggregatorCollection aggregators) { final AggregatorCollection aggregators) {
super(); super();
this.values = values; this.values = values;
this.plottedValues = plottedValues;
this.maxValue = maxValue; this.maxValue = maxValue;
this.statsAverage = statsAverage; this.statsAverage = statsAverage;
this.aggregators = aggregators; this.aggregators = aggregators;
@@ -29,16 +27,6 @@ class CsvSummary {
return values; return values;
} }
/**
* Number of plotted values in the selected date range <em>and</em> y-range.
*
* @see CsvSummary#getValues()
* @return number of plotted values
*/
public int getPlottedValues() {
return plottedValues;
}
public long getMaxValue() { public long getMaxValue() {
return maxValue; return maxValue;
} }

View File

@@ -31,8 +31,6 @@ public interface DataSeries {
public int getValues(); public int getValues();
public int getPlottedValues();
public long getMaxValue(); public long getMaxValue();
public double getAverage(); public double getAverage();

View File

@@ -48,11 +48,6 @@ public class FileBackedDataSeries implements DataSeries {
return csvSummary.getValues(); return csvSummary.getValues();
} }
@Override
public int getPlottedValues() {
return csvSummary.getPlottedValues();
}
@Override @Override
public long getMaxValue() { public long getMaxValue() {
return csvSummary.getMaxValue(); return csvSummary.getMaxValue();

View File

@@ -4,7 +4,7 @@ import java.nio.file.Path;
import org.lucares.pdb.api.DateTimeRange; import org.lucares.pdb.api.DateTimeRange;
import org.lucares.pdb.plot.api.AggregateHandlerCollection; import org.lucares.pdb.plot.api.AggregateHandlerCollection;
import org.lucares.pdb.plot.api.AxisScale; import org.lucares.pdb.plot.api.YAxisDefinition;
public class GnuplotSettings { public class GnuplotSettings {
@@ -27,14 +27,13 @@ public class GnuplotSettings {
// set output "datausage.png" // set output "datausage.png"
private final Path output; private final Path output;
private AxisScale yAxisScale; private YAxisDefinition y1;
private YAxisDefinition y2;
private AggregateHandlerCollection aggregates; private AggregateHandlerCollection aggregates;
private boolean keyOutside = false; private boolean keyOutside = false;
private AxisSettings xAxisSettings = new AxisSettings(); private AxisSettings xAxisSettings = new AxisSettings();
private boolean renderLabels = true; private boolean renderLabels = true;
private int yRangeMin = -1;
private int yRangeMax = -1;
private DateTimeRange dateTimeRange; private DateTimeRange dateTimeRange;
public GnuplotSettings(final Path output) { public GnuplotSettings(final Path output) {
@@ -93,14 +92,6 @@ public class GnuplotSettings {
return output; return output;
} }
public void setYAxisScale(final AxisScale yAxisScale) {
this.yAxisScale = yAxisScale;
}
public AxisScale getYAxisScale() {
return yAxisScale;
}
public void setAggregates(final AggregateHandlerCollection aggregates) { public void setAggregates(final AggregateHandlerCollection aggregates) {
this.aggregates = aggregates; this.aggregates = aggregates;
} }
@@ -125,24 +116,23 @@ public class GnuplotSettings {
return renderLabels; return renderLabels;
} }
public boolean hasYRange() { public YAxisDefinition getY1() {
return yRangeMin >= 0 && yRangeMax >= 0 && yRangeMin < yRangeMax; return y1;
} }
public void setYRange(final int yRangeMin, final int yRangeMax) { public void setY1(final YAxisDefinition y1) {
this.yRangeMin = yRangeMin; this.y1 = y1;
this.yRangeMax = yRangeMax;
} }
public int getYRangeMin() { public YAxisDefinition getY2() {
return yRangeMin; return y2;
} }
public int getYRangeMax() { public void setY2(final YAxisDefinition y2) {
return yRangeMax; this.y2 = y2;
} }
public void setDateTimeRange(DateTimeRange dateTimeRange) { public void setDateTimeRange(final DateTimeRange dateTimeRange) {
this.dateTimeRange = dateTimeRange; this.dateTimeRange = dateTimeRange;
} }
@@ -150,6 +140,17 @@ public class GnuplotSettings {
return dateTimeRange; return dateTimeRange;
} }
public YAxisDefinition getYAxisDefinition(final GnuplotAxis yAxis) {
switch (yAxis) {
case Y1:
return y1;
case Y2:
return y2;
default:
throw new IllegalArgumentException("Unexpected value: " + yAxis);
}
}
// plot 'sample.txt' using 1:2 title 'Bytes' with linespoints 2 // plot 'sample.txt' using 1:2 title 'Bytes' with linespoints 2
} }

View File

@@ -24,7 +24,6 @@ import org.lucares.pdb.api.Tags;
import org.lucares.pdb.plot.api.AggregatorCollection; import org.lucares.pdb.plot.api.AggregatorCollection;
import org.lucares.pdb.plot.api.Limit; import org.lucares.pdb.plot.api.Limit;
import org.lucares.pdb.plot.api.PlotSettings; import org.lucares.pdb.plot.api.PlotSettings;
import org.lucares.pdb.plot.api.TimeRangeUnit;
import org.lucares.performance.db.PerformanceDb; import org.lucares.performance.db.PerformanceDb;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -108,10 +107,10 @@ public class Plotter {
gnuplotSettings.setWidth(width); gnuplotSettings.setWidth(width);
gnuplotSettings.setDateTimeRange(plotSettings.dateRange()); gnuplotSettings.setDateTimeRange(plotSettings.dateRange());
gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale()); gnuplotSettings.setY1(plotSettings.getY1());
gnuplotSettings.setY2(plotSettings.getY2());
gnuplotSettings.setAggregates(plotSettings.getAggregates()); gnuplotSettings.setAggregates(plotSettings.getAggregates());
defineYRange(gnuplotSettings, plotSettings.getYRangeMin(), plotSettings.getYRangeMax(),
plotSettings.getYRangeUnit());
gnuplotSettings.setKeyOutside(plotSettings.isKeyOutside()); gnuplotSettings.setKeyOutside(plotSettings.isKeyOutside());
gnuplot.plot(gnuplotSettings, dataSeries); gnuplot.plot(gnuplotSettings, dataSeries);
} }
@@ -124,11 +123,9 @@ public class Plotter {
gnuplotSettings.setHeight(plotSettings.getThumbnailMaxHeight()); gnuplotSettings.setHeight(plotSettings.getThumbnailMaxHeight());
gnuplotSettings.setWidth(plotSettings.getThumbnailMaxWidth()); gnuplotSettings.setWidth(plotSettings.getThumbnailMaxWidth());
gnuplotSettings.setDateTimeRange(plotSettings.dateRange()); gnuplotSettings.setDateTimeRange(plotSettings.dateRange());
gnuplotSettings.setY1(plotSettings.getY1());
gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale()); gnuplotSettings.setY2(plotSettings.getY2());
gnuplotSettings.setAggregates(plotSettings.getAggregates()); gnuplotSettings.setAggregates(plotSettings.getAggregates());
defineYRange(gnuplotSettings, plotSettings.getYRangeMin(), plotSettings.getYRangeMax(),
plotSettings.getYRangeUnit());
gnuplotSettings.setKeyOutside(false); gnuplotSettings.setKeyOutside(false);
gnuplotSettings.renderLabels(false); gnuplotSettings.renderLabels(false);
gnuplot.plot(gnuplotSettings, dataSeries); gnuplot.plot(gnuplotSettings, dataSeries);
@@ -148,16 +145,6 @@ public class Plotter {
} }
} }
private void defineYRange(final GnuplotSettings gnuplotSettings, final int yRangeMin, final int yRangeMax,
final TimeRangeUnit yRangeUnit) {
if (yRangeUnit != TimeRangeUnit.AUTOMATIC) {
final int min = yRangeUnit.toMilliSeconds(yRangeMin);
final int max = yRangeUnit.toMilliSeconds(yRangeMax);
gnuplotSettings.setYRange(min, max);
}
}
private static CsvSummary toCsvDeduplicated(final GroupResult groupResult, final Path tmpDir, private static CsvSummary toCsvDeduplicated(final GroupResult groupResult, final Path tmpDir,
final OffsetDateTime dateFrom, final OffsetDateTime dateTo, final PlotSettings plotSettings) final OffsetDateTime dateFrom, final OffsetDateTime dateTo, final PlotSettings plotSettings)
throws IOException { throws IOException {
@@ -169,16 +156,11 @@ public class Plotter {
final long toEpochMilli = dateTo.toInstant().toEpochMilli(); final long toEpochMilli = dateTo.toInstant().toEpochMilli();
final boolean useMillis = (toEpochMilli - fromEpochMilli) < TimeUnit.MINUTES.toMillis(5); final boolean useMillis = (toEpochMilli - fromEpochMilli) < TimeUnit.MINUTES.toMillis(5);
final long minValue = plotSettings.getYRangeUnit() == TimeRangeUnit.AUTOMATIC ? 0
: plotSettings.getYRangeUnit().toMilliSeconds(plotSettings.getYRangeMin());
final long maxValue = plotSettings.getYRangeUnit() == TimeRangeUnit.AUTOMATIC ? Long.MAX_VALUE
: plotSettings.getYRangeUnit().toMilliSeconds(plotSettings.getYRangeMax());
final AggregatorCollection aggregator = plotSettings.getAggregates().createCustomAggregator(tmpDir, final AggregatorCollection aggregator = plotSettings.getAggregates().createCustomAggregator(tmpDir,
plotSettings, fromEpochMilli, toEpochMilli); plotSettings, fromEpochMilli, toEpochMilli);
int count = 0; // number of values in the x-axis range (used to compute stats) int count = 0; // number of values in the x-axis range (used to compute stats)
int plottedValues = 0; final int plottedValues = 0;
long statsMaxValue = 0; long statsMaxValue = 0;
double statsCurrentAverage = 0.0; double statsCurrentAverage = 0.0;
long ignoredValues = 0; long ignoredValues = 0;
@@ -204,22 +186,14 @@ public class Plotter {
// compute average (important to do this after 'count' has been incremented) // compute average (important to do this after 'count' has been incremented)
statsCurrentAverage = statsCurrentAverage + (value - statsCurrentAverage) / count; statsCurrentAverage = statsCurrentAverage + (value - statsCurrentAverage) / count;
// check if value is in the selected y-range aggregator.addValue(groupedBy, epochMilli, value);
final boolean valueIsInYRange = value < minValue || value > maxValue;
if (valueIsInYRange) {
ignoredValues++;
} else {
plottedValues++;
}
aggregator.addValue(groupedBy, valueIsInYRange, epochMilli, value);
} }
} }
METRICS_LOGGER.debug("wrote {} values to csv in: {}ms (ignored {} values) use millis: {}, grouping={}", METRICS_LOGGER.debug("wrote {} values to csv in: {}ms (ignored {} values) use millis: {}, grouping={}",
plottedValues, (System.nanoTime() - start) / 1_000_000.0, ignoredValues, Boolean.toString(useMillis), plottedValues, (System.nanoTime() - start) / 1_000_000.0, ignoredValues, Boolean.toString(useMillis),
groupResult.getGroupedBy().asString()); groupResult.getGroupedBy().asString());
return new CsvSummary(count, plottedValues, statsMaxValue, statsCurrentAverage, aggregator); return new CsvSummary(count, statsMaxValue, statsCurrentAverage, aggregator);
} }
@@ -229,17 +203,13 @@ public class Plotter {
} }
static String title(final Tags tags, final CsvSummary csvSummary) { static String title(final Tags tags, final CsvSummary csvSummary) {
// FIXME title must be computed by the AggregateHandler, because it is the only
// one knowing how many values are plotted
final StringBuilder result = new StringBuilder(tags.asValueString()); final StringBuilder result = new StringBuilder(tags.asValueString());
final int values = csvSummary.getValues(); final int values = csvSummary.getValues();
final int plottedValues = csvSummary.getPlottedValues();
result.append(" ("); result.append(" (");
if (plottedValues != values) { result.append(String.format("%,d", values));
result.append(String.format("%,d / %,d", plottedValues, values));
} else {
result.append(String.format("%,d", values));
}
result.append(")"); result.append(")");
return result.toString(); return result.toString();

View File

@@ -12,23 +12,28 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.lucares.pdb.plot.api.YAxisDefinition;
class YAxisTicks { class YAxisTicks {
public static List<String> computeYTicks(final GnuplotSettings settings, final Collection<DataSeries> dataSeries) { public static List<String> computeYTicks(final GnuplotSettings settings, final GnuplotAxis yAxis,
final Collection<DataSeries> dataSeries) {
List<String> result = new ArrayList<String>(); List<String> result = new ArrayList<String>();
final YAxisDefinition yAxisDefinition = settings.getYAxisDefinition(yAxis);
final long yRangeMax; final long yRangeMax;
final long yRangeMin; final long yRangeMin;
if (settings.hasYRange()) { if (yAxisDefinition.hasRange()) {
yRangeMax = settings.getYRangeMax(); yRangeMin = yAxisDefinition.getRangeMinInMs();
yRangeMin = settings.getYRangeMin(); yRangeMax = yAxisDefinition.getRangeMaxInMs();
} else { } else {
yRangeMax = DataSeries.maxValue(dataSeries);
yRangeMin = 0; yRangeMin = 0;
yRangeMax = DataSeries.maxValue(dataSeries);
} }
final int height = settings.getHeight(); final int height = settings.getHeight();
switch (settings.getYAxisScale()) { switch (yAxisDefinition.getAxisScale()) {
case LINEAR: case LINEAR:
result = computeLinearYTicks(height, yRangeMin, yRangeMax); result = computeLinearYTicks(height, yRangeMin, yRangeMax);
break; break;
@@ -81,16 +86,17 @@ class YAxisTicks {
return ticsLabels; return ticsLabels;
} }
private static List<String> computeLinearYTicks(final long height, final long yRangeMin, final long yRangeMax) { private static List<String> computeLinearYTicks(final long height, final long yRangeMinInMs,
final long yRangeMaxInMs) {
final long plotHeight = height - GnuplotSettings.GNUPLOT_TOP_BOTTOM_MARGIN; final long plotHeight = height - GnuplotSettings.GNUPLOT_TOP_BOTTOM_MARGIN;
final long maxLabels = plotHeight / (GnuplotSettings.TICKS_FONT_SIZE * 5); final long maxLabels = plotHeight / (GnuplotSettings.TICKS_FONT_SIZE * 5);
final long range = yRangeMax - yRangeMin; final long range = yRangeMaxInMs - yRangeMinInMs;
final long msPerLabel = roundToLinearLabelSteps(range / maxLabels); final long msPerLabel = roundToLinearLabelSteps(range / maxLabels);
final List<String> ticsLabels = new ArrayList<>(); final List<String> ticsLabels = new ArrayList<>();
for (long i = yRangeMin; i <= yRangeMax; i += msPerLabel) { for (long i = yRangeMinInMs; i <= yRangeMaxInMs; i += msPerLabel) {
ticsLabels.add("\"" + msToTic(i, msPerLabel) + "\" " + i); ticsLabels.add("\"" + msToTic(i, msPerLabel) + "\" " + i);
} }

View File

@@ -1,12 +1,9 @@
package org.lucares.pdbui; package org.lucares.pdbui;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.text.Collator; import java.text.Collator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
@@ -23,9 +20,6 @@ import org.lucares.pdb.api.DateTimeRange;
import org.lucares.pdb.api.QueryWithCaretMarker; import org.lucares.pdb.api.QueryWithCaretMarker;
import org.lucares.pdb.api.QueryWithCaretMarker.ResultMode; import org.lucares.pdb.api.QueryWithCaretMarker.ResultMode;
import org.lucares.pdb.datastore.Proposal; import org.lucares.pdb.datastore.Proposal;
import org.lucares.pdb.plot.api.Aggregate;
import org.lucares.pdb.plot.api.AxisScale;
import org.lucares.pdb.plot.api.Limit;
import org.lucares.pdb.plot.api.PlotSettings; import org.lucares.pdb.plot.api.PlotSettings;
import org.lucares.pdbui.domain.AutocompleteProposal; import org.lucares.pdbui.domain.AutocompleteProposal;
import org.lucares.pdbui.domain.AutocompleteProposalByValue; import org.lucares.pdbui.domain.AutocompleteProposalByValue;
@@ -48,7 +42,6 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -60,7 +53,6 @@ import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonMappingException;
@@ -156,65 +148,64 @@ public class PdbController implements HardcodedValues, PropertyKeys {
} }
} }
@RequestMapping(path = "/plots", // /*
method = RequestMethod.GET, // * @RequestMapping(path = "/plots", // method = RequestMethod.GET, // produces =
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE // * MediaType.APPLICATION_OCTET_STREAM_VALUE // ) StreamingResponseBody
) * createPlotImage(@RequestParam(name = "query", defaultValue = "") final String
StreamingResponseBody createPlotImage(@RequestParam(name = "query", defaultValue = "") final String query, * query,
@RequestParam(name = "groupBy[]", defaultValue = "") final List<String> aGroupBy, *
@RequestParam(name = "limitBy.number", defaultValue = "10") final int limit, * @RequestParam(name = "groupBy[]", defaultValue = "") final List<String>
@RequestParam(name = "limitBy.selected", defaultValue = "NO_LIMIT") final Limit limitBy, * aGroupBy,
@RequestParam(name = "dateRange") final String dateRange, *
@RequestParam(name = "axisScale", defaultValue = "LINEAR") final AxisScale axisScale, * @RequestParam(name = "limitBy.number", defaultValue = "10") final int limit,
@RequestParam(name = "aggregates") final EnumSet<Aggregate> aggregate, *
@RequestParam(name = "keyOutside", defaultValue = "false") final boolean keyOutside, * @RequestParam(name = "limitBy.selected", defaultValue = "NO_LIMIT") final
@RequestParam(name = "width", defaultValue = "1920") final int hidth, * Limit limitBy,
@RequestParam(name = "height", defaultValue = "1080") final int height) { *
return (final OutputStream outputStream) -> { * @RequestParam(name = "dateRange") final String dateRange,
*
if (StringUtils.isBlank(query)) { * @RequestParam(name = "axisScale", defaultValue = "LINEAR") final AxisScale
throw new BadRequest("The query must not be empty!"); * axisScale,
} *
* @RequestParam(name = "aggregates") final EnumSet<Aggregate> aggregate,
if (StringUtils.isBlank(dateRange)) { *
throw new BadRequest("The parameter 'dateRange' must be set."); * @RequestParam(name = "keyOutside", defaultValue = "false") final boolean
} * keyOutside,
*
final PlotSettings plotSettings = new PlotSettings(); * @RequestParam(name = "width", defaultValue = "1920") final int hidth,
plotSettings.setQuery(query); *
plotSettings.setGroupBy(aGroupBy); * @RequestParam(name = "height", defaultValue = "1080") final int height) {
plotSettings.setHeight(height); * return (final OutputStream outputStream) -> {
plotSettings.setWidth(hidth); *
plotSettings.setLimit(limit); * if (StringUtils.isBlank(query)) { throw new
plotSettings.setLimitBy(limitBy); * BadRequest("The query must not be empty!"); }
plotSettings.setDateRange(dateRange); *
plotSettings.setYAxisScale(axisScale); * if (StringUtils.isBlank(dateRange)) { throw new
plotSettings.setAggregates(PlotSettingsTransformer.toAggregateInternal(plotSettings.getYRangeUnit(), * BadRequest("The parameter 'dateRange' must be set."); }
plotSettings.getYAxisScale(), aggregate)); *
plotSettings.setKeyOutside(keyOutside); * final PlotSettings plotSettings = new PlotSettings();
plotSettings.setGenerateThumbnail(false); * plotSettings.setQuery(query); plotSettings.setGroupBy(aGroupBy);
* plotSettings.setHeight(height); plotSettings.setWidth(hidth);
if (plotterLock.tryLock()) { * plotSettings.setLimit(limit); plotSettings.setLimitBy(limitBy);
try { * plotSettings.setDateRange(dateRange); plotSettings.setY1(y1);
final PlotResult result = plotter.plot(plotSettings); * plotSettings.setYAxisScale(axisScale);
* plotSettings.setAggregates(PlotSettingsTransformer.toAggregateInternal(
try (FileInputStream in = new FileInputStream(result.getImagePath().toFile())) { * plotSettings.getYRangeUnit(), plotSettings.getYAxisScale(), aggregate));
StreamUtils.copy(in, outputStream); * plotSettings.setKeyOutside(keyOutside);
} * plotSettings.setGenerateThumbnail(false);
} catch (final NoDataPointsException e) { *
throw new NotFoundException(e); * if (plotterLock.tryLock()) { try { final PlotResult result =
} catch (final InternalPlottingException e) { * plotter.plot(plotSettings);
throw new InternalServerError(e); *
} finally { * try (FileInputStream in = new
plotterLock.unlock(); * FileInputStream(result.getImagePath().toFile())) { StreamUtils.copy(in,
} * outputStream); } } catch (final NoDataPointsException e) { throw new
* NotFoundException(e); } catch (final InternalPlottingException e) { throw new
} else { * InternalServerError(e); } finally { plotterLock.unlock(); }
throw new ServiceUnavailableException("Too many parallel requests!"); *
} * } else { throw new
}; * ServiceUnavailableException("Too many parallel requests!"); } }; }
} */
@RequestMapping(path = "/autocomplete", // @RequestMapping(path = "/autocomplete", //
method = RequestMethod.GET, // method = RequestMethod.GET, //
produces = MediaType.APPLICATION_JSON_VALUE // produces = MediaType.APPLICATION_JSON_VALUE //

View File

@@ -1,5 +1,7 @@
package org.lucares.pdbui; package org.lucares.pdbui;
import java.util.List;
import org.lucares.pdb.plot.api.Aggregate; import org.lucares.pdb.plot.api.Aggregate;
import org.lucares.pdb.plot.api.AggregateHandlerCollection; import org.lucares.pdb.plot.api.AggregateHandlerCollection;
import org.lucares.pdb.plot.api.AxisScale; import org.lucares.pdb.plot.api.AxisScale;
@@ -10,6 +12,7 @@ import org.lucares.pdb.plot.api.ParallelRequestsAggregate;
import org.lucares.pdb.plot.api.PlotSettings; import org.lucares.pdb.plot.api.PlotSettings;
import org.lucares.pdb.plot.api.ScatterAggregateHandler; import org.lucares.pdb.plot.api.ScatterAggregateHandler;
import org.lucares.pdb.plot.api.TimeRangeUnit; import org.lucares.pdb.plot.api.TimeRangeUnit;
import org.lucares.pdb.plot.api.YAxisDefinition;
import org.lucares.pdbui.domain.PlotRequest; import org.lucares.pdbui.domain.PlotRequest;
class PlotSettingsTransformer { class PlotSettingsTransformer {
@@ -24,40 +27,20 @@ class PlotSettingsTransformer {
result.setLimit(request.getLimit()); result.setLimit(request.getLimit());
result.setLimitBy(request.getLimitBy()); result.setLimitBy(request.getLimitBy());
result.setDateRange(request.getDateRange()); result.setDateRange(request.getDateRange());
result.setYAxisScale(request.getY1().getAxisScale());
result.setKeyOutside(request.isKeyOutside()); result.setKeyOutside(request.isKeyOutside());
result.setThumbnailMaxWidth(request.getThumbnailMaxWidth()); result.setThumbnailMaxWidth(request.getThumbnailMaxWidth());
result.setThumbnailMaxHeight(request.getThumbnailMaxHeight()); result.setThumbnailMaxHeight(request.getThumbnailMaxHeight());
result.setGenerateThumbnail(request.isGenerateThumbnail()); result.setGenerateThumbnail(request.isGenerateThumbnail());
result.setYRangeMin(request.getY1().getyRangeMin()); result.setY1(request.getY1());
result.setYRangeMax(request.getY1().getyRangeMax()); result.setY2(request.getY2());
result.setYRangeUnit(toTimeRangeUnitInternal(request.getY1().getyRangeUnit())); result.setAggregates(toAggregateInternal(request.getY1(), request.getY2(), request.getAggregates()));
result.setAggregates(
toAggregateInternal(result.getYRangeUnit(), result.getYAxisScale(), request.getAggregates()));
return result; return result;
} }
private static TimeRangeUnit toTimeRangeUnitInternal(final TimeRangeUnit yRangeUnit) { static AggregateHandlerCollection toAggregateInternal(final YAxisDefinition y1, final YAxisDefinition y2,
switch (yRangeUnit) { final List<Aggregate> aggregates) {
case AUTOMATIC:
return TimeRangeUnit.AUTOMATIC;
case MILLISECONDS:
return TimeRangeUnit.MILLISECONDS;
case SECONDS:
return TimeRangeUnit.SECONDS;
case MINUTES:
return TimeRangeUnit.MINUTES;
case HOURS:
return TimeRangeUnit.HOURS;
case DAYS:
return TimeRangeUnit.DAYS;
}
throw new IllegalStateException("unhandled enum value: " + yRangeUnit);
}
static AggregateHandlerCollection toAggregateInternal(final TimeRangeUnit yRangeUnit, final AxisScale yAxisScale,
final Iterable<Aggregate> aggregates) {
final AggregateHandlerCollection aggregateHandlerCollection = new AggregateHandlerCollection(); final AggregateHandlerCollection aggregateHandlerCollection = new AggregateHandlerCollection();
for (final Aggregate aggregate : aggregates) { for (final Aggregate aggregate : aggregates) {
@@ -70,14 +53,7 @@ class PlotSettingsTransformer {
aggregateHandlerCollection.addAggregateHandler(new ParallelRequestsAggregate()); aggregateHandlerCollection.addAggregateHandler(new ParallelRequestsAggregate());
break; break;
case SCATTER: case SCATTER:
if (yRangeUnit == TimeRangeUnit.AUTOMATIC && yAxisScale == AxisScale.LINEAR) { aggregateHandlerCollection.addAggregateHandler(new ScatterAggregateHandler());
// TODO need a second ScatterAggregateHandler for YRangeUnit() ==
// TimeRangeUnitInternal.AUTOMATIC
throw new UnsupportedOperationException(
"linear axis with automatic y range does not work, use logarthmic y-axis, or define a y-axis range");
} else {
aggregateHandlerCollection.addAggregateHandler(new ScatterAggregateHandler());
}
break; break;
case HISTOGRAM: case HISTOGRAM:
aggregateHandlerCollection.addAggregateHandler(new HistogramHandler()); aggregateHandlerCollection.addAggregateHandler(new HistogramHandler());
@@ -92,6 +68,14 @@ class PlotSettingsTransformer {
aggregateHandlerCollection.updateAxisForHandlers(); aggregateHandlerCollection.updateAxisForHandlers();
// Note: this check is incomplete -> implement the todo and remove this
if (y1.getRangeUnit() == TimeRangeUnit.AUTOMATIC && y1.getAxisScale() == AxisScale.LINEAR) {
// TODO need a second ScatterAggregateHandler for YRangeUnit() ==
// TimeRangeUnitInternal.AUTOMATIC
throw new UnsupportedOperationException(
"linear axis with automatic y range does not work, use logarthmic y-axis, or define a y-axis range");
}
return aggregateHandlerCollection; return aggregateHandlerCollection;
} }
} }

View File

@@ -6,11 +6,9 @@ public class DataSeriesStats {
private final int values; private final int values;
private final long maxValue; private final long maxValue;
private final double average; private final double average;
private final int plottedValues;
public DataSeriesStats(final int values, final int plottedValues, final long maxValue, final double average) { public DataSeriesStats(final int values, final long maxValue, final double average) {
this.values = values; this.values = values;
this.plottedValues = plottedValues;
this.maxValue = maxValue; this.maxValue = maxValue;
this.average = average; this.average = average;
} }
@@ -24,15 +22,6 @@ public class DataSeriesStats {
return values; return values;
} }
/**
* The number of values in the date range <em>and</em> the y-range.
*
* @return number of plotted values
*/
public int getPlottedValues() {
return plottedValues;
}
public long getMaxValue() { public long getMaxValue() {
return maxValue; return maxValue;
} }

View File

@@ -12,20 +12,17 @@ public class PlotResponseStats {
private double average; private double average;
private int plottedValues;
private List<DataSeriesStats> dataSeriesStats; private List<DataSeriesStats> dataSeriesStats;
public PlotResponseStats() { public PlotResponseStats() {
super(); super();
} }
public PlotResponseStats(final long maxValue, final int values, final int plottedValues, final double average, public PlotResponseStats(final long maxValue, final int values, final double average,
final List<DataSeriesStats> dataSeriesStats) { final List<DataSeriesStats> dataSeriesStats) {
this.maxValue = maxValue; this.maxValue = maxValue;
this.values = values; this.values = values;
this.plottedValues = plottedValues;
this.average = average; this.average = average;
this.dataSeriesStats = dataSeriesStats; this.dataSeriesStats = dataSeriesStats;
} }
@@ -46,14 +43,6 @@ public class PlotResponseStats {
this.values = values; this.values = values;
} }
public int getPlottedValues() {
return plottedValues;
}
public void setPlottedValues(final int plottedValues) {
this.plottedValues = plottedValues;
}
public double getAverage() { public double getAverage() {
return average; return average;
} }
@@ -73,27 +62,25 @@ public class PlotResponseStats {
@Override @Override
public String toString() { public String toString() {
return "PlotResponseStats [maxValue=" + maxValue + ", values=" + values + ", average=" + average return "PlotResponseStats [maxValue=" + maxValue + ", values=" + values + ", average=" + average
+ ", plottedValues=" + plottedValues + ", dataSeriesStats=" + dataSeriesStats + "]"; + ", dataSeriesStats=" + dataSeriesStats + "]";
} }
public static PlotResponseStats fromDataSeries(final List<DataSeries> dataSeries) { public static PlotResponseStats fromDataSeries(final List<DataSeries> dataSeries) {
int values = 0; int values = 0;
int plottedValues = 0;
long maxValue = 0; long maxValue = 0;
final List<DataSeriesStats> dataSeriesStats = new ArrayList<>(); final List<DataSeriesStats> dataSeriesStats = new ArrayList<>();
for (final DataSeries dataSerie : dataSeries) { for (final DataSeries dataSerie : dataSeries) {
values += dataSerie.getValues(); values += dataSerie.getValues();
plottedValues += dataSerie.getPlottedValues();
maxValue = Math.max(maxValue, dataSerie.getMaxValue()); maxValue = Math.max(maxValue, dataSerie.getMaxValue());
dataSeriesStats.add(new DataSeriesStats(dataSerie.getValues(), dataSerie.getPlottedValues(), dataSeriesStats
dataSerie.getMaxValue(), dataSerie.getAverage())); .add(new DataSeriesStats(dataSerie.getValues(), dataSerie.getMaxValue(), dataSerie.getAverage()));
} }
final double average = Math.round(DataSeriesStats.average(dataSeriesStats)); final double average = Math.round(DataSeriesStats.average(dataSeriesStats));
return new PlotResponseStats(maxValue, values, plottedValues, average, dataSeriesStats); return new PlotResponseStats(maxValue, values, average, dataSeriesStats);
} }
} }

View File

@@ -17,14 +17,14 @@ public class DataSeriesStatsTest {
{ {
final List<DataSeriesStats> stats = Arrays.asList(// final List<DataSeriesStats> stats = Arrays.asList(//
new DataSeriesStats(10, 0, 0, 5.0)// new DataSeriesStats(10, 0, 5.0)//
); );
final double expected = 5.0; final double expected = 5.0;
result.add(Arguments.of(stats, expected)); result.add(Arguments.of(stats, expected));
} }
{ {
final List<DataSeriesStats> stats = Arrays.asList(// final List<DataSeriesStats> stats = Arrays.asList(//
new DataSeriesStats(0, 0, 0, 5.0)// new DataSeriesStats(0, 0, 5.0)//
); );
final double expected = 0.0; // no values final double expected = 0.0; // no values
result.add(Arguments.of(stats, expected)); result.add(Arguments.of(stats, expected));
@@ -32,17 +32,17 @@ public class DataSeriesStatsTest {
{ {
final List<DataSeriesStats> stats = Arrays.asList(// final List<DataSeriesStats> stats = Arrays.asList(//
new DataSeriesStats(10, 0, 0, 5.0), // new DataSeriesStats(10, 0, 5.0), //
new DataSeriesStats(40, 0, 0, 1.0)// new DataSeriesStats(40, 0, 1.0)//
); );
final double expected = 1.8; // 90 / 50 final double expected = 1.8; // 90 / 50
result.add(Arguments.of(stats, expected)); result.add(Arguments.of(stats, expected));
} }
{ {
final List<DataSeriesStats> stats = Arrays.asList(// final List<DataSeriesStats> stats = Arrays.asList(//
new DataSeriesStats(5, 0, 0, 7.0), // new DataSeriesStats(5, 0, 7.0), //
new DataSeriesStats(0, 0, 0, 5.0), // // no values new DataSeriesStats(0, 0, 5.0), // // no values
new DataSeriesStats(20, 0, 0, 2.0)// new DataSeriesStats(20, 0, 2.0)//
); );
final double expected = 3.0; // (35+40) / 25 final double expected = 3.0; // (35+40) / 25
result.add(Arguments.of(stats, expected)); result.add(Arguments.of(stats, expected));