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

View File

@ -23,13 +23,18 @@ import com.metaweb.gridworks.model.Row;
*/
public class NumericBinIndex {
private int _total_count;
private int _number_count;
private int _totalValueCount;
private int _numbericValueCount;
private double _min;
private double _max;
private double _step;
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) {
Properties bindings = ExpressionUtils.createBindings(project);
@ -44,32 +49,79 @@ public class NumericBinIndex {
ExpressionUtils.bind(bindings, row, i, columnName, cell);
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()) {
Object[] a = (Object[]) value;
for (Object v : a) {
_total_count++;
if (v instanceof Number) {
processValue(((Number) v).doubleValue(), allValues);
_totalValueCount++;
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<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
_total_count++;
if (v instanceof Number) {
processValue(((Number) v).doubleValue(), allValues);
_totalValueCount++;
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 {
_total_count++;
_totalValueCount++;
if (value instanceof Number) {
rowHasNumeric = true;
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) {
_step = 1;
@ -116,11 +168,7 @@ public class NumericBinIndex {
}
public boolean isNumeric() {
return _number_count > _total_count / 2;
}
public int getNumberCount() {
return _number_count;
return _numbericValueCount > _totalValueCount / 2;
}
public double getMin() {
@ -139,6 +187,22 @@ public class NumericBinIndex {
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) {
if (!Double.isInfinite(v) && !Double.isNaN(v)) {
_min = Math.min(_min, v);
@ -146,4 +210,5 @@ public class NumericBinIndex {
allValues.add(v);
}
}
}

View File

@ -51,6 +51,11 @@ public class RangeFacet implements Facet {
protected int[] _baseBins;
protected int[] _bins;
protected int _baseNumericCount;
protected int _baseNonNumericCount;
protected int _baseBlankCount;
protected int _baseErrorCount;
protected int _numericCount;
protected int _nonNumericCount;
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("nonNumericCount"); writer.value(_nonNumericCount);
writer.key("blankCount"); writer.value(_blankCount);
@ -210,6 +220,11 @@ public class RangeFacet implements Facet {
_step = index.getStep();
_baseBins = index.getBins();
_baseNumericCount = index.getNumericRowCount();
_baseNonNumericCount = index.getNonNumericRowCount();
_baseBlankCount = index.getBlankRowCount();
_baseErrorCount = index.getErrorRowCount();
if (_selected) {
_from = Math.max(_from, _min);
_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._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._nonNumericCount = 0;
this._blankCount = 0;
@ -177,6 +182,10 @@ RangeFacet.prototype._renderOtherChoices = function() {
var self = this;
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 tr0 = table.insertRow(0);
var tr1 = table.insertRow(1);
@ -185,6 +194,8 @@ RangeFacet.prototype._renderOtherChoices = function() {
* Numeric
*/
var td00 = $(tr0.insertCell(0)).attr("width", "1%");
var td01 = $(tr0.insertCell(1));
var numericCheck = $('<input type="checkbox" />').appendTo(td00).change(function() {
self._selectNumeric = !self._selectNumeric;
self._updateRest();
@ -193,7 +204,6 @@ RangeFacet.prototype._renderOtherChoices = function() {
numericCheck[0].checked = true;
}
var td01 = $(tr0.insertCell(1));
$('<span>').text("Numeric ").addClass("facet-choice-label").appendTo(td01);
$('<span>').text(this._numericCount).addClass("facet-choice-count").appendTo(td01);
@ -201,50 +211,64 @@ RangeFacet.prototype._renderOtherChoices = function() {
* Blank
*/
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));
$('<span>').text("Blank ").addClass("facet-choice-label").appendTo(td03);
$('<span>').text(this._blankCount).addClass("facet-choice-count").appendTo(td03);
if (this._baseBlankCount === 0) {
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
*/
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));
$('<span>').text("Non-numeric ").addClass("facet-choice-label").appendTo(td11);
$('<span>').text(this._nonNumericCount).addClass("facet-choice-count").appendTo(td11);
if (this._baseNonNumericCount === 0) {
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
*/
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));
$('<span>').text("Error ").addClass("facet-choice-label").appendTo(td13);
$('<span>').text(this._errorCount).addClass("facet-choice-count").appendTo(td13);
if (this._baseErrorCount === 0) {
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() {
@ -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._nonNumericCount = data.nonNumericCount;
this._blankCount = data.blankCount;