In numeric range facets, show the other choices only if they have positive counts in the base distribution.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@445 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-04-11 08:19:05 +00:00
parent 5928a689e2
commit 75ea8304a3
4 changed files with 194 additions and 52 deletions

View File

@ -32,6 +32,14 @@ public class ExpressionNumericRowBinner implements RowVisitor {
public int blankCount; public int blankCount;
public int errorCount; public int errorCount;
/*
* Scratchpad variables
*/
private boolean rowHasError;
private boolean rowHasBlank;
private boolean rowHasNumeric;
private boolean rowHasNonNumeric;
public ExpressionNumericRowBinner(Evaluable evaluable, String columnName, int cellIndex, NumericBinIndex index) { public ExpressionNumericRowBinner(Evaluable evaluable, String columnName, int cellIndex, NumericBinIndex index) {
_evaluable = evaluable; _evaluable = evaluable;
_columnName = columnName; _columnName = columnName;
@ -47,45 +55,70 @@ public class ExpressionNumericRowBinner implements RowVisitor {
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell); ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
Object value = _evaluable.evaluate(bindings); Object value = _evaluable.evaluate(bindings);
rowHasError = false;
rowHasBlank = false;
rowHasNumeric = false;
rowHasNonNumeric = false;
if (value != null) { if (value != null) {
if (value.getClass().isArray()) { if (value.getClass().isArray()) {
Object[] a = (Object[]) value; Object[] a = (Object[]) value;
for (Object v : a) { for (Object v : a) {
processValue(v); processValue(v);
} }
updateCounts();
return false; return false;
} else if (value instanceof Collection<?>) { } else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) { for (Object v : ExpressionUtils.toObjectCollection(value)) {
processValue(v); processValue(v);
} }
updateCounts();
return false; return false;
} // else, fall through } // else, fall through
} }
processValue(value); processValue(value);
updateCounts();
return false; return false;
} }
protected void updateCounts() {
if (rowHasError) {
errorCount++;
}
if (rowHasBlank) {
blankCount++;
}
if (rowHasNumeric) {
numericCount++;
}
if (rowHasNonNumeric) {
nonNumericCount++;
}
}
protected void processValue(Object value) { protected void processValue(Object value) {
if (ExpressionUtils.isError(value)) { if (ExpressionUtils.isError(value)) {
errorCount++; rowHasError = true;
} else if (ExpressionUtils.isNonBlankData(value)) { } else if (ExpressionUtils.isNonBlankData(value)) {
if (value instanceof Number) { if (value instanceof Number) {
double d = ((Number) value).doubleValue(); double d = ((Number) value).doubleValue();
if (!Double.isInfinite(d) && !Double.isNaN(d)) { if (!Double.isInfinite(d) && !Double.isNaN(d)) {
numericCount++; rowHasNumeric = true;
int bin = (int) Math.floor((d - _index.getMin()) / _index.getStep()); int bin = (int) Math.floor((d - _index.getMin()) / _index.getStep());
bins[bin]++; bins[bin]++;
} else { } else {
errorCount++; rowHasError = true;
} }
} else { } else {
nonNumericCount++; rowHasNonNumeric = true;
} }
} else { } else {
blankCount++; rowHasBlank = true;
} }
} }
} }

View File

