range definitions for the y-axis

Sometimes it is useful to specify the certain y-axis range. For example
when you are only interested in the values that take longer than a
threshold. Or when you want to exclude some outliers. When you want to
compare plots in a gallery, it is very handy when all plots have the
same data-area.
This commit is contained in:
2018-05-01 10:18:06 +02:00
parent 54ee23459d
commit 6d85c56cb0
10 changed files with 180 additions and 28 deletions

View File

@@ -72,9 +72,7 @@ public class QueryCompletionPdbLangParser extends PdbLangParser {
int count = 0; int count = 0;
try { try {
count = dataStore.count(p.getProposedQuery()); count = dataStore.count(p.getProposedQuery());
} } catch (final SyntaxException e) {
catch(SyntaxException e)
{
// ignore: if the query is not valid, then it does not find any results // ignore: if the query is not valid, then it does not find any results
} }
return new Proposal(p, count > 0); return new Proposal(p, count > 0);
@@ -139,23 +137,7 @@ public class QueryCompletionPdbLangParser extends PdbLangParser {
return new Proposal(key, String.format(newQueryPattern, key + "=* "), true, newQuery, return new Proposal(key, String.format(newQueryPattern, key + "=* "), true, newQuery,
newCaretPosition); newCaretPosition);
}) }).forEach(proposals::add);
// .map(p -> {
//
// final String proposedQuery = p.getProposedQuery();
// final int count = count(proposedQuery);
// return new Proposal(p, count > 0);
// })
.forEach(proposals::add);
}
private int count(final String proposedQuery) {
try {
return dataStore.count(proposedQuery);
} catch (final SyntaxException e) {
return -1;
}
} }
private boolean isEOF(final Object offendingSymbol) { private boolean isEOF(final Object offendingSymbol) {

View File

@@ -38,6 +38,10 @@ public class PlotSettings {
private AggregateHandler aggregate; private AggregateHandler aggregate;
private int yRangeMin;
private int yRangeMax;
private TimeRangeUnitInternal yRangeUnit = TimeRangeUnitInternal.AUTOMATIC;
private boolean keyOutside; private boolean keyOutside;
private boolean generateThumbnail; private boolean generateThumbnail;
@@ -183,7 +187,9 @@ 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 + ", dateFrom=" + dateFrom + ", dateRange=" + dateRange + ", limitBy=" + limitBy + ", limit=" + limit + ", dateFrom=" + dateFrom + ", dateRange=" + dateRange
+ ", yAxisScale=" + yAxisScale + ", aggregate=" + aggregate + ", keyOutside=" + keyOutside + "]"; + ", yAxisScale=" + yAxisScale + ", aggregate=" + aggregate + ", yRangeMin=" + yRangeMin
+ ", yRangeMax=" + yRangeMax + ", yRangeUnit=" + yRangeUnit + ", keyOutside=" + keyOutside
+ ", generateThumbnail=" + generateThumbnail + "]";
} }
public void setAggregate(final AggregateHandler aggregate) { public void setAggregate(final AggregateHandler aggregate) {
@@ -209,4 +215,29 @@ public class PlotSettings {
public boolean isGenerateThumbnail() { public boolean isGenerateThumbnail() {
return generateThumbnail; return generateThumbnail;
} }
public int getYRangeMin() {
return yRangeMin;
}
public void setYRangeMin(final int yRangeMin) {
this.yRangeMin = yRangeMin;
}
public int getYRangeMax() {
return yRangeMax;
}
public void setYRangeMax(final int yRangeMax) {
this.yRangeMax = yRangeMax;
}
public TimeRangeUnitInternal getYRangeUnit() {
return yRangeUnit;
}
public void setYRangeUnit(final TimeRangeUnitInternal yRangeUnit) {
this.yRangeUnit = yRangeUnit;
}
} }

View File

@@ -0,0 +1,24 @@
package org.lucares.pdb.plot.api;
public enum TimeRangeUnitInternal {
AUTOMATIC, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS;
public int toMilliSeconds(final int value) {
switch (this) {
case MILLISECONDS:
return value;
case SECONDS:
return value * 1000;
case MINUTES:
return value * 60 * 1000;
case HOURS:
return value * 60 * 60 * 1000;
case DAYS:
return value * 24 * 60 * 60 * 1000;
case AUTOMATIC:
return Integer.MAX_VALUE;
}
return Integer.MAX_VALUE;
}
}

View File

@@ -28,8 +28,14 @@ public class GnuplotFileGenerator {
appendfln(result, "set xlabel \"%s\"", xAxis.getXlabel()); appendfln(result, "set xlabel \"%s\"", xAxis.getXlabel());
appendfln(result, "set xrange [\"%s\":\"%s\"]", xAxis.getFrom(), xAxis.getTo()); appendfln(result, "set xrange [\"%s\":\"%s\"]", xAxis.getFrom(), xAxis.getTo());
final long graphOffset = settings.getYAxisScale() == AxisScale.LINEAR ? 0 : 1; final int graphOffset = settings.getYAxisScale() == AxisScale.LINEAR ? 0 : 1;
if (settings.hasYRange()) {
final int min = Math.max(settings.getYRangeMin(), graphOffset);
final int max = settings.getYRangeMax();
appendfln(result, String.format("set yrange [\"%d\":\"%d\"]", min, max));
} else {
appendfln(result, "set yrange [\"" + graphOffset + "\":]"); appendfln(result, "set yrange [\"" + graphOffset + "\":]");
}
appendfln(result, "set ylabel \"%s\"", settings.getYlabel()); appendfln(result, "set ylabel \"%s\"", settings.getYlabel());
switch (settings.getYAxisScale()) { switch (settings.getYAxisScale()) {

View File

@@ -26,6 +26,8 @@ public class GnuplotSettings {
private XAxisSettings xAxisSettings = new XAxisSettings(); private XAxisSettings xAxisSettings = new XAxisSettings();
private boolean renderLabels = true; private boolean renderLabels = true;
private int yRangeMin = -1;
private int yRangeMax = -1;
public GnuplotSettings(final Path output) { public GnuplotSettings(final Path output) {
this.output = output; this.output = output;
@@ -123,6 +125,23 @@ public class GnuplotSettings {
return renderLabels; return renderLabels;
} }
public boolean hasYRange() {
return yRangeMin >= 0 && yRangeMax >= 0 && yRangeMin < yRangeMax;
}
public void setYRange(final int yRangeMin, final int yRangeMax) {
this.yRangeMin = yRangeMin;
this.yRangeMax = yRangeMax;
}
public int getYRangeMin() {
return yRangeMin;
}
public int getYRangeMax() {
return yRangeMax;
}
// plot 'sample.txt' using 1:2 title 'Bytes' with linespoints 2 // plot 'sample.txt' using 1:2 title 'Bytes' with linespoints 2
} }

View File

@@ -30,6 +30,7 @@ import org.lucares.pdb.api.Tags;
import org.lucares.pdb.plot.api.CustomAggregator; import org.lucares.pdb.plot.api.CustomAggregator;
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.performance.db.PerformanceDb; import org.lucares.performance.db.PerformanceDb;
import org.lucares.utils.file.FileUtils; import org.lucares.utils.file.FileUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -120,6 +121,8 @@ public class ScatterPlot {
gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale()); gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale());
gnuplotSettings.setAggregate(plotSettings.getAggregate()); gnuplotSettings.setAggregate(plotSettings.getAggregate());
defineYRange(gnuplotSettings, plotSettings.getYRangeMin(), plotSettings.getYRangeMax(),
plotSettings.getYRangeUnit());
gnuplotSettings.setKeyOutside(plotSettings.isKeyOutside()); gnuplotSettings.setKeyOutside(plotSettings.isKeyOutside());
gnuplot.plot(gnuplotSettings, dataSeries); gnuplot.plot(gnuplotSettings, dataSeries);
} }
@@ -135,6 +138,8 @@ public class ScatterPlot {
gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale()); gnuplotSettings.setYAxisScale(plotSettings.getYAxisScale());
gnuplotSettings.setAggregate(plotSettings.getAggregate()); gnuplotSettings.setAggregate(plotSettings.getAggregate());
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);
@@ -154,6 +159,16 @@ public class ScatterPlot {
} }
} }
private void defineYRange(final GnuplotSettings gnuplotSettings, final int yRangeMin, final int yRangeMax,
final TimeRangeUnitInternal yRangeUnit) {
if (yRangeUnit != TimeRangeUnitInternal.AUTOMATIC) {
final int min = yRangeUnit.toMilliSeconds(yRangeMin);
final int max = yRangeUnit.toMilliSeconds(yRangeMax);
gnuplotSettings.setYRange(min, max);
}
}
private void defineXAxis(final GnuplotSettings gnuplotSettings, final OffsetDateTime minDate, private void defineXAxis(final GnuplotSettings gnuplotSettings, final OffsetDateTime minDate,
final OffsetDateTime maxDate) { final OffsetDateTime maxDate) {

View File

@@ -30,6 +30,10 @@ public class PlotRequest {
private Aggregate aggregate = Aggregate.NONE; private Aggregate aggregate = Aggregate.NONE;
private int yRangeMin;
private int yRangeMax;
private TimeRangeUnit yRangeUnit = TimeRangeUnit.AUTOMATIC;
private boolean keyOutside; private boolean keyOutside;
private boolean generateThumbnail; private boolean generateThumbnail;
@@ -154,4 +158,27 @@ public class PlotRequest {
this.generateThumbnail = generateThumbnail; this.generateThumbnail = generateThumbnail;
} }
public int getyRangeMin() {
return yRangeMin;
}
public void setyRangeMin(final int yRangeMin) {
this.yRangeMin = yRangeMin;
}
public int getyRangeMax() {
return yRangeMax;
}
public void setyRangeMax(final int yRangeMax) {
this.yRangeMax = yRangeMax;
}
public TimeRangeUnit getyRangeUnit() {
return yRangeUnit;
}
public void setyRangeUnit(final TimeRangeUnit yRangeUnit) {
this.yRangeUnit = yRangeUnit;
}
} }

