make it possible to render any combination of plots

This commit is contained in:
2019-10-20 10:16:25 +02:00
parent b7c4fe4c1f
commit f28a67a5c1
26 changed files with 321 additions and 243 deletions

View File

@@ -1,5 +0,0 @@
package org.lucares.pdb.plot.api;
public enum AggreateInternal {
NONE, MEAN, PERCENTILE95, PERCENTILE99, PERCENTILE999
}

View File

@@ -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,

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -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));
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
} }

View File

@@ -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;
} }
} }

View File

@@ -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();
} }

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
} }

View File

@@ -93,4 +93,9 @@ public class ParallelRequestsAggregator implements CustomAggregator {
builder.append(NEWLINE); builder.append(NEWLINE);
} }
@Override
public Aggregate getType() {
return Aggregate.PARALLEL;
}
} }

View File

@@ -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) {

View File

@@ -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;
}
} }

View File

@@ -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;
}
} }

View File

@@ -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;
} }
} }

View File

@@ -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<>();

View File

@@ -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();
} }
} }

View File

@@ -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();
} }

View File

@@ -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) {

View File

@@ -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();
} }
} }

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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) {

View File

@@ -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>