@ -23,13 +23,18 @@ import com.metaweb.gridworks.model.Row;
*/ */
public class NumericBinIndex { public class NumericBinIndex {
private int _total_count; private int _totalValueCount;
private int _number_count; private int _numbericValueCount;
private double _min; private double _min;
private double _max; private double _max;
private double _step; private double _step;
private int[] _bins; private int[] _bins;
private int _numericRowCount;
private int _nonNumericRowCount;
private int _blankRowCount;
private int _errorRowCount;
public NumericBinIndex(Project project, String columnName, int cellIndex, Evaluable eval) { public NumericBinIndex(Project project, String columnName, int cellIndex, Evaluable eval) {
Properties bindings = ExpressionUtils.createBindings(project); Properties bindings = ExpressionUtils.createBindings(project);
@ -44,32 +49,79 @@ public class NumericBinIndex {
ExpressionUtils.bind(bindings, row, i, columnName, cell); ExpressionUtils.bind(bindings, row, i, columnName, cell);
Object value = eval.evaluate(bindings); Object value = eval.evaluate(bindings);
if (value != null) {
boolean rowHasError = false;
boolean rowHasNonNumeric = false;
boolean rowHasNumeric = false;
boolean rowHasBlank = false;
if (ExpressionUtils.isError(value)) {
rowHasError = true;
} else if (ExpressionUtils.isNonBlankData(value)) {
if (value.getClass().isArray()) { if (value.getClass().isArray()) {
Object[] a = (Object[]) value; Object[] a = (Object[]) value;
for (Object v : a) { for (Object v : a) {
_total_count++; _totalValueCount++;
if (v instanceof Number) {
processValue(((Number) v).doubleValue(), allValues); if (ExpressionUtils.isError(v)) {
rowHasError = true;
} else if (ExpressionUtils.isNonBlankData(v)) {
if (v instanceof Number) {
rowHasNumeric = true;
processValue(((Number) v).doubleValue(), allValues);
} else {
rowHasNonNumeric = true;
}
} else {
rowHasBlank = true;
} }
} }
} else if (value instanceof Collection<?>) { } else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) { for (Object v : ExpressionUtils.toObjectCollection(value)) {
_total_count++; _totalValueCount++;
if (v instanceof Number) {
processValue(((Number) v).doubleValue(), allValues); if (ExpressionUtils.isError(v)) {
rowHasError = true;
} else if (ExpressionUtils.isNonBlankData(v)) {
if (v instanceof Number) {
rowHasNumeric = true;
processValue(((Number) v).doubleValue(), allValues);
} else {
rowHasNonNumeric = true;
}
} else {
rowHasBlank = true;
} }
} }
} else { } else {
_total_count++; _totalValueCount++;
if (value instanceof Number) { if (value instanceof Number) {
rowHasNumeric = true;
processValue(((Number) value).doubleValue(), allValues); processValue(((Number) value).doubleValue(), allValues);
} else {
rowHasNonNumeric = true;
} }
} }
} else {
rowHasBlank = true;
}
if (rowHasError) {
_errorRowCount++;
}
if (rowHasBlank) {
_blankRowCount++;
}
if (rowHasNumeric) {
_numericRowCount++;
}
if (rowHasNonNumeric) {
_nonNumericRowCount++;
} }
} }
_number_count = allValues.size(); _numbericValueCount = allValues.size();
if (_min >= _max) { if (_min >= _max) {
_step = 1; _step = 1;
@ -116,11 +168,7 @@ public class NumericBinIndex {
} }
public boolean isNumeric() { public boolean isNumeric() {
return _number_count > _total_count / 2; return _numbericValueCount > _totalValueCount / 2;
}
public int getNumberCount() {
return _number_count;
} }
public double getMin() { public double getMin() {
@ -138,6 +186,22 @@ public class NumericBinIndex {
public int[] getBins() { public int[] getBins() {
return _bins; return _bins;
} }
public int getNumericRowCount() {
return _numericRowCount;
}
public int getNonNumericRowCount() {
return _nonNumericRowCount;
}
public int getBlankRowCount() {
return _blankRowCount;
}
public int getErrorRowCount() {
return _errorRowCount;
}
protected void processValue(double v, List<Double> allValues) { protected void processValue(double v, List<Double> allValues) {
if (!Double.isInfinite(v) && !Double.isNaN(v)) { if (!Double.isInfinite(v) && !Double.isNaN(v)) {
@ -146,4 +210,5 @@ public class NumericBinIndex {
allValues.add(v); allValues.add(v);
} }
} }
} }

View File

@ -51,6 +51,11 @@ public class RangeFacet implements Facet {
protected int[] _baseBins; protected int[] _baseBins;
protected int[] _bins; protected int[] _bins;
protected int _baseNumericCount;
protected int _baseNonNumericCount;
protected int _baseBlankCount;
protected int _baseErrorCount;
protected int _numericCount; protected int _numericCount;
protected int _nonNumericCount; protected int _nonNumericCount;
protected int _blankCount; protected int _blankCount;
@ -103,6 +108,11 @@ public class RangeFacet implements Facet {
} }
} }
writer.key("baseNumericCount"); writer.value(_baseNumericCount);
writer.key("baseNonNumericCount"); writer.value(_baseNonNumericCount);
writer.key("baseBlankCount"); writer.value(_baseBlankCount);
writer.key("baseErrorCount"); writer.value(_baseErrorCount);
writer.key("numericCount"); writer.value(_numericCount); writer.key("numericCount"); writer.value(_numericCount);
writer.key("nonNumericCount"); writer.value(_nonNumericCount); writer.key("nonNumericCount"); writer.value(_nonNumericCount);
writer.key("blankCount"); writer.value(_blankCount); writer.key("blankCount"); writer.value(_blankCount);
@ -210,6 +220,11 @@ public class RangeFacet implements Facet {
_step = index.getStep(); _step = index.getStep();
_baseBins = index.getBins(); _baseBins = index.getBins();
_baseNumericCount = index.getNumericRowCount();
_baseNonNumericCount = index.getNonNumericRowCount();
_baseBlankCount = index.getBlankRowCount();
_baseErrorCount = index.getErrorRowCount();
if (_selected) { if (_selected) {
_from = Math.max(_from, _min); _from = Math.max(_from, _min);
_to = Math.min(_to, _max); _to = Math.min(_to, _max);

View File

@ -11,6 +11,11 @@ function RangeFacet(div, config, options) {
this._selectBlank = ("selectBlank" in this._config) ? this._config.selectBlank : true; this._selectBlank = ("selectBlank" in this._config) ? this._config.selectBlank : true;
this._selectError = ("selectError" in this._config) ? this._config.selectError : true; this._selectError = ("selectError" in this._config) ? this._config.selectError : true;
this._baseNumericCount = 0;
this._baseNonNumericCount = 0;
this._baseBlankCount = 0;
this._baseErrorCount = 0;
this._numericCount = 0; this._numericCount = 0;
this._nonNumericCount = 0; this._nonNumericCount = 0;
this._blankCount = 0; this._blankCount = 0;
@ -177,6 +182,10 @@ RangeFacet.prototype._renderOtherChoices = function() {
var self = this; var self = this;
var container = this._otherChoicesDiv.empty(); var container = this._otherChoicesDiv.empty();
if (this._baseNonNumericCount === 0 && this._baseBlankCount === 0 && this._baseErrorCount === 0) {
return;
}
var table = $('<table>').attr("cellpadding", "0").attr("cellspacing", "1").css("white-space", "pre").appendTo(container)[0]; var table = $('<table>').attr("cellpadding", "0").attr("cellspacing", "1").css("white-space", "pre").appendTo(container)[0];
var tr0 = table.insertRow(0); var tr0 = table.insertRow(0);
var tr1 = table.insertRow(1); var tr1 = table.insertRow(1);
@ -185,6 +194,8 @@ RangeFacet.prototype._renderOtherChoices = function() {
* Numeric * Numeric
*/ */
var td00 = $(tr0.insertCell(0)).attr("width", "1%"); var td00 = $(tr0.insertCell(0)).attr("width", "1%");
var td01 = $(tr0.insertCell(1));
var numericCheck = $('<input type="checkbox" />').appendTo(td00).change(function() { var numericCheck = $('<input type="checkbox" />').appendTo(td00).change(function() {
self._selectNumeric = !self._selectNumeric; self._selectNumeric = !self._selectNumeric;
self._updateRest(); self._updateRest();
@ -193,7 +204,6 @@ RangeFacet.prototype._renderOtherChoices = function() {
numericCheck[0].checked = true; numericCheck[0].checked = true;
} }
var td01 = $(tr0.insertCell(1));
$('<span>').text("Numeric ").addClass("facet-choice-label").appendTo(td01); $('<span>').text("Numeric ").addClass("facet-choice-label").appendTo(td01);
$('<span>').text(this._numericCount).addClass("facet-choice-count").appendTo(td01); $('<span>').text(this._numericCount).addClass("facet-choice-count").appendTo(td01);
@ -201,50 +211,64 @@ RangeFacet.prototype._renderOtherChoices = function() {
* Blank * Blank
*/ */
var td02 = $(tr0.insertCell(2)).attr("width", "1%"); var td02 = $(tr0.insertCell(2)).attr("width", "1%");
var blankCheck = $('<input type="checkbox" />').appendTo(td02).change(function() {
self._selectBlank = !self._selectBlank;
self._updateRest();
});
if (this._selectBlank) {
blankCheck[0].checked = true;
}
var td03 = $(tr0.insertCell(3)); var td03 = $(tr0.insertCell(3));
$('<span>').text("Blank ").addClass("facet-choice-label").appendTo(td03); if (this._baseBlankCount === 0) {
$('<span>').text(this._blankCount).addClass("facet-choice-count").appendTo(td03); td02.hide();
td03.hide();
} else {
var blankCheck = $('<input type="checkbox" />').appendTo(td02).change(function() {
self._selectBlank = !self._selectBlank;
self._updateRest();
});
if (this._selectBlank) {
blankCheck[0].checked = true;
}
$('<span>').text("Blank ").addClass("facet-choice-label").appendTo(td03);
$('<span>').text(this._blankCount).addClass("facet-choice-count").appendTo(td03);
}
/* /*
* Non-Numeric * Non-Numeric
*/ */
var td10 = $(tr1.insertCell(0)).attr("width", "1%"); var td10 = $(tr1.insertCell(0)).attr("width", "1%");
var nonNumericCheck = $('<input type="checkbox" />').appendTo(td10).change(function() {
self._selectNonNumeric = !self._selectNonNumeric;
self._updateRest();
});
if (this._selectNonNumeric) {
nonNumericCheck[0].checked = true;
}
var td11 = $(tr1.insertCell(1)); var td11 = $(tr1.insertCell(1));
$('<span>').text("Non-numeric ").addClass("facet-choice-label").appendTo(td11); if (this._baseNonNumericCount === 0) {
$('<span>').text(this._nonNumericCount).addClass("facet-choice-count").appendTo(td11); td10.hide();
td11.hide();
} else {
var nonNumericCheck = $('<input type="checkbox" />').appendTo(td10).change(function() {
self._selectNonNumeric = !self._selectNonNumeric;
self._updateRest();
});
if (this._selectNonNumeric) {
nonNumericCheck[0].checked = true;
}
$('<span>').text("Non-numeric ").addClass("facet-choice-label").appendTo(td11);
$('<span>').text(this._nonNumericCount).addClass("facet-choice-count").appendTo(td11);
}
/* /*
* Error * Error
*/ */
var td12 = $(tr1.insertCell(2)).attr("width", "1%"); var td12 = $(tr1.insertCell(2)).attr("width", "1%");
var errorCheck = $('<input type="checkbox" />').appendTo(td12).change(function() {
self._selectError = !self._selectError;
self._updateRest();
});
if (this._selectError) {
errorCheck[0].checked = true;
}
var td13 = $(tr1.insertCell(3)); var td13 = $(tr1.insertCell(3));
$('<span>').text("Error ").addClass("facet-choice-label").appendTo(td13); if (this._baseErrorCount === 0) {
$('<span>').text(this._errorCount).addClass("facet-choice-count").appendTo(td13); td12.hide();
td13.hide();
} else {
var errorCheck = $('<input type="checkbox" />').appendTo(td12).change(function() {
self._selectError = !self._selectError;
self._updateRest();
});
if (this._selectError) {
errorCheck[0].checked = true;
}
$('<span>').text("Error ").addClass("facet-choice-label").appendTo(td13);
$('<span>').text(this._errorCount).addClass("facet-choice-count").appendTo(td13);
}
}; };
RangeFacet.prototype._setRangeIndicators = function() { RangeFacet.prototype._setRangeIndicators = function() {
@ -290,6 +314,11 @@ RangeFacet.prototype.updateState = function(data) {
} }
} }
this._baseNumericCount = data.baseNumericCount;
this._baseNonNumericCount = data.baseNonNumericCount;
this._baseBlankCount = data.baseBlankCount;
this._baseErrorCount = data.baseErrorCount;
this._numericCount = data.numericCount; this._numericCount = data.numericCount;
this._nonNumericCount = data.nonNumericCount; this._nonNumericCount = data.nonNumericCount;
this._blankCount = data.blankCount; this._blankCount = data.blankCount;