View File

@@ -0,0 +1,5 @@
package org.lucares.pdbui.domain;
public enum TimeRangeUnit {
AUTOMATIC, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
}

View File

@@ -124,8 +124,8 @@ textarea {
background: lightgrey; background: lightgrey;
} }
#search-limit-value { .number-input-1k {
width: 4em; width: 3em;
} }
.input_date { .input_date {

View File

@@ -599,6 +599,9 @@ Vue.component('search-bar', {
'dateRange': data.searchBar.dateRange, 'dateRange': data.searchBar.dateRange,
'axisScale': data.searchBar.axisScale, 'axisScale': data.searchBar.axisScale,
'aggregate': data.searchBar.aggregate, 'aggregate': data.searchBar.aggregate,
'yRangeMin': data.searchBar.yRange.min,
'yRangeMax': data.searchBar.yRange.max,
'yRangeUnit': data.searchBar.yRange.unit,
'keyOutside': data.searchBar.keyOutside, 'keyOutside': data.searchBar.keyOutside,
}; };
@@ -641,8 +644,9 @@ Vue.component('search-bar', {
type="number" type="number"
id="search-limit-value" id="search-limit-value"
name="search-limit-value" name="search-limit-value"
class="number-input-1k"
min="1" min="1"
max="1000" max="999"
v-show="searchBar.limitBy.selected != 'NO_LIMIT'" v-show="searchBar.limitBy.selected != 'NO_LIMIT'"
v-model="searchBar.limitBy.number"/> v-model="searchBar.limitBy.number"/>
</div> </div>
@@ -695,6 +699,34 @@ Vue.component('search-bar', {
</select> </select>
</div> </div>
<div class="group">
<label for="y-max-value">Y-Range</label>
<input
v-show="searchBar.yRange.unit != 'AUTOMATIC'"
type="number"
id="y-range-min"
class="number-input-1k"
min="0"
max="999"
v-model="searchBar.yRange.min"/>
<input
v-show="searchBar.yRange.unit != 'AUTOMATIC'"
type="number"
id="y-range-max"
class="number-input-1k"
min="0"
max="999"
v-model="searchBar.yRange.max"/>
<select id="y-max-unit" v-model="searchBar.yRange.unit">
<option value="AUTOMATIC" title="adjust automatically">automatic</option>
<option value="MILLISECONDS" title="milli seconds">milli seconds</option>
<option value="SECONDS" title="seconds">seconds</option>
<option value="MINUTES" title="minutes">minutes</option>
<option value="HOURS" title="hours">hours</option>
<option value="DAYS" title="days">hours</option>
</select>
</div>
<div class="group"> <div class="group">
<input type="checkbox" id="key-outside" v-model="searchBar.keyOutside"/> <input type="checkbox" id="key-outside" v-model="searchBar.keyOutside"/>
<label for="key-outside">Legend outside</label> <label for="key-outside">Legend outside</label>
@@ -775,6 +807,11 @@ var data = {
dateRange: GetURLParameter('dateRange','1 week'), dateRange: GetURLParameter('dateRange','1 week'),
axisScale: GetURLParameter('axisScale','LOG10'), axisScale: GetURLParameter('axisScale','LOG10'),
aggregate: GetURLParameter('aggregate','NONE'), aggregate: GetURLParameter('aggregate','NONE'),
yRange: {
min: GetURLParameter('yRangeMin','0'),
max: GetURLParameter('yRangeMax','999'),
unit: GetURLParameter('yRangeUnit','AUTOMATIC')
},
keyOutside: GetURLParameterBoolean('keyOutside', 'false'), keyOutside: GetURLParameterBoolean('keyOutside', 'false'),
splitBy: { splitBy: {
@@ -879,6 +916,9 @@ function createRequest(query, generateThumbnail){
request['aggregate'] = data.searchBar.aggregate; request['aggregate'] = data.searchBar.aggregate;
request['keyOutside'] = data.searchBar.keyOutside; request['keyOutside'] = data.searchBar.keyOutside;
request['generateThumbnail'] = generateThumbnail; request['generateThumbnail'] = generateThumbnail;
request['yRangeMin'] = data.searchBar.yRange.min;
request['yRangeMax'] = data.searchBar.yRange.max;
request['yRangeUnit'] = data.searchBar.yRange.unit;
return request; return request;
} }
@@ -928,6 +968,9 @@ function updateImageLink(query) {
'dateRange': data.searchBar.dateRange, 'dateRange': data.searchBar.dateRange,
'axisScale': data.searchBar.axisScale, 'axisScale': data.searchBar.axisScale,
'aggregate': data.searchBar.aggregate, 'aggregate': data.searchBar.aggregate,
'yRangeMin': data.searchBar.yRange.min,
'yRangeMax': data.searchBar.yRange.max,
'yRangeUnit': data.searchBar.yRange.unit,
'keyOutside': data.searchBar.keyOutside, 'keyOutside': data.searchBar.keyOutside,
'width': Math.floor($('#result').width()), 'width': Math.floor($('#result').width()),
'height': Math.floor($('#result').height()) 'height': Math.floor($('#result').height())