progress but still no worky on the scatterfacet
git-svn-id: http://google-refine.googlecode.com/svn/trunk@457 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
ba85f50e39
commit
e232a90a73
@ -7,14 +7,13 @@ import org.json.JSONObject;
|
|||||||
import org.json.JSONWriter;
|
import org.json.JSONWriter;
|
||||||
|
|
||||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||||
import com.metaweb.gridworks.browsing.filters.ExpressionNumberComparisonRowFilter;
|
import com.metaweb.gridworks.browsing.filters.DualExpressionsNumberComparisonRowFilter;
|
||||||
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
||||||
import com.metaweb.gridworks.expr.Evaluable;
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
import com.metaweb.gridworks.expr.MetaParser;
|
import com.metaweb.gridworks.expr.MetaParser;
|
||||||
import com.metaweb.gridworks.expr.ParsingException;
|
import com.metaweb.gridworks.expr.ParsingException;
|
||||||
import com.metaweb.gridworks.model.Column;
|
import com.metaweb.gridworks.model.Column;
|
||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.util.JSONUtilities;
|
|
||||||
|
|
||||||
public class ScatterplotFacet implements Facet {
|
public class ScatterplotFacet implements Facet {
|
||||||
|
|
||||||
@ -22,213 +21,184 @@ public class ScatterplotFacet implements Facet {
|
|||||||
* Configuration, from the client side
|
* Configuration, from the client side
|
||||||
*/
|
*/
|
||||||
protected String _name; // name of facet
|
protected String _name; // name of facet
|
||||||
protected String _expression; // expression to compute numeric value(s) per row
|
|
||||||
protected String _columnName; // column to base expression on, if any
|
|
||||||
protected String _mode; // "range", MIN, MAX
|
|
||||||
|
|
||||||
protected double _from; // the numeric selection
|
protected String _x_expression; // expression to compute the x numeric value(s) per row
|
||||||
protected double _to;
|
protected String _y_expression; // expression to compute the y numeric value(s) per row
|
||||||
|
protected String _x_columnName; // column to base the x expression on, if any
|
||||||
|
protected String _y_columnName; // column to base the y expression on, if any
|
||||||
|
|
||||||
protected boolean _selectNumeric; // whether the numeric selection applies, default true
|
protected double _x_from; // the numeric selection for the x axis
|
||||||
protected boolean _selectNonNumeric;
|
protected double _x_to;
|
||||||
protected boolean _selectBlank;
|
protected double _y_from; // the numeric selection for the y axis
|
||||||
protected boolean _selectError;
|
protected double _y_to;
|
||||||
|
|
||||||
|
protected double _x_min;
|
||||||
|
protected double _x_max;
|
||||||
|
protected double _y_min;
|
||||||
|
protected double _y_max;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Derived configuration data
|
* Derived configuration data
|
||||||
*/
|
*/
|
||||||
protected int _cellIndex;
|
protected int _x_cellIndex;
|
||||||
protected Evaluable _eval;
|
protected int _y_cellIndex;
|
||||||
protected String _errorMessage;
|
protected Evaluable _x_eval;
|
||||||
|
protected Evaluable _y_eval;
|
||||||
|
protected String _x_errorMessage;
|
||||||
|
protected String _y_errorMessage;
|
||||||
|
|
||||||
protected boolean _selected; // false if we're certain that all rows will match
|
protected boolean _selected; // false if we're certain that all rows will match
|
||||||
// and there isn't any filtering to do
|
// and there isn't any filtering to do
|
||||||
|
|
||||||
/*
|
|
||||||
* Computed data, to return to the client side
|
|
||||||
*/
|
|
||||||
protected double _min;
|
|
||||||
protected double _max;
|
|
||||||
protected double _step;
|
|
||||||
protected int[] _baseBins;
|
|
||||||
protected int[] _bins;
|
|
||||||
|
|
||||||
protected int _numericCount;
|
|
||||||
protected int _nonNumericCount;
|
|
||||||
protected int _blankCount;
|
|
||||||
protected int _errorCount;
|
|
||||||
|
|
||||||
public ScatterplotFacet() {
|
public ScatterplotFacet() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String MIN = "min";
|
private static final String X_MIN = "x_min";
|
||||||
private static final String MAX = "max";
|
private static final String X_MAX = "x_max";
|
||||||
private static final String TO = "to";
|
private static final String X_TO = "x_to";
|
||||||
private static final String FROM = "from";
|
private static final String X_FROM = "x_from";
|
||||||
|
private static final String Y_MIN = "y_min";
|
||||||
|
private static final String Y_MAX = "y_max";
|
||||||
|
private static final String Y_TO = "y_to";
|
||||||
|
private static final String Y_FROM = "y_from";
|
||||||
|
|
||||||
public void write(JSONWriter writer, Properties options)
|
public void write(JSONWriter writer, Properties options)
|
||||||
throws JSONException {
|
throws JSONException {
|
||||||
|
|
||||||
writer.object();
|
writer.object();
|
||||||
writer.key("name"); writer.value(_name);
|
writer.key("name"); writer.value(_name);
|
||||||
writer.key("expression"); writer.value(_expression);
|
writer.key("x_expression"); writer.value(_x_expression);
|
||||||
writer.key("columnName"); writer.value(_columnName);
|
writer.key("x_columnName"); writer.value(_x_columnName);
|
||||||
writer.key("mode"); writer.value(_mode);
|
|
||||||
|
|
||||||
if (_errorMessage != null) {
|
if (_x_errorMessage != null) {
|
||||||
writer.key("error"); writer.value(_errorMessage);
|
writer.key("x_error"); writer.value(_x_errorMessage);
|
||||||
} else {
|
} else {
|
||||||
if (!Double.isInfinite(_min) && !Double.isInfinite(_max)) {
|
if (!Double.isInfinite(_x_min) && !Double.isInfinite(_x_max)) {
|
||||||
writer.key(MIN); writer.value(_min);
|
writer.key(X_MIN); writer.value(_x_min);
|
||||||
writer.key(MAX); writer.value(_max);
|
writer.key(X_MAX); writer.value(_x_max);
|
||||||
writer.key("step"); writer.value(_step);
|
writer.key(X_FROM); writer.value(_x_from);
|
||||||
|
writer.key(X_TO); writer.value(_x_to);
|
||||||
writer.key("bins"); writer.array();
|
|
||||||
for (int b : _bins) {
|
|
||||||
writer.value(b);
|
|
||||||
}
|
}
|
||||||
writer.endArray();
|
if (!Double.isInfinite(_y_min) && !Double.isInfinite(_y_max)) {
|
||||||
|
writer.key(Y_MIN); writer.value(_y_min);
|
||||||
writer.key("baseBins"); writer.array();
|
writer.key(Y_MAX); writer.value(_y_max);
|
||||||
for (int b : _baseBins) {
|
writer.key(Y_FROM); writer.value(_y_from);
|
||||||
writer.value(b);
|
writer.key(Y_TO); writer.value(_y_to);
|
||||||
}
|
}
|
||||||
writer.endArray();
|
|
||||||
|
|
||||||
if (MIN.equals(_mode)) {
|
|
||||||
writer.key(FROM); writer.value(_from);
|
|
||||||
} else if (MAX.equals(_mode)) {
|
|
||||||
writer.key(TO); writer.value(_to);
|
|
||||||
} else {
|
|
||||||
writer.key(FROM); writer.value(_from);
|
|
||||||
writer.key(TO); writer.value(_to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.key("numericCount"); writer.value(_numericCount);
|
|
||||||
writer.key("nonNumericCount"); writer.value(_nonNumericCount);
|
|
||||||
writer.key("blankCount"); writer.value(_blankCount);
|
|
||||||
writer.key("errorCount"); writer.value(_errorCount);
|
|
||||||
}
|
}
|
||||||
writer.endObject();
|
writer.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
|
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
|
||||||
_name = o.getString("name");
|
_name = o.getString("name");
|
||||||
_expression = o.getString("expression");
|
|
||||||
_columnName = o.getString("columnName");
|
|
||||||
|
|
||||||
if (_columnName.length() > 0) {
|
_x_expression = o.getString("x_expression");
|
||||||
Column column = project.columnModel.getColumnByName(_columnName);
|
_x_columnName = o.getString("x_columnName");
|
||||||
if (column != null) {
|
|
||||||
_cellIndex = column.getCellIndex();
|
if (_x_columnName.length() > 0) {
|
||||||
|
Column x_column = project.columnModel.getColumnByName(_x_columnName);
|
||||||
|
if (x_column != null) {
|
||||||
|
_x_cellIndex = x_column.getCellIndex();
|
||||||
} else {
|
} else {
|
||||||
_errorMessage = "No column named " + _columnName;
|
_x_errorMessage = "No column named " + _x_columnName;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_cellIndex = -1;
|
_x_cellIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_eval = MetaParser.parse(_expression);
|
_x_eval = MetaParser.parse(_x_expression);
|
||||||
} catch (ParsingException e) {
|
} catch (ParsingException e) {
|
||||||
_errorMessage = e.getMessage();
|
_x_errorMessage = e.getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
_mode = o.getString("mode");
|
if (o.has(X_FROM) && o.has(X_TO)) {
|
||||||
if (MIN.equals(_mode)) {
|
_x_from = o.getDouble(X_FROM);
|
||||||
if (o.has(FROM)) {
|
_x_to = o.getDouble(X_TO);
|
||||||
_from = o.getDouble(FROM);
|
|
||||||
_selected = true;
|
_selected = true;
|
||||||
}
|
}
|
||||||
} else if (MAX.equals(_mode)) {
|
|
||||||
if (o.has(TO)) {
|
_y_expression = o.getString("y_expression");
|
||||||
_to = o.getDouble(TO);
|
_y_columnName = o.getString("y_columnName");
|
||||||
_selected = true;
|
|
||||||
|
if (_y_columnName.length() > 0) {
|
||||||
|
Column y_column = project.columnModel.getColumnByName(_y_columnName);
|
||||||
|
if (y_column != null) {
|
||||||
|
_y_cellIndex = y_column.getCellIndex();
|
||||||
|
} else {
|
||||||
|
_y_errorMessage = "No column named " + _y_columnName;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (o.has(FROM) && o.has(TO)) {
|
_y_cellIndex = -1;
|
||||||
_from = o.getDouble(FROM);
|
|
||||||
_to = o.getDouble(TO);
|
|
||||||
_selected = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_selectNumeric = JSONUtilities.getBoolean(o, "selectNumeric", true);
|
try {
|
||||||
_selectNonNumeric = JSONUtilities.getBoolean(o, "selectNonNumeric", true);
|
_y_eval = MetaParser.parse(_y_expression);
|
||||||
_selectBlank = JSONUtilities.getBoolean(o, "selectBlank", true);
|
} catch (ParsingException e) {
|
||||||
_selectError = JSONUtilities.getBoolean(o, "selectError", true);
|
_y_errorMessage = e.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
if (!_selectNumeric || !_selectNonNumeric || !_selectBlank || !_selectError) {
|
if (o.has(Y_FROM) && o.has(Y_TO)) {
|
||||||
|
_y_from = o.getDouble(Y_FROM);
|
||||||
|
_y_to = o.getDouble(Y_TO);
|
||||||
_selected = true;
|
_selected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RowFilter getRowFilter() {
|
public RowFilter getRowFilter() {
|
||||||
if (_eval != null && _errorMessage == null && _selected) {
|
if (_selected &&
|
||||||
if (MIN.equals(_mode)) {
|
_x_eval != null && _x_errorMessage == null &&
|
||||||
return new ExpressionNumberComparisonRowFilter(
|
_y_eval != null && _y_errorMessage == null)
|
||||||
_eval, _columnName, _cellIndex, _selectNumeric, _selectNonNumeric, _selectBlank, _selectError) {
|
{
|
||||||
|
return new DualExpressionsNumberComparisonRowFilter(_x_eval, _x_columnName, _x_cellIndex, _y_eval, _y_columnName, _y_cellIndex) {
|
||||||
protected boolean checkValue(double d) {
|
protected boolean checkValues(double x, double y) {
|
||||||
return d >= _from;
|
return x >= _x_from && x < _x_to && y >= _y_from && y < _y_to;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
} else if (MAX.equals(_mode)) {
|
|
||||||
return new ExpressionNumberComparisonRowFilter(
|
|
||||||
_eval, _columnName, _cellIndex, _selectNumeric, _selectNonNumeric, _selectBlank, _selectError) {
|
|
||||||
|
|
||||||
protected boolean checkValue(double d) {
|
|
||||||
return d < _to;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return new ExpressionNumberComparisonRowFilter(
|
|
||||||
_eval, _columnName, _cellIndex, _selectNumeric, _selectNonNumeric, _selectBlank, _selectError) {
|
|
||||||
|
|
||||||
protected boolean checkValue(double d) {
|
|
||||||
return d >= _from && d < _to;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void computeChoices(Project project, FilteredRows filteredRows) {
|
public void computeChoices(Project project, FilteredRows filteredRows) {
|
||||||
if (_eval != null && _errorMessage == null) {
|
if (_x_eval != null && _y_eval != null && _x_errorMessage == null && _y_errorMessage == null) {
|
||||||
Column column = project.columnModel.getColumnByCellIndex(_cellIndex);
|
Column column_x = project.columnModel.getColumnByCellIndex(_x_cellIndex);
|
||||||
|
String key_x = "numeric-bin:" + _x_expression;
|
||||||
String key = "numeric-bin:" + _expression;
|
NumericBinIndex index_x = (NumericBinIndex) column_x.getPrecompute(key_x);
|
||||||
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
if (index_x == null) {
|
||||||
if (index == null) {
|
index_x = new NumericBinIndex(project, _x_columnName, _x_cellIndex, _x_eval);
|
||||||
index = new NumericBinIndex(project, _columnName, _cellIndex, _eval);
|
column_x.setPrecompute(key_x, index_x);
|
||||||
column.setPrecompute(key, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_min = index.getMin();
|
_x_min = index_x.getMin();
|
||||||
_max = index.getMax();
|
_x_max = index_x.getMax();
|
||||||
_step = index.getStep();
|
|
||||||
_baseBins = index.getBins();
|
|
||||||
|
|
||||||
if (_selected) {
|
if (_selected) {
|
||||||
_from = Math.max(_from, _min);
|
_x_from = Math.max(_x_from, _x_min);
|
||||||
_to = Math.min(_to, _max);
|
_x_to = Math.min(_x_to, _x_max);
|
||||||
} else {
|
} else {
|
||||||
_from = _min;
|
_x_from = _x_min;
|
||||||
_to = _max;
|
_x_to = _x_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionNumericRowBinner binner =
|
Column column_y = project.columnModel.getColumnByCellIndex(_y_cellIndex);
|
||||||
new ExpressionNumericRowBinner(_eval, _columnName, _cellIndex, index);
|
String key_y = "numeric-bin:" + _y_expression;
|
||||||
|
NumericBinIndex index_y = (NumericBinIndex) column_y.getPrecompute(key_y);
|
||||||
|
if (index_y == null) {
|
||||||
|
index_y = new NumericBinIndex(project, _y_columnName, _y_cellIndex, _y_eval);
|
||||||
|
column_y.setPrecompute(key_y, index_y);
|
||||||
|
}
|
||||||
|
|
||||||
filteredRows.accept(project, binner);
|
_y_min = index_y.getMin();
|
||||||
|
_y_max = index_y.getMax();
|
||||||
|
|
||||||
_bins = binner.bins;
|
if (_selected) {
|
||||||
_numericCount = binner.numericCount;
|
_y_from = Math.max(_y_from, _y_min);
|
||||||
_nonNumericCount = binner.nonNumericCount;
|
_y_to = Math.min(_y_to, _y_max);
|
||||||
_blankCount = binner.blankCount;
|
} else {
|
||||||
_errorCount = binner.errorCount;
|
_y_from = _y_min;
|
||||||
|
_y_to = _y_max;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
package com.metaweb.gridworks.browsing.filters;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.expr.Evaluable;
|
||||||
|
import com.metaweb.gridworks.expr.ExpressionUtils;
|
||||||
|
import com.metaweb.gridworks.model.Cell;
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.model.Row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Judge if a row matches by evaluating two given expressions on the row, based on two different columns
|
||||||
|
* and checking the results. It's a match if the result satisfies some numeric comparisons.
|
||||||
|
*/
|
||||||
|
abstract public class DualExpressionsNumberComparisonRowFilter implements RowFilter {
|
||||||
|
|
||||||
|
final protected Evaluable _x_evaluable;
|
||||||
|
final protected String _x_columnName;
|
||||||
|
final protected int _x_cellIndex;
|
||||||
|
final protected Evaluable _y_evaluable;
|
||||||
|
final protected String _y_columnName;
|
||||||
|
final protected int _y_cellIndex;
|
||||||
|
|
||||||
|
public DualExpressionsNumberComparisonRowFilter(
|
||||||
|
Evaluable x_evaluable,
|
||||||
|
String x_columnName,
|
||||||
|
int x_cellIndex,
|
||||||
|
Evaluable y_evaluable,
|
||||||
|
String y_columnName,
|
||||||
|
int y_cellIndex
|
||||||
|
) {
|
||||||
|
_x_evaluable = x_evaluable;
|
||||||
|
_x_columnName = x_columnName;
|
||||||
|
_x_cellIndex = x_cellIndex;
|
||||||
|
_y_evaluable = y_evaluable;
|
||||||
|
_y_columnName = y_columnName;
|
||||||
|
_y_cellIndex = y_cellIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean filterRow(Project project, int rowIndex, Row row) {
|
||||||
|
Cell x_cell = _x_cellIndex < 0 ? null : row.getCell(_x_cellIndex);
|
||||||
|
Properties x_bindings = ExpressionUtils.createBindings(project);
|
||||||
|
ExpressionUtils.bind(x_bindings, row, rowIndex, _x_columnName, x_cell);
|
||||||
|
Object x_value = _x_evaluable.evaluate(x_bindings);
|
||||||
|
|
||||||
|
Cell y_cell = _y_cellIndex < 0 ? null : row.getCell(_y_cellIndex);
|
||||||
|
Properties y_bindings = ExpressionUtils.createBindings(project);
|
||||||
|
ExpressionUtils.bind(y_bindings, row, rowIndex, _y_columnName, y_cell);
|
||||||
|
Object y_value = _y_evaluable.evaluate(y_bindings);
|
||||||
|
|
||||||
|
if (x_value != null && y_value != null) {
|
||||||
|
if (x_value.getClass().isArray() || y_value.getClass().isArray()) {
|
||||||
|
return false;
|
||||||
|
} else if (x_value instanceof Collection<?> || y_value instanceof Collection<?>) {
|
||||||
|
return false;
|
||||||
|
} // else, fall through
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkValue(x_value,y_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean checkValue(Object vx, Object vy) {
|
||||||
|
if (ExpressionUtils.isError(vx) || ExpressionUtils.isError(vy)) {
|
||||||
|
return false;
|
||||||
|
} else if (ExpressionUtils.isNonBlankData(vx) && ExpressionUtils.isNonBlankData(vy)) {
|
||||||
|
if (vx instanceof Number && vy instanceof Number) {
|
||||||
|
double dx = ((Number) vx).doubleValue();
|
||||||
|
double dy = ((Number) vy).doubleValue();
|
||||||
|
return (!Double.isInfinite(dx) && !Double.isNaN(dx) && !Double.isInfinite(dy) && !Double.isNaN(dy) && checkValue(dx,dy));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected boolean checkValues(double dx, double dy);
|
||||||
|
}
|
@ -92,14 +92,28 @@ ScatterplotDialog.prototype._renderMatrix = function() {
|
|||||||
if (columns.length > 0) {
|
if (columns.length > 0) {
|
||||||
var table = $('<table></table>').addClass("scatterplot-matrix-table")[0];
|
var table = $('<table></table>').addClass("scatterplot-matrix-table")[0];
|
||||||
|
|
||||||
|
var wrap = function(element,cx,cy) {
|
||||||
|
return element.click(function() {
|
||||||
|
var options = {
|
||||||
|
"name" : name,
|
||||||
|
"x_columnName" : cx,
|
||||||
|
"y_columnName" : cy,
|
||||||
|
"x_expression" : "value",
|
||||||
|
"y_expression" : "value",
|
||||||
|
};
|
||||||
|
ui.browsingEngine.addFacet("scatterplot",options);
|
||||||
|
//self._dismiss();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
for (var i = 0; i < columns.length; i++) {
|
for (var i = 0; i < columns.length; i++) {
|
||||||
var tr = table.insertRow(table.rows.length);
|
var tr = table.insertRow(table.rows.length);
|
||||||
for (var j = 0; j < i; j++) {
|
for (var j = 0; j < i; j++) {
|
||||||
var cx = columns[i];
|
var cx = columns[i].name;
|
||||||
var cy = columns[j];
|
var cy = columns[j].name;
|
||||||
var plotter_params = {
|
var plotter_params = {
|
||||||
'cx' : cx.name,
|
'cx' : cx,
|
||||||
'cy' : cy.name,
|
'cy' : cy,
|
||||||
'w' : self._plot_size,
|
'w' : self._plot_size,
|
||||||
'h' : self._plot_size,
|
'h' : self._plot_size,
|
||||||
'dot': self._dot_size,
|
'dot': self._dot_size,
|
||||||
@ -111,21 +125,9 @@ ScatterplotDialog.prototype._renderMatrix = function() {
|
|||||||
plotter: JSON.stringify(plotter_params)
|
plotter: JSON.stringify(plotter_params)
|
||||||
}
|
}
|
||||||
var url = "/command/get-scatterplot?" + $.param(params);
|
var url = "/command/get-scatterplot?" + $.param(params);
|
||||||
var name = cx.name + '(x) vs. ' + cy.name + '(y)';
|
var name = cx + ' (x) vs. ' + cy + ' (y)';
|
||||||
var cell = $(tr.insertCell(j));
|
var cell = $(tr.insertCell(j));
|
||||||
var link = $('<a href="javascript:{}"></a>').attr("title",name).click(function() {
|
var link = wrap($('<a href="javascript:{}"></a>').attr("title",name),cx,cy);
|
||||||
ui.browsingEngine.addFacet(
|
|
||||||
"scatterplot",
|
|
||||||
{
|
|
||||||
"name" : name,
|
|
||||||
"x_column" : cx.name,
|
|
||||||
"y_column" : cy.name,
|
|
||||||
"expression" : "value",
|
|
||||||
"mode" : "scatterplot"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
//self._dismiss();
|
|
||||||
});
|
|
||||||
var plot = $('<img src="' + url + '" />').addClass("scatterplot").appendTo(link);
|
var plot = $('<img src="' + url + '" />').addClass("scatterplot").appendTo(link);
|
||||||
link.appendTo(cell);
|
link.appendTo(cell);
|
||||||
}
|
}
|
||||||
|
@ -29,15 +29,14 @@ ScatterplotFacet.prototype.getUIState = function() {
|
|||||||
return json;
|
return json;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ScatterplotFacet.prototype.getJSON = function() {
|
ScatterplotFacet.prototype.getJSON = function() {
|
||||||
var o = {
|
var o = {
|
||||||
type: "scatterplot",
|
type: "scatterplot",
|
||||||
name: this._config.name,
|
name: this._config.name,
|
||||||
mode: this._config.mode,
|
x_columnName : this._config.x_columnName,
|
||||||
expression: this._config.expression,
|
y_columnName : this._config.y_columnName,
|
||||||
x_column : this._config.x_column,
|
x_expression: this._config.x_expression,
|
||||||
y_column : this._config.y_column,
|
y_expression: this._config.y_expression,
|
||||||
};
|
};
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
@ -73,39 +72,32 @@ ScatterplotFacet.prototype._initializeUI = function() {
|
|||||||
this._plotDiv = $('<div>').addClass("facet-scatterplot-plot").appendTo(bodyDiv);
|
this._plotDiv = $('<div>').addClass("facet-scatterplot-plot").appendTo(bodyDiv);
|
||||||
this._statusDiv = $('<div>').addClass("facet-scatterplot-status").appendTo(bodyDiv);
|
this._statusDiv = $('<div>').addClass("facet-scatterplot-status").appendTo(bodyDiv);
|
||||||
|
|
||||||
this._plot = new ScatterplotWidget(this._plotDiv, { binColors: [ "#ccccff", "#6666ff" ] });
|
this._plot = new ScatterplotWidget(this._plotDiv, this._config);
|
||||||
};
|
};
|
||||||
|
|
||||||
ScatterplotFacet.prototype.updateState = function(data) {
|
ScatterplotFacet.prototype.updateState = function(data) {
|
||||||
if ("min" in data && "max" in data) {
|
if ("min_x" in data && "max_x" in data && "max_y" in data && "min_y" in data) {
|
||||||
this._error = false;
|
this._error = false;
|
||||||
|
|
||||||
this._config.min = data.min;
|
this._config.min_x = data.min_x;
|
||||||
this._config.max = data.max;
|
this._config.max_x = data.max_x;
|
||||||
this._config.step = data.step;
|
this._config.min_y = data.min_y;
|
||||||
this._baseBins = data.baseBins;
|
this._config.max_y = data.max_y;
|
||||||
this._bins = data.bins;
|
|
||||||
|
|
||||||
switch (this._config.mode) {
|
this._from_x = Math.max(data.from_x, this._config.min_x);
|
||||||
case "min":
|
if ("to_x" in data) {
|
||||||
this._from = Math.max(data.from, this._config.min);
|
this._to_x = Math.min(data.to_x, this._config.max_x);
|
||||||
break;
|
|
||||||
case "max":
|
|
||||||
this._to = Math.min(data.to, this._config.max);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this._from = Math.max(data.from, this._config.min);
|
|
||||||
if ("to" in data) {
|
|
||||||
this._to = Math.min(data.to, this._config.max);
|
|
||||||
} else {
|
} else {
|
||||||
this._to = data.max;
|
this._to_x = data.max_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._from_y = Math.max(data.from_y, this._config.min_y);
|
||||||
|
if ("to_y" in data) {
|
||||||
|
this._to_y = Math.min(data.to_y, this._config.max_y);
|
||||||
|
} else {
|
||||||
|
this._to_y = data.max_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._numericCount = data.numericCount;
|
|
||||||
this._nonNumericCount = data.nonNumericCount;
|
|
||||||
this._blankCount = data.blankCount;
|
|
||||||
this._errorCount = data.errorCount;
|
|
||||||
} else {
|
} else {
|
||||||
this._error = true;
|
this._error = true;
|
||||||
this._errorMessage = "error" in data ? data.error : "Unknown error.";
|
this._errorMessage = "error" in data ? data.error : "Unknown error.";
|
||||||
@ -122,10 +114,8 @@ ScatterplotFacet.prototype.render = function() {
|
|||||||
|
|
||||||
if (this._error) {
|
if (this._error) {
|
||||||
this._messageDiv.text(this._errorMessage).show();
|
this._messageDiv.text(this._errorMessage).show();
|
||||||
this._sliderDiv.hide();
|
this._plotDiv.hide();
|
||||||
this._histogramDiv.hide();
|
|
||||||
this._statusDiv.hide();
|
this._statusDiv.hide();
|
||||||
this._otherChoicesDiv.hide();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,12 +124,14 @@ ScatterplotFacet.prototype.render = function() {
|
|||||||
this._statusDiv.show();
|
this._statusDiv.show();
|
||||||
|
|
||||||
this._plot.update(
|
this._plot.update(
|
||||||
this._config.min,
|
this._config.x_min,
|
||||||
this._config.max,
|
this._config.x_max,
|
||||||
this._config.step,
|
this._x_from,
|
||||||
[ this._baseBins, this._bins ],
|
this._x_to,
|
||||||
this._from,
|
this._config.y_min,
|
||||||
this._to
|
this._config.y_max,
|
||||||
|
this._y_from,
|
||||||
|
this._y_to
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -148,7 +140,6 @@ ScatterplotFacet.prototype._remove = function() {
|
|||||||
|
|
||||||
this._div = null;
|
this._div = null;
|
||||||
this._config = null;
|
this._config = null;
|
||||||
this._data = null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ScatterplotFacet.prototype._updateRest = function() {
|
ScatterplotFacet.prototype._updateRest = function() {
|
||||||
|
@ -2,39 +2,37 @@ function ScatterplotWidget(elmt, options) {
|
|||||||
this._elmt = elmt;
|
this._elmt = elmt;
|
||||||
this._options = options;
|
this._options = options;
|
||||||
|
|
||||||
|
this._plotter = {
|
||||||
|
'cx' : options.x_column,
|
||||||
|
'cy' : options.y_column,
|
||||||
|
'ye' : options.x_expression,
|
||||||
|
'ye' : options.x_expression,
|
||||||
|
};
|
||||||
|
|
||||||
this._range = null;
|
this._range = null;
|
||||||
this._binMatrix = null;
|
|
||||||
this._highlight = null;
|
this._highlight = null;
|
||||||
|
|
||||||
this._initializeUI();
|
this._initializeUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
ScatterplotWidget.prototype.highlight = function(from, to) {
|
ScatterplotWidget.prototype.highlight = function(from_x, to_x, from_y, to_y) {
|
||||||
this._highlight = { from: from, to: to };
|
this._highlight = { from_x: from_x, to_x: to_x, from_y: from_y, to_y: to_y };
|
||||||
this._update();
|
this._update();
|
||||||
};
|
};
|
||||||
|
|
||||||
ScatterplotWidget.prototype.update = function(min, max, step, binMatrix, from, to) {
|
ScatterplotWidget.prototype.update = function(x_min, x_max, x_from, x_to, y_min, y_max, y_from, y_to) {
|
||||||
if (typeof min == "undefined" || typeof binMatrix == "undefined" || binMatrix.length === 0 || binMatrix[0].length === 0) {
|
if (typeof x_min == "undefined" || typeof y_min == "undefined") {
|
||||||
this._range = null;
|
this._range = null;
|
||||||
this._binMatrix = null;
|
|
||||||
this._highlight = null;
|
this._highlight = null;
|
||||||
|
|
||||||
this._elmt.hide();
|
this._elmt.hide();
|
||||||
} else {
|
} else {
|
||||||
this._range = { min: min, max: max, step: step };
|
this._range = { x_min: x_min, x_max: x_max, y_min: y_min, y_max: y_max };
|
||||||
this._binMatrix = binMatrix;
|
|
||||||
|
|
||||||
this._peak = 0;
|
if (typeof from_x != "undefined" && typeof to_x != "undefined" &&
|
||||||
for (var r = 0; r < binMatrix.length; r++) {
|
typeof from_y != "undefined" && typeof to_y != "undefined")
|
||||||
var row = binMatrix[r];
|
{
|
||||||
for (var c = 0; c < row.length; c++) {
|
this._highlight = { from_x: from_x, to_x: to_x, from_y: from_y, to_y: to_y };
|
||||||
this._peak = Math.max(this._peak, row[c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof from != "undefined" && typeof to != "undefined") {
|
|
||||||
this._highlight = { from: from, to: to };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._update();
|
this._update();
|
||||||
@ -42,16 +40,16 @@ ScatterplotWidget.prototype.update = function(min, max, step, binMatrix, from, t
|
|||||||
};
|
};
|
||||||
|
|
||||||
ScatterplotWidget.prototype._update = function() {
|
ScatterplotWidget.prototype._update = function() {
|
||||||
if (this._binMatrix !== null) {
|
|
||||||
if (this._highlight !== null) {
|
if (this._highlight !== null) {
|
||||||
this._highlight.from = Math.max(this._highlight.from, this._range.min);
|
this._highlight.from_x = Math.max(this._highlight.from_x, this._range.min_x);
|
||||||
this._highlight.to = Math.min(this._highlight.to, this._range.max);
|
this._highlight.to_x = Math.min(this._highlight.to_x, this._range.max_x);
|
||||||
|
this._highlight.from_y = Math.max(this._highlight.from_y, this._range.min_y);
|
||||||
|
this._highlight.to_y = Math.min(this._highlight.to_y, this._range.max_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._elmt.show();
|
this._elmt.show();
|
||||||
this._resize();
|
this._resize();
|
||||||
this._render();
|
this._render();
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ScatterplotWidget.prototype._initializeUI = function() {
|
ScatterplotWidget.prototype._initializeUI = function() {
|
||||||
@ -59,16 +57,16 @@ ScatterplotWidget.prototype._initializeUI = function() {
|
|||||||
.empty()
|
.empty()
|
||||||
.hide()
|
.hide()
|
||||||
.addClass("scatterplot-widget")
|
.addClass("scatterplot-widget")
|
||||||
.html(
|
.html('<canvas bind="canvas"></canvas>');
|
||||||
'<canvas bind="canvas"></canvas>'
|
|
||||||
);
|
|
||||||
|
|
||||||
this._elmts = DOM.bind(this._elmt);
|
this._elmts = DOM.bind(this._elmt);
|
||||||
};
|
};
|
||||||
|
|
||||||
ScatterplotWidget.prototype._resize = function() {
|
ScatterplotWidget.prototype._resize = function() {
|
||||||
this._elmts.canvas.attr("height", "height" in this._options ? this._options.height : 50);
|
this._plotter.w = this._elmts.canvas.width();
|
||||||
this._elmts.canvas.attr("width", this._elmts.canvas.width());
|
this._plotter.h = ("height" in this._options) ? this._options.height : w;
|
||||||
|
this._elmts.canvas.attr("width", this._plotter.w);
|
||||||
|
this._elmts.canvas.attr("height", this._plotter.h);
|
||||||
};
|
};
|
||||||
|
|
||||||
ScatterplotWidget.prototype._render = function() {
|
ScatterplotWidget.prototype._render = function() {
|
||||||
@ -81,80 +79,31 @@ ScatterplotWidget.prototype._render = function() {
|
|||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
|
var img = new Image();
|
||||||
|
img.onload = function(){
|
||||||
|
ctx.drawImage(img,0,0);
|
||||||
|
var img2 = new Image();
|
||||||
|
img2.onload = function(){
|
||||||
|
ctx.drawImage(img2,0,0);
|
||||||
|
|
||||||
ctx.translate(0, canvas.height);
|
ctx.translate(0, canvas.height);
|
||||||
ctx.scale(1, -1);
|
ctx.scale(1, -1);
|
||||||
|
|
||||||
var stepPixels = canvas.width / this._binMatrix[0].length;
|
// draw something else
|
||||||
var stepScale = stepPixels / this._range.step;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Draw axis
|
|
||||||
*/
|
|
||||||
ctx.save();
|
|
||||||
ctx.strokeStyle = "emptyBinColor" in options ? options.emptyBinColor : "#faa";
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.moveTo(0, 0);
|
|
||||||
ctx.lineTo(canvas.width, 0);
|
|
||||||
ctx.stroke();
|
|
||||||
ctx.restore();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Draw bins
|
|
||||||
*/
|
|
||||||
var makeColor = function(i) {
|
|
||||||
var n = Math.floor(15 * (self._binMatrix.length - i) / self._binMatrix.length);
|
|
||||||
var h = n.toString(16);
|
|
||||||
return "#" + h + h + h;
|
|
||||||
};
|
|
||||||
var renderRow = function(row, color) {
|
|
||||||
ctx.save();
|
|
||||||
ctx.lineWidth = 0;
|
|
||||||
ctx.fillStyle = color;
|
|
||||||
for (var c = 0; c < row.length; c++) {
|
|
||||||
var x = self._range.min + c * self._range.step;
|
|
||||||
var y = row[c];
|
|
||||||
if (y > 0) {
|
|
||||||
var left = c * stepPixels;
|
|
||||||
var width = Math.ceil(stepPixels);
|
|
||||||
var height = Math.ceil(y * canvas.height / self._peak);
|
|
||||||
|
|
||||||
ctx.fillRect(left, 0, width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.restore();
|
|
||||||
};
|
|
||||||
for (var r = 0; r < this._binMatrix.length; r++) {
|
|
||||||
renderRow(
|
|
||||||
this._binMatrix[r],
|
|
||||||
"binColors" in options && r < options.binColors.length ?
|
|
||||||
options.binColors[r] :
|
|
||||||
makeColor(r)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Draw highlight
|
|
||||||
*/
|
|
||||||
if (this._highlight !== null) {
|
|
||||||
ctx.fillStyle = "rgba(192,192,192, 0.5)";
|
|
||||||
ctx.globalCompositeOperation = "source-over";
|
|
||||||
if (this._highlight.from > this._range.min) {
|
|
||||||
ctx.fillRect(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
(this._highlight.from - this._range.min) * stepScale,
|
|
||||||
canvas.height
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (this._highlight.to < this._range.max) {
|
|
||||||
ctx.fillRect(
|
|
||||||
(this._highlight.to - this._range.min) * stepScale,
|
|
||||||
0,
|
|
||||||
canvas.width - (this._highlight.to - this._range.min) * stepScale,
|
|
||||||
canvas.height
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
|
}
|
||||||
|
img2.src = self._get_image_url(self._plotter) + "&color=000088&dot=0.3";
|
||||||
|
}
|
||||||
|
img.src = self._get_image_url(self._plotter) + "&color=000000&dot=0.2";
|
||||||
|
};
|
||||||
|
|
||||||
|
ScatterplotWidget.prototype._get_image_url = function(o) {
|
||||||
|
var params = {
|
||||||
|
project: theProject.id,
|
||||||
|
engine: JSON.stringify(ui.browsingEngine.getJSON()),
|
||||||
|
plotter: JSON.stringify(o)
|
||||||
|
}
|
||||||
|
return "/command/get-scatterplot?" + $.param(params);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user