Fixed issue 58: Meta facet
git-svn-id: http://google-refine.googlecode.com/svn/trunk@848 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
433a047fb6
commit
c6827fe242
@ -15,6 +15,8 @@ Fixes:
|
||||
- Issue 46: "Array literals in GEL"
|
||||
- Issue 55: "Use stable sorting for text facets sorted by count"
|
||||
- Issue 53: "Moving the cursor inside the Text Filter box by clicking"
|
||||
- Issue 58: "Meta facet"
|
||||
Supported by the function facetCount()
|
||||
|
||||
Features:
|
||||
- Row/record sorting (Issue 32)
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.metaweb.gridworks.browsing.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -166,35 +167,45 @@ public class ExpressionNominalValueGrouper implements RowVisitor, RecordVisitor
|
||||
@Override
|
||||
public Object eval(Project project, int rowIndex, Row row, Properties bindings) {
|
||||
Object value = evalRow(project, rowIndex, row, bindings);
|
||||
if (value != null) {
|
||||
if (value.getClass().isArray()) {
|
||||
Object[] a = (Object[]) value;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
a[i] = getValueCount(a[i]);
|
||||
}
|
||||
return a;
|
||||
} else if (value instanceof Collection<?>) {
|
||||
List<Object> list = ExpressionUtils.toObjectList(value);
|
||||
int count = list.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
list.set(i, getValueCount(list.get(i)));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
return getValueCount(value);
|
||||
return getChoiceValueCountMultiple(value);
|
||||
}
|
||||
|
||||
protected Integer getValueCount(Object value) {
|
||||
if (value == null) {
|
||||
return blankCount;
|
||||
} else if (ExpressionUtils.isError(value)) {
|
||||
return errorCount;
|
||||
} else {
|
||||
return choices.get(value).count;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Object getChoiceValueCountMultiple(Object value) {
|
||||
if (value != null) {
|
||||
if (value.getClass().isArray()) {
|
||||
Object[] choiceValues = (Object[]) value;
|
||||
List<Integer> counts = new ArrayList<Integer>(choiceValues.length);
|
||||
|
||||
for (int i = 0; i < choiceValues.length; i++) {
|
||||
counts.add(getChoiceValueCount(choiceValues[i]));
|
||||
}
|
||||
return counts;
|
||||
} else if (value instanceof Collection<?>) {
|
||||
List<Object> choiceValues = ExpressionUtils.toObjectList(value);
|
||||
List<Integer> counts = new ArrayList<Integer>(choiceValues.size());
|
||||
|
||||
int count = choiceValues.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
counts.add(getChoiceValueCount(choiceValues.get(i)));
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
}
|
||||
|
||||
return getChoiceValueCount(value);
|
||||
}
|
||||
|
||||
public Integer getChoiceValueCount(Object choiceValue) {
|
||||
if (ExpressionUtils.isError(choiceValue)) {
|
||||
return errorCount;
|
||||
} else if (ExpressionUtils.isNonBlankData(choiceValue)) {
|
||||
IndexedNominalFacetChoice choice = choices.get(choiceValue);
|
||||
return choice != null ? choice.count : 0;
|
||||
} else {
|
||||
return blankCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
package com.metaweb.gridworks.expr.functions;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONWriter;
|
||||
|
||||
import com.metaweb.gridworks.browsing.Engine;
|
||||
import com.metaweb.gridworks.browsing.util.ExpressionNominalValueGrouper;
|
||||
import com.metaweb.gridworks.expr.EvalError;
|
||||
import com.metaweb.gridworks.expr.Evaluable;
|
||||
import com.metaweb.gridworks.expr.MetaParser;
|
||||
import com.metaweb.gridworks.expr.ParsingException;
|
||||
import com.metaweb.gridworks.gel.ControlFunctionRegistry;
|
||||
import com.metaweb.gridworks.gel.Function;
|
||||
import com.metaweb.gridworks.model.Column;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
|
||||
public class FacetCount implements Function {
|
||||
|
||||
public Object call(Properties bindings, Object[] args) {
|
||||
if (args.length == 3 && args[1] instanceof String && args[2] instanceof String) {
|
||||
Object choiceValue = args[0]; // choice value to look up
|
||||
String facetExpression = (String) args[1];
|
||||
String columnName = (String) args[2];
|
||||
|
||||
Project project = (Project) bindings.get("project");
|
||||
Column column = project.columnModel.getColumnByName(columnName);
|
||||
if (column == null) {
|
||||
return new EvalError("No such column named " + columnName);
|
||||
}
|
||||
|
||||
String key = "nominal-bin:" + facetExpression;
|
||||
ExpressionNominalValueGrouper grouper = (ExpressionNominalValueGrouper) column.getPrecompute(key);
|
||||
if (grouper == null) {
|
||||
try {
|
||||
Evaluable eval = MetaParser.parse(facetExpression);
|
||||
Engine engine = new Engine(project);
|
||||
|
||||
grouper = new ExpressionNominalValueGrouper(eval, columnName, column.getCellIndex());
|
||||
engine.getAllRows().accept(project, grouper);
|
||||
|
||||
column.setPrecompute(key, grouper);
|
||||
} catch (ParsingException e) {
|
||||
return new EvalError("Error parsing facet expression " + facetExpression);
|
||||
}
|
||||
}
|
||||
|
||||
return grouper.getChoiceValueCountMultiple(choiceValue);
|
||||
}
|
||||
return new EvalError(ControlFunctionRegistry.getFunctionName(this) +
|
||||
" expects a choice value, an expression as a string, and a column name");
|
||||
}
|
||||
|
||||
public void write(JSONWriter writer, Properties options)
|
||||
throws JSONException {
|
||||
|
||||
writer.object();
|
||||
writer.key("description"); writer.value("Returns the facet count corresponding to the given choice value");
|
||||
writer.key("params"); writer.value("choiceValue, string facetExpression, string columnName");
|
||||
writer.key("returns"); writer.value("number");
|
||||
writer.endObject();
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.metaweb.gridworks.expr.functions.Cross;
|
||||
import com.metaweb.gridworks.expr.functions.FacetCount;
|
||||
import com.metaweb.gridworks.expr.functions.Get;
|
||||
import com.metaweb.gridworks.expr.functions.Length;
|
||||
import com.metaweb.gridworks.expr.functions.Slice;
|
||||
@ -175,6 +176,8 @@ public class ControlFunctionRegistry {
|
||||
|
||||
registerFunction("cross", new Cross());
|
||||
|
||||
registerFunction("facetCount", new FacetCount());
|
||||
|
||||
registerControl("if", new If());
|
||||
registerControl("with", new With());
|
||||
registerControl("forEach", new ForEach());
|
||||
|
@ -245,6 +245,9 @@ ListFacet.prototype._update = function(resetScroll) {
|
||||
this._elmts.bodyInnerDiv.empty().append(
|
||||
$('<div>').text(this._data.error).addClass("facet-body-message"));
|
||||
|
||||
if (this._data.error == "Too many choices") {
|
||||
this._renderBodyControls();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -324,6 +327,7 @@ ListFacet.prototype._update = function(resetScroll) {
|
||||
}
|
||||
|
||||
this._elmts.bodyInnerDiv.html(html.join(''));
|
||||
this._renderBodyControls();
|
||||
this._elmts.bodyInnerDiv[0].scrollTop = scrollTop;
|
||||
|
||||
var getChoice = function(elmt) {
|
||||
@ -398,6 +402,52 @@ ListFacet.prototype._update = function(resetScroll) {
|
||||
window.setTimeout(wireEvents, 100);
|
||||
};
|
||||
|
||||
ListFacet.prototype._renderBodyControls = function() {
|
||||
var self = this;
|
||||
var bodyControls = $('<div>')
|
||||
.addClass("facet-body-controls")
|
||||
.appendTo(this._elmts.bodyInnerDiv);
|
||||
|
||||
$('<a>')
|
||||
.text("facet by choice counts")
|
||||
.attr("href", "javascript:{}")
|
||||
.addClass("action")
|
||||
.appendTo(bodyControls)
|
||||
.click(function() {
|
||||
ui.browsingEngine.addFacet(
|
||||
"range",
|
||||
{
|
||||
"name" : self._config.columnName,
|
||||
"columnName" : self._config.columnName,
|
||||
"expression" : self._getMetaExpression(),
|
||||
"mode" : "range"
|
||||
},
|
||||
{
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
ListFacet.prototype._getMetaExpression = function() {
|
||||
var expression = this._config.expression;
|
||||
|
||||
var language = "gel:";
|
||||
var colon = expression.indexOf(":");
|
||||
if (colon > 0) {
|
||||
var l = expression.substring(0, colon + 1);
|
||||
if (l == "gel:" || l == "jython:" || l == "clojure:") {
|
||||
expression = expression.substring(colon + 1);
|
||||
language = l;
|
||||
}
|
||||
}
|
||||
|
||||
return language + 'facetCount(' + [
|
||||
expression,
|
||||
JSON.stringify(this._config.expression),
|
||||
JSON.stringify(this._config.columnName)
|
||||
].join(', ') + ')';
|
||||
}
|
||||
|
||||
ListFacet.prototype._doEdit = function() {
|
||||
new ClusteringDialog(this._config.columnName, this._config.expression);
|
||||
};
|
||||
|
@ -137,6 +137,10 @@ a.facet-title-remove:hover {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.facet-body-controls {
|
||||
margin: 0.5em 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.facet-choice {
|
||||
padding: 2px 5px;
|
||||
|
Loading…
Reference in New Issue
Block a user