make it possible to render any combination of plots
This commit is contained in:
@@ -1,5 +0,0 @@
|
|||||||
package org.lucares.pdb.plot.api;
|
|
||||||
|
|
||||||
public enum AggreateInternal {
|
|
||||||
NONE, MEAN, PERCENTILE95, PERCENTILE99, PERCENTILE999
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
package org.lucares.pdbui.domain;
|
package org.lucares.pdb.plot.api;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: The order in this enum defines the order in which the aggregates are drawn.
|
* Note: The order in this enum defines the order in which the aggregates are drawn.
|
||||||
*/
|
*/
|
||||||
public enum Aggregate {
|
public enum Aggregate {
|
||||||
NONE,
|
|
||||||
|
|
||||||
PARALLEL,
|
PARALLEL,
|
||||||
|
|
||||||
SCATTER,
|
SCATTER,
|
||||||
@@ -2,12 +2,14 @@ package org.lucares.pdb.plot.api;
|
|||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.lucares.recommind.logs.DataSeries;
|
import org.lucares.recommind.logs.DataSeries;
|
||||||
|
import org.lucares.recommind.logs.LineStyle;
|
||||||
|
|
||||||
public interface AggregateHandler {
|
public interface AggregateHandler {
|
||||||
|
|
||||||
// TODO handle aggregates as normal DataSeries
|
Aggregate getAggregateType();
|
||||||
|
|
||||||
void addGnuplotDefinitions(StringBuilder result, String separator, Collection<DataSeries> dataSeries);
|
void addGnuplotDefinitions(StringBuilder result, String separator, Collection<DataSeries> dataSeries);
|
||||||
|
|
||||||
@@ -19,9 +21,16 @@ public interface AggregateHandler {
|
|||||||
builder.append(String.format(format + "\n", args));
|
builder.append(String.format(format + "\n", args));
|
||||||
}
|
}
|
||||||
|
|
||||||
void addPlotsBeforeScatter(StringBuilder result, Collection<DataSeries> dataSeries);
|
default String gnuplotTitle(Optional<String> title) {
|
||||||
|
|
||||||
void addPlotsAfterScatter(StringBuilder result, Collection<DataSeries> dataSeries);
|
return title.isPresent() ? "title '"+title.get()+"'": "notitle";
|
||||||
|
}
|
||||||
|
|
||||||
|
// void addPlotsBeforeScatter(StringBuilder result, Collection<DataSeries> dataSeries);
|
||||||
|
//
|
||||||
|
// void addPlotsAfterScatter(StringBuilder result, Collection<DataSeries> dataSeries);
|
||||||
|
|
||||||
|
void addPlot(StringBuilder result, AggregatedData aggregatedData, LineStyle lineStyle, Optional<String> title);
|
||||||
|
|
||||||
CustomAggregator createCustomAggregator(Path tmpDir, PlotSettings plotSettings, long fromEpochMilli, long toEpochMilli);
|
CustomAggregator createCustomAggregator(Path tmpDir, PlotSettings plotSettings, long fromEpochMilli, long toEpochMilli);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package org.lucares.pdb.plot.api;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.lucares.recommind.logs.DataSeries;
|
||||||
|
|
||||||
|
public class AggregateHandlerCollection {
|
||||||
|
private static final Comparator<AggregateHandler> COMPARATOR = Comparator.comparing(AggregateHandler::getAggregateType);
|
||||||
|
|
||||||
|
private final List<AggregateHandler> aggregateHandlers = new ArrayList<>();
|
||||||
|
|
||||||
|
public void add(AggregateHandler aggregateHandler) {
|
||||||
|
aggregateHandlers.add(aggregateHandler);
|
||||||
|
Collections.sort(aggregateHandlers, COMPARATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addGnuplotDefinitions(StringBuilder result, String datafileSeparator, Collection<DataSeries> dataSeries) {
|
||||||
|
for (AggregateHandler handler : aggregateHandlers) {
|
||||||
|
handler.addGnuplotDefinitions(result, datafileSeparator, dataSeries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AggregatorCollection createCustomAggregator(Path tmpDir, PlotSettings plotSettings, long fromEpochMilli,
|
||||||
|
long toEpochMilli) {
|
||||||
|
|
||||||
|
final List<CustomAggregator> aggregators = new ArrayList<>();
|
||||||
|
|
||||||
|
for (AggregateHandler handler : aggregateHandlers) {
|
||||||
|
CustomAggregator aggregator = handler.createCustomAggregator(tmpDir, plotSettings, fromEpochMilli, toEpochMilli);
|
||||||
|
if (aggregator != null) {
|
||||||
|
aggregators.add(aggregator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AggregatorCollection(aggregators);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPlots(StringBuilder result, Collection<DataSeries> dataSeries) {
|
||||||
|
|
||||||
|
boolean first = true;
|
||||||
|
for (AggregateHandler handler : aggregateHandlers) {
|
||||||
|
|
||||||
|
for (DataSeries dataSerie : dataSeries) {
|
||||||
|
final Optional<String> title = first ? Optional.of(dataSerie.getTitle()) : Optional.empty();
|
||||||
|
|
||||||
|
Optional<AggregatedData> aggregatedData = dataSerie.getAggregatedData().get(handler.getAggregateType());
|
||||||
|
if(aggregatedData.isPresent()) {
|
||||||
|
handler.addPlot(result, aggregatedData.get(), dataSerie.getStyle(), title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.lucares.pdb.plot.api;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class AggregatedDataCollection implements Iterable<AggregatedData>{
|
||||||
|
private final LinkedHashMap<Aggregate, AggregatedData> aggregatedDatas = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public void put(Aggregate aggregate, AggregatedData aggregatedData) {
|
||||||
|
aggregatedDatas.put(aggregate, aggregatedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<AggregatedData> iterator() {
|
||||||
|
return aggregatedDatas.values().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<AggregatedData> get(Aggregate aggregateType) {
|
||||||
|
return Optional.ofNullable(aggregatedDatas.get(aggregateType));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.lucares.pdb.plot.api;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AggregatorCollection {
|
||||||
|
private final List<CustomAggregator> aggregators;
|
||||||
|
|
||||||
|
public AggregatorCollection(List<CustomAggregator> aggregators) {
|
||||||
|
this.aggregators = aggregators;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addValue(boolean valueIsInYRange, long epochMilli, long value) {
|
||||||
|
for (CustomAggregator aggregator : aggregators) {
|
||||||
|
aggregator.addValue(valueIsInYRange, epochMilli, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AggregatedDataCollection getAggregatedData() throws IOException {
|
||||||
|
|
||||||
|
AggregatedDataCollection result = new AggregatedDataCollection();
|
||||||
|
|
||||||
|
for (CustomAggregator aggregator : aggregators) {
|
||||||
|
result.put(aggregator.getType(), aggregator.getAggregatedData());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -120,4 +120,9 @@ public class CumulativeDistributionCustomAggregator implements CustomAggregator
|
|||||||
return new AggregatedData(title, dataFile);
|
return new AggregatedData(title, dataFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Aggregate getType() {
|
||||||
|
return Aggregate.CUM_DISTRIBUTION;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.lucares.pdb.plot.api;
|
|||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.lucares.recommind.logs.DataSeries;
|
import org.lucares.recommind.logs.DataSeries;
|
||||||
import org.lucares.recommind.logs.LineStyle;
|
import org.lucares.recommind.logs.LineStyle;
|
||||||
@@ -9,8 +10,8 @@ import org.lucares.recommind.logs.LineStyle;
|
|||||||
public class CumulativeDistributionHandler implements AggregateHandler {
|
public class CumulativeDistributionHandler implements AggregateHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CustomAggregator createCustomAggregator(final Path tmpDir, PlotSettings plotSettings, final long fromEpochMilli,
|
public CustomAggregator createCustomAggregator(final Path tmpDir, PlotSettings plotSettings,
|
||||||
final long toEpochMilli) {
|
final long fromEpochMilli, final long toEpochMilli) {
|
||||||
return new CumulativeDistributionCustomAggregator(tmpDir);
|
return new CumulativeDistributionCustomAggregator(tmpDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,23 +29,17 @@ public class CumulativeDistributionHandler implements AggregateHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPlotsBeforeScatter(final StringBuilder result, final Collection<DataSeries> dataSeries) {
|
public void addPlot(StringBuilder result, AggregatedData aggregatedData, LineStyle lineStyle, Optional<String> title) {
|
||||||
// nothing to do: the percentile line should be drawn on the scatter plots and
|
appendfln(result, "'%s' using 1:2 %s with lines axes x2y1 lw 2 %s, \\", //
|
||||||
// must therefore be rendered after the scatter
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPlotsAfterScatter(final StringBuilder result, final Collection<DataSeries> dataSeries) {
|
|
||||||
for (final DataSeries dataSerie : dataSeries) {
|
|
||||||
final AggregatedData aggregatedData = dataSerie.getAggregatedData();
|
|
||||||
if (aggregatedData != null) {
|
|
||||||
final LineStyle lineStyle = dataSerie.getStyle();
|
|
||||||
appendfln(result, "'%s' using 1:2 notitle with lines axes x2y1 lw 2 %s, \\", //
|
|
||||||
aggregatedData.getDataFile().getAbsolutePath(), //
|
aggregatedData.getDataFile().getAbsolutePath(), //
|
||||||
|
gnuplotTitle(title),//
|
||||||
lineStyle.darker()//
|
lineStyle.darker()//
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public Aggregate getAggregateType() {
|
||||||
|
return Aggregate.CUM_DISTRIBUTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ public interface CustomAggregator {
|
|||||||
void addValue(boolean valueIsInYRange, long epochMilli, long value);
|
void addValue(boolean valueIsInYRange, long epochMilli, long value);
|
||||||
|
|
||||||
AggregatedData getAggregatedData() throws IOException;
|
AggregatedData getAggregatedData() throws IOException;
|
||||||
|
|
||||||
|
Aggregate getType();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.lucares.pdb.plot.api;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import org.lucares.recommind.logs.DataSeries;
|
|
||||||
|
|
||||||
public class NullAggregate implements AggregateHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addGnuplotDefinitions(final StringBuilder result, final String separator,
|
|
||||||
final Collection<DataSeries> dataSeries) {
|
|
||||||
// nothing to do; this is a Null-Object
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPlotsBeforeScatter(final StringBuilder result, final Collection<DataSeries> dataSeries) {
|
|
||||||
// nothing to do; this is a Null-Object
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPlotsAfterScatter(final StringBuilder result, final Collection<DataSeries> dataSeries) {
|
|
||||||
// nothing to do; this is a Null-Object
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CustomAggregator createCustomAggregator(final Path tmpDir, PlotSettings plotSettings, final long fromEpochMilli,
|
|
||||||
final long toEpochMilli) {
|
|
||||||
return new NullCustomAggregator();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package org.lucares.pdb.plot.api;
|
|
||||||
|
|
||||||
public class NullCustomAggregator implements CustomAggregator {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addValue(boolean valueIsInYRange,final long epochMilli, final long value) {
|
|
||||||
// nothing to do; this is a null-object
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AggregatedData getAggregatedData() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,11 @@ package org.lucares.pdb.plot.api;
|
|||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.lucares.recommind.logs.DataSeries;
|
import org.lucares.recommind.logs.DataSeries;
|
||||||
|
import org.lucares.recommind.logs.LineStyle;
|
||||||
|
|
||||||
public class ParallelRequestsAggregate implements AggregateHandler {
|
public class ParallelRequestsAggregate implements AggregateHandler {
|
||||||
|
|
||||||
@@ -16,31 +18,27 @@ public class ParallelRequestsAggregate implements AggregateHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPlotsBeforeScatter(final StringBuilder result, final Collection<DataSeries> dataSeries) {
|
public void addPlot(StringBuilder result, AggregatedData aggregatedData, LineStyle lineStyle,
|
||||||
for (final DataSeries dataSerie : dataSeries) {
|
Optional<String> title) {
|
||||||
final AggregatedData aggregatedData = dataSerie.getAggregatedData();
|
appendfln(result, "'%s' using 1:2 %s with filledcurve axes x1y2 lw 1 %s, \\", //
|
||||||
if (aggregatedData != null) {
|
|
||||||
appendfln(result, "'%s' using 1:2 notitle with filledcurve axes x1y2 lw 1 %s, \\", //
|
|
||||||
aggregatedData.getDataFile().getAbsolutePath(), //
|
aggregatedData.getDataFile().getAbsolutePath(), //
|
||||||
dataSerie.getStyle().brighter().asGnuplotLineStyle()//
|
gnuplotTitle(title), //
|
||||||
|
lineStyle.brighter().asGnuplotLineStyle()//
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPlotsAfterScatter(final StringBuilder result, final Collection<DataSeries> dataSeries) {
|
public CustomAggregator createCustomAggregator(final Path tmpDir, PlotSettings plotSettings,
|
||||||
// nothing to do: the parallel line plots shall be drawn below the scatter plot,
|
final long fromEpochMilli, final long toEpochMilli) {
|
||||||
// so that you can see both. Therefore it must be drawn first.
|
if ((toEpochMilli - fromEpochMilli) <= TimeUnit.HOURS.toMillis(50)) {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CustomAggregator createCustomAggregator(final Path tmpDir, PlotSettings plotSettings, final long fromEpochMilli,
|
|
||||||
final long toEpochMilli) {
|
|
||||||
if ((toEpochMilli - fromEpochMilli) <= TimeUnit.HOURS.toMillis(5)) {
|
|
||||||
return new ParallelRequestsAggregator(tmpDir, fromEpochMilli, toEpochMilli);
|
return new ParallelRequestsAggregator(tmpDir, fromEpochMilli, toEpochMilli);
|
||||||
} else {
|
} else {
|
||||||
return new NullCustomAggregator();
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Aggregate getAggregateType() {
|
||||||
|
return Aggregate.PARALLEL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,4 +93,9 @@ public class ParallelRequestsAggregator implements CustomAggregator {
|
|||||||
builder.append(NEWLINE);
|
builder.append(NEWLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Aggregate getType() {
|
||||||
|
return Aggregate.PARALLEL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class PlotSettings {
|
|||||||
|
|
||||||
private AxisScale yAxisScale;
|
private AxisScale yAxisScale;
|
||||||
|
|
||||||
private AggregateHandler aggregate;
|
private AggregateHandlerCollection aggregates;
|
||||||
|
|
||||||
private int yRangeMin;
|
private int yRangeMin;
|
||||||
private int yRangeMax;
|
private int yRangeMax;
|
||||||
@@ -141,17 +141,17 @@ public class PlotSettings {
|
|||||||
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
|
||||||
+ ", yAxisScale=" + yAxisScale + ", aggregate=" + aggregate + ", yRangeMin=" + yRangeMin
|
+ ", yAxisScale=" + yAxisScale + ", aggregates=" + aggregates + ", yRangeMin=" + yRangeMin
|
||||||
+ ", yRangeMax=" + yRangeMax + ", yRangeUnit=" + yRangeUnit + ", keyOutside=" + keyOutside
|
+ ", yRangeMax=" + yRangeMax + ", yRangeUnit=" + yRangeUnit + ", keyOutside=" + keyOutside
|
||||||
+ ", generateThumbnail=" + generateThumbnail + "]";
|
+ ", generateThumbnail=" + generateThumbnail + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAggregate(final AggregateHandler aggregate) {
|
public void setAggregates(final AggregateHandlerCollection aggregates) {
|
||||||
this.aggregate = aggregate;
|
this.aggregates = aggregates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AggregateHandler getAggregate() {
|
public AggregateHandlerCollection getAggregates() {
|
||||||
return aggregate;
|
return aggregates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKeyOutside(final boolean keyOutside) {
|
public void setKeyOutside(final boolean keyOutside) {
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package org.lucares.pdb.plot.api;
|
|||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.lucares.recommind.logs.DataSeries;
|
import org.lucares.recommind.logs.DataSeries;
|
||||||
import org.lucares.recommind.logs.GnuplotLineType;
|
import org.lucares.recommind.logs.GnuplotLineType;
|
||||||
|
import org.lucares.recommind.logs.LineStyle;
|
||||||
|
|
||||||
public class ScatterAggregateHandler implements AggregateHandler {
|
public class ScatterAggregateHandler implements AggregateHandler {
|
||||||
|
|
||||||
@@ -15,28 +17,15 @@ public class ScatterAggregateHandler implements AggregateHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPlotsBeforeScatter(StringBuilder result, Collection<DataSeries> dataSeries) {
|
public void addPlot(StringBuilder result, AggregatedData aggregatedData, LineStyle lineStyle, Optional<String> title) {
|
||||||
|
|
||||||
for (final DataSeries dataSerie : dataSeries) {
|
appendfln(result, "'%s' using 1:2 %s with %s %s, \\", //
|
||||||
final AggregatedData aggregatedData = dataSerie.getAggregatedData();
|
|
||||||
if (aggregatedData != null) {
|
|
||||||
|
|
||||||
appendfln(result, "'%s' using 1:2 title '%s' with %s %s, \\", //
|
|
||||||
aggregatedData.getDataFile(), //
|
aggregatedData.getDataFile(), //
|
||||||
dataSerie.getTitle(), //
|
gnuplotTitle(title), //
|
||||||
GnuplotLineType.Points,
|
GnuplotLineType.Points, //
|
||||||
dataSerie.getStyle()//
|
lineStyle//
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPlotsAfterScatter(StringBuilder result, Collection<DataSeries> dataSeries) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CustomAggregator createCustomAggregator(Path tmpDir, PlotSettings plotSettings, long fromEpochMilli,
|
public CustomAggregator createCustomAggregator(Path tmpDir, PlotSettings plotSettings, long fromEpochMilli,
|
||||||
@@ -44,4 +33,9 @@ public class ScatterAggregateHandler implements AggregateHandler {
|
|||||||
|
|
||||||
return new ScatterAggregator(tmpDir, plotSettings, fromEpochMilli, toEpochMilli);
|
return new ScatterAggregator(tmpDir, plotSettings, fromEpochMilli, toEpochMilli);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Aggregate getAggregateType() {
|
||||||
|
return Aggregate.SCATTER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,4 +91,9 @@ public class ScatterAggregator implements CustomAggregator {
|
|||||||
|
|
||||||
return new AggregatedData("scatter", dataFile);
|
return new AggregatedData("scatter", dataFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Aggregate getType() {
|
||||||
|
return Aggregate.SCATTER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package org.lucares.recommind.logs;
|
package org.lucares.recommind.logs;
|
||||||
|
|
||||||
import org.lucares.pdb.plot.api.AggregatedData;
|
import org.lucares.pdb.plot.api.AggregatedDataCollection;
|
||||||
|
|
||||||
class CsvSummary {
|
class CsvSummary {
|
||||||
private final int values;
|
private final int values;
|
||||||
private final long maxValue;
|
private final long maxValue;
|
||||||
private final AggregatedData aggregatedData;
|
private final AggregatedDataCollection aggregatedData;
|
||||||
private final double statsAverage;
|
private final double statsAverage;
|
||||||
private final int plottedValues;
|
private final int plottedValues;
|
||||||
|
|
||||||
public CsvSummary(final int values, final int plottedValues, final long maxValue,
|
public CsvSummary(final int values, final int plottedValues, final long maxValue,
|
||||||
final double statsAverage, final AggregatedData aggregatedData) {
|
final double statsAverage, final AggregatedDataCollection aggregatedData) {
|
||||||
super();
|
super();
|
||||||
this.values = values;
|
this.values = values;
|
||||||
this.plottedValues = plottedValues;
|
this.plottedValues = plottedValues;
|
||||||
@@ -48,7 +48,7 @@ class CsvSummary {
|
|||||||
return statsAverage;
|
return statsAverage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AggregatedData getAggregatedData() {
|
public AggregatedDataCollection getAggregatedData() {
|
||||||
return aggregatedData;
|
return aggregatedData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.lucares.pdb.plot.api.AggregatedData;
|
import org.lucares.pdb.plot.api.AggregatedDataCollection;
|
||||||
import org.lucares.pdb.plot.api.Limit;
|
import org.lucares.pdb.plot.api.Limit;
|
||||||
|
|
||||||
public interface DataSeries {
|
public interface DataSeries {
|
||||||
@@ -41,7 +41,7 @@ public interface DataSeries {
|
|||||||
|
|
||||||
public LineStyle getStyle();
|
public LineStyle getStyle();
|
||||||
|
|
||||||
public AggregatedData getAggregatedData();
|
public AggregatedDataCollection getAggregatedData();
|
||||||
|
|
||||||
public static Map<String, Integer> toMap(final List<DataSeries> dataSeries) {
|
public static Map<String, Integer> toMap(final List<DataSeries> dataSeries) {
|
||||||
final Map<String, Integer> result = new LinkedHashMap<>();
|
final Map<String, Integer> result = new LinkedHashMap<>();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.lucares.recommind.logs;
|
package org.lucares.recommind.logs;
|
||||||
|
|
||||||
import org.lucares.pdb.plot.api.AggregatedData;
|
import org.lucares.pdb.plot.api.AggregatedDataCollection;
|
||||||
|
|
||||||
public class FileBackedDataSeries implements DataSeries {
|
public class FileBackedDataSeries implements DataSeries {
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ public class FileBackedDataSeries implements DataSeries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AggregatedData getAggregatedData() {
|
public AggregatedDataCollection getAggregatedData() {
|
||||||
return csvSummary.getAggregatedData();
|
return csvSummary.getAggregatedData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class GnuplotFileGenerator {
|
|||||||
|
|
||||||
appendfln(result, "set datafile separator \"%s\"", settings.getDatafileSeparator());
|
appendfln(result, "set datafile separator \"%s\"", settings.getDatafileSeparator());
|
||||||
|
|
||||||
settings.getAggregate().addGnuplotDefinitions(result, settings.getDatafileSeparator(), dataSeries);
|
settings.getAggregates().addGnuplotDefinitions(result, settings.getDatafileSeparator(), dataSeries);
|
||||||
|
|
||||||
appendfln(result, "set timefmt '%s'", settings.getTimefmt());
|
appendfln(result, "set timefmt '%s'", settings.getTimefmt());
|
||||||
|
|
||||||
@@ -103,9 +103,7 @@ public class GnuplotFileGenerator {
|
|||||||
|
|
||||||
appendf(result, "plot ");
|
appendf(result, "plot ");
|
||||||
|
|
||||||
settings.getAggregate().addPlotsBeforeScatter(result, dataSeries);
|
settings.getAggregates().addPlots(result, dataSeries);
|
||||||
|
|
||||||
settings.getAggregate().addPlotsAfterScatter(result, dataSeries);
|
|
||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.lucares.recommind.logs;
|
|||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import org.lucares.pdb.plot.api.AggregateHandler;
|
import org.lucares.pdb.plot.api.AggregateHandlerCollection;
|
||||||
import org.lucares.pdb.plot.api.AxisScale;
|
import org.lucares.pdb.plot.api.AxisScale;
|
||||||
|
|
||||||
public class GnuplotSettings {
|
public class GnuplotSettings {
|
||||||
@@ -26,7 +26,7 @@ public class GnuplotSettings {
|
|||||||
private final Path output;
|
private final Path output;
|
||||||
|
|
||||||
private AxisScale yAxisScale;
|
private AxisScale yAxisScale;
|
||||||
private AggregateHandler aggregate;
|
private AggregateHandlerCollection aggregates;
|
||||||
private boolean keyOutside = false;
|
private boolean keyOutside = false;
|
||||||
|
|
||||||
private XAxisSettings xAxisSettings = new XAxisSettings();
|
private XAxisSettings xAxisSettings = new XAxisSettings();
|
||||||
@@ -98,12 +98,12 @@ public class GnuplotSettings {
|
|||||||
return yAxisScale;
|
return yAxisScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAggregate(final AggregateHandler aggregate) {
|
public void setAggregates(final AggregateHandlerCollection aggregates) {
|
||||||
this.aggregate = aggregate;
|
this.aggregates = aggregates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AggregateHandler getAggregate() {
|
public AggregateHandlerCollection getAggregates() {
|
||||||
return aggregate;
|
return aggregates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKeyOutside(final boolean keyOutside) {
|
public void setKeyOutside(final boolean keyOutside) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.lucares.pdb.api.GroupResult;
|
|||||||
import org.lucares.pdb.api.Query;
|
import org.lucares.pdb.api.Query;
|
||||||
import org.lucares.pdb.api.Result;
|
import org.lucares.pdb.api.Result;
|
||||||
import org.lucares.pdb.api.Tags;
|
import org.lucares.pdb.api.Tags;
|
||||||
import org.lucares.pdb.plot.api.CustomAggregator;
|
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.TimeRangeUnitInternal;
|
import org.lucares.pdb.plot.api.TimeRangeUnitInternal;
|
||||||
@@ -115,7 +115,7 @@ public class Plotter {
|
|||||||
defineXAxis(gnuplotSettings, plotSettings.dateRange());
|
defineXAxis(gnuplotSettings, plotSettings.dateRange());
|
||||||
|
|
||||||
gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale());
|
gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale());
|
||||||
gnuplotSettings.setAggregate(plotSettings.getAggregate());
|
gnuplotSettings.setAggregates(plotSettings.getAggregates());
|
||||||
defineYRange(gnuplotSettings, plotSettings.getYRangeMin(), plotSettings.getYRangeMax(),
|
defineYRange(gnuplotSettings, plotSettings.getYRangeMin(), plotSettings.getYRangeMax(),
|
||||||
plotSettings.getYRangeUnit());
|
plotSettings.getYRangeUnit());
|
||||||
gnuplotSettings.setKeyOutside(plotSettings.isKeyOutside());
|
gnuplotSettings.setKeyOutside(plotSettings.isKeyOutside());
|
||||||
@@ -132,7 +132,7 @@ public class Plotter {
|
|||||||
defineXAxis(gnuplotSettings, plotSettings.dateRange());
|
defineXAxis(gnuplotSettings, plotSettings.dateRange());
|
||||||
|
|
||||||
gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale());
|
gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale());
|
||||||
gnuplotSettings.setAggregate(plotSettings.getAggregate());
|
gnuplotSettings.setAggregates(plotSettings.getAggregates());
|
||||||
defineYRange(gnuplotSettings, plotSettings.getYRangeMin(), plotSettings.getYRangeMax(),
|
defineYRange(gnuplotSettings, plotSettings.getYRangeMin(), plotSettings.getYRangeMax(),
|
||||||
plotSettings.getYRangeUnit());
|
plotSettings.getYRangeUnit());
|
||||||
gnuplotSettings.setKeyOutside(false);
|
gnuplotSettings.setKeyOutside(false);
|
||||||
@@ -205,7 +205,7 @@ public class Plotter {
|
|||||||
final long maxValue = plotSettings.getYRangeUnit() == TimeRangeUnitInternal.AUTOMATIC ? Long.MAX_VALUE
|
final long maxValue = plotSettings.getYRangeUnit() == TimeRangeUnitInternal.AUTOMATIC ? Long.MAX_VALUE
|
||||||
: plotSettings.getYRangeUnit().toMilliSeconds(plotSettings.getYRangeMax());
|
: plotSettings.getYRangeUnit().toMilliSeconds(plotSettings.getYRangeMax());
|
||||||
|
|
||||||
final CustomAggregator aggregator = plotSettings.getAggregate().createCustomAggregator(tmpDir, plotSettings, fromEpochMilli,
|
final AggregatorCollection aggregator = plotSettings.getAggregates().createCustomAggregator(tmpDir, plotSettings, fromEpochMilli,
|
||||||
toEpochMilli);
|
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)
|
||||||
@@ -228,8 +228,6 @@ public class Plotter {
|
|||||||
|
|
||||||
final long value = entry.get(i + 1);
|
final long value = entry.get(i + 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// compute stats
|
// compute stats
|
||||||
count++;
|
count++;
|
||||||
statsMaxValue = Math.max(statsMaxValue, value);
|
statsMaxValue = Math.max(statsMaxValue, value);
|
||||||
@@ -293,7 +291,5 @@ public class Plotter {
|
|||||||
result.append(")");
|
result.append(")");
|
||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -20,10 +21,10 @@ 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.AxisScale;
|
||||||
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.pdbui.domain.Aggregate;
|
|
||||||
import org.lucares.pdbui.domain.AutocompleteProposal;
|
import org.lucares.pdbui.domain.AutocompleteProposal;
|
||||||
import org.lucares.pdbui.domain.AutocompleteProposalByValue;
|
import org.lucares.pdbui.domain.AutocompleteProposalByValue;
|
||||||
import org.lucares.pdbui.domain.AutocompleteResponse;
|
import org.lucares.pdbui.domain.AutocompleteResponse;
|
||||||
@@ -158,7 +159,7 @@ public class PdbController implements HardcodedValues, PropertyKeys {
|
|||||||
@RequestParam(name = "limitBy.selected", defaultValue = "NO_LIMIT") final Limit limitBy,
|
@RequestParam(name = "limitBy.selected", defaultValue = "NO_LIMIT") final Limit limitBy,
|
||||||
@RequestParam(name = "dateRange") final String dateRange,
|
@RequestParam(name = "dateRange") final String dateRange,
|
||||||
@RequestParam(name = "axisScale", defaultValue = "LINEAR") final AxisScale axisScale,
|
@RequestParam(name = "axisScale", defaultValue = "LINEAR") final AxisScale axisScale,
|
||||||
@RequestParam(name = "aggregate", defaultValue = "NONE") final Aggregate aggregate,
|
@RequestParam(name = "aggregates") final EnumSet<Aggregate>aggregate,
|
||||||
@RequestParam(name = "keyOutside", defaultValue = "false") final boolean keyOutside,
|
@RequestParam(name = "keyOutside", defaultValue = "false") final boolean keyOutside,
|
||||||
@RequestParam(name = "width", defaultValue = "1920") final int hidth,
|
@RequestParam(name = "width", defaultValue = "1920") final int hidth,
|
||||||
@RequestParam(name = "height", defaultValue = "1080") final int height) {
|
@RequestParam(name = "height", defaultValue = "1080") final int height) {
|
||||||
@@ -181,7 +182,7 @@ public class PdbController implements HardcodedValues, PropertyKeys {
|
|||||||
plotSettings.setLimitBy(limitBy);
|
plotSettings.setLimitBy(limitBy);
|
||||||
plotSettings.setDateRange(dateRange);
|
plotSettings.setDateRange(dateRange);
|
||||||
plotSettings.setYAxisScale(axisScale);
|
plotSettings.setYAxisScale(axisScale);
|
||||||
plotSettings.setAggregate(PlotSettingsTransformer.toAggregateInternal(aggregate));
|
plotSettings.setAggregates(PlotSettingsTransformer.toAggregateInternal(aggregate));
|
||||||
plotSettings.setKeyOutside(keyOutside);
|
plotSettings.setKeyOutside(keyOutside);
|
||||||
plotSettings.setGenerateThumbnail(false);
|
plotSettings.setGenerateThumbnail(false);
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package org.lucares.pdbui;
|
package org.lucares.pdbui;
|
||||||
|
|
||||||
import org.lucares.pdb.plot.api.AggregateHandler;
|
import org.lucares.pdb.plot.api.Aggregate;
|
||||||
import org.lucares.pdb.plot.api.NullAggregate;
|
import org.lucares.pdb.plot.api.AggregateHandlerCollection;
|
||||||
import org.lucares.pdb.plot.api.ParallelRequestsAggregate;
|
|
||||||
import org.lucares.pdb.plot.api.CumulativeDistributionHandler;
|
import org.lucares.pdb.plot.api.CumulativeDistributionHandler;
|
||||||
|
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.TimeRangeUnitInternal;
|
import org.lucares.pdb.plot.api.TimeRangeUnitInternal;
|
||||||
import org.lucares.pdbui.domain.Aggregate;
|
|
||||||
import org.lucares.pdbui.domain.PlotRequest;
|
import org.lucares.pdbui.domain.PlotRequest;
|
||||||
import org.lucares.pdbui.domain.TimeRangeUnit;
|
import org.lucares.pdbui.domain.TimeRangeUnit;
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ class PlotSettingsTransformer {
|
|||||||
result.setLimitBy(request.getLimitBy());
|
result.setLimitBy(request.getLimitBy());
|
||||||
result.setDateRange(request.getDateRange());
|
result.setDateRange(request.getDateRange());
|
||||||
result.setYAxisScale(request.getAxisScale());
|
result.setYAxisScale(request.getAxisScale());
|
||||||
result.setAggregate(toAggregateInternal(request.getAggregate()));
|
result.setAggregates(toAggregateInternal(request.getAggregates()));
|
||||||
result.setKeyOutside(request.isKeyOutside());
|
result.setKeyOutside(request.isKeyOutside());
|
||||||
result.setThumbnailMaxWidth(request.getThumbnailMaxWidth());
|
result.setThumbnailMaxWidth(request.getThumbnailMaxWidth());
|
||||||
result.setThumbnailMaxHeight(request.getThumbnailMaxHeight());
|
result.setThumbnailMaxHeight(request.getThumbnailMaxHeight());
|
||||||
@@ -54,17 +53,26 @@ class PlotSettingsTransformer {
|
|||||||
throw new IllegalStateException("unhandled enum value: " + yRangeUnit);
|
throw new IllegalStateException("unhandled enum value: " + yRangeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AggregateHandler toAggregateInternal(final Aggregate aggregate) {
|
static AggregateHandlerCollection toAggregateInternal(final Iterable<Aggregate> aggregates) {
|
||||||
|
final AggregateHandlerCollection aggregateHandlerCollection = new AggregateHandlerCollection();
|
||||||
|
|
||||||
|
for (Aggregate aggregate : aggregates) {
|
||||||
|
|
||||||
switch (aggregate) {
|
switch (aggregate) {
|
||||||
case NONE:
|
|
||||||
return new NullAggregate();
|
|
||||||
case CUM_DISTRIBUTION:
|
case CUM_DISTRIBUTION:
|
||||||
return new CumulativeDistributionHandler();
|
aggregateHandlerCollection.add(new CumulativeDistributionHandler());
|
||||||
|
break;
|
||||||
case PARALLEL:
|
case PARALLEL:
|
||||||
return new ParallelRequestsAggregate();
|
aggregateHandlerCollection.add(new ParallelRequestsAggregate());
|
||||||
|
break;
|
||||||
case SCATTER:
|
case SCATTER:
|
||||||
return new ScatterAggregateHandler();
|
aggregateHandlerCollection.add(new ScatterAggregateHandler());
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
throw new IllegalStateException("unhandled enum: " + aggregate);
|
throw new IllegalStateException("unhandled enum: " + aggregate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aggregateHandlerCollection;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package org.lucares.pdbui.domain;
|
package org.lucares.pdbui.domain;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.lucares.pdb.plot.api.Aggregate;
|
||||||
import org.lucares.pdb.plot.api.AxisScale;
|
import org.lucares.pdb.plot.api.AxisScale;
|
||||||
import org.lucares.pdb.plot.api.Limit;
|
import org.lucares.pdb.plot.api.Limit;
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ public class PlotRequest {
|
|||||||
|
|
||||||
private String dateRange;
|
private String dateRange;
|
||||||
|
|
||||||
private Aggregate aggregate = Aggregate.NONE;
|
private List<Aggregate> aggregates = new ArrayList<>();
|
||||||
|
|
||||||
private int yRangeMin;
|
private int yRangeMin;
|
||||||
private int yRangeMax;
|
private int yRangeMax;
|
||||||
@@ -121,12 +123,12 @@ public class PlotRequest {
|
|||||||
this.yAxis = yAxis;
|
this.yAxis = yAxis;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAggregate(final Aggregate aggregate) {
|
public void setAggregate(final List<Aggregate> aggregates) {
|
||||||
this.aggregate = aggregate;
|
this.aggregates = aggregates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Aggregate getAggregate() {
|
public List<Aggregate> getAggregates() {
|
||||||
return aggregate;
|
return aggregates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKeyOutside(final boolean keyOutside) {
|
public void setKeyOutside(final boolean keyOutside) {
|
||||||
|
|||||||
@@ -780,7 +780,7 @@ Vue.component('search-bar', {
|
|||||||
|
|
||||||
<div class="group" id="group-show-aggregate">
|
<div class="group" id="group-show-aggregate">
|
||||||
<label for="show-aggregate">X2-Axis:</label>
|
<label for="show-aggregate">X2-Axis:</label>
|
||||||
<select id="show-aggregate" v-model="searchBar.aggregate">
|
<select id="show-aggregate" v-model="searchBar.aggregate" multiple>
|
||||||
<option value="NONE">-</option>
|
<option value="NONE">-</option>
|
||||||
<option value="CUM_DISTRIBUTION" title="cumulative distribution, see https://serialmentor.com/dataviz/ecdf-qq.html">cum. distribution</option>
|
<option value="CUM_DISTRIBUTION" title="cumulative distribution, see https://serialmentor.com/dataviz/ecdf-qq.html">cum. distribution</option>
|
||||||
<option value="PARALLEL">parallel requests</option>
|
<option value="PARALLEL">parallel requests</option>
|
||||||
|
|||||||
Reference in New Issue
Block a user