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 46: "Array literals in GEL"
|
||||||
- Issue 55: "Use stable sorting for text facets sorted by count"
|
- Issue 55: "Use stable sorting for text facets sorted by count"
|
||||||
- Issue 53: "Moving the cursor inside the Text Filter box by clicking"
|
- Issue 53: "Moving the cursor inside the Text Filter box by clicking"
|
||||||
|
- Issue 58: "Meta facet"
|
||||||
|
Supported by the function facetCount()
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
- Row/record sorting (Issue 32)
|
- Row/record sorting (Issue 32)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.metaweb.gridworks.browsing.util;
|
package com.metaweb.gridworks.browsing.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -166,35 +167,45 @@ public class ExpressionNominalValueGrouper implements RowVisitor, RecordVisitor
|
|||||||
@Override
|
@Override
|
||||||
public Object eval(Project project, int rowIndex, Row row, Properties bindings) {
|
public Object eval(Project project, int rowIndex, Row row, Properties bindings) {
|
||||||
Object value = evalRow(project, rowIndex, row, bindings);
|
Object value = evalRow(project, rowIndex, row, bindings);
|
||||||
if (value != null) {
|
return getChoiceValueCountMultiple(value);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 java.util.Map.Entry;
|
||||||
|
|
||||||
import com.metaweb.gridworks.expr.functions.Cross;
|
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.Get;
|
||||||
import com.metaweb.gridworks.expr.functions.Length;
|
import com.metaweb.gridworks.expr.functions.Length;
|
||||||
import com.metaweb.gridworks.expr.functions.Slice;
|
import com.metaweb.gridworks.expr.functions.Slice;
|
||||||
@ -175,6 +176,8 @@ public class ControlFunctionRegistry {
|
|||||||
|
|
||||||
registerFunction("cross", new Cross());
|
registerFunction("cross", new Cross());
|
||||||
|
|
||||||
|
registerFunction("facetCount", new FacetCount());
|
||||||
|
|
||||||
registerControl("if", new If());
|
registerControl("if", new If());
|
||||||
registerControl("with", new With());
|
registerControl("with", new With());
|
||||||
registerControl("forEach", new ForEach());
|
registerControl("forEach", new ForEach());
|
||||||
|
@ -245,6 +245,9 @@ ListFacet.prototype._update = function(resetScroll) {
|
|||||||
this._elmts.bodyInnerDiv.empty().append(
|
this._elmts.bodyInnerDiv.empty().append(
|
||||||
$('<div>').text(this._data.error).addClass("facet-body-message"));
|
$('<div>').text(this._data.error).addClass("facet-body-message"));
|
||||||
|
|
||||||
|
if (this._data.error == "Too many choices") {
|
||||||
|
this._renderBodyControls();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,6 +327,7 @@ ListFacet.prototype._update = function(resetScroll) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._elmts.bodyInnerDiv.html(html.join(''));
|
this._elmts.bodyInnerDiv.html(html.join(''));
|
||||||
|
this._renderBodyControls();
|
||||||
this._elmts.bodyInnerDiv[0].scrollTop = scrollTop;
|
this._elmts.bodyInnerDiv[0].scrollTop = scrollTop;
|
||||||
|
|
||||||
var getChoice = function(elmt) {
|
var getChoice = function(elmt) {
|
||||||
@ -398,6 +402,52 @@ ListFacet.prototype._update = function(resetScroll) {
|
|||||||
window.setTimeout(wireEvents, 100);
|
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() {
|
ListFacet.prototype._doEdit = function() {
|
||||||
new ClusteringDialog(this._config.columnName, this._config.expression);
|
new ClusteringDialog(this._config.columnName, this._config.expression);
|
||||||
};
|
};
|
||||||
|
@ -137,6 +137,10 @@ a.facet-title-remove:hover {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
.facet-body-controls {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.facet-choice {
|
.facet-choice {
|
||||||
padding: 2px 5px;
|
padding: 2px 5px;
|
||||||
|
Loading…
Reference in New Issue
Block a user