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 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.expr.Evaluable;
|
||||
import com.metaweb.gridworks.expr.MetaParser;
|
||||
import com.metaweb.gridworks.expr.ParsingException;
|
||||
import com.metaweb.gridworks.model.Column;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.util.JSONUtilities;
|
||||
|
||||
public class ScatterplotFacet implements Facet {
|
||||
|
||||
@ -22,213 +21,184 @@ public class ScatterplotFacet implements Facet {
|
||||
* Configuration, from the client side
|
||||
*/
|
||||
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 double _to;
|
||||
protected String _x_expression; // expression to compute the x numeric value(s) per row
|
||||
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 boolean _selectNonNumeric;
|
||||
protected boolean _selectBlank;
|
||||
protected boolean _selectError;
|
||||
protected double _x_from; // the numeric selection for the x axis
|
||||
protected double _x_to;
|
||||
protected double _y_from; // the numeric selection for the y axis
|
||||
protected double _y_to;
|
||||
|
||||
protected double _x_min;
|
||||
protected double _x_max;
|
||||
protected double _y_min;
|
||||
protected double _y_max;
|
||||
|
||||
/*
|
||||
* Derived configuration data
|
||||
*/
|
||||
protected int _cellIndex;
|
||||
protected Evaluable _eval;
|
||||
protected String _errorMessage;
|
||||
protected int _x_cellIndex;
|
||||
protected int _y_cellIndex;
|
||||
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
|
||||
// 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() {
|
||||
}
|
||||
|
||||
private static final String MIN = "min";
|
||||
private static final String MAX = "max";
|
||||
private static final String TO = "to";
|
||||
private static final String FROM = "from";
|
||||
private static final String X_MIN = "x_min";
|
||||
private static final String X_MAX = "x_max";
|
||||
private static final String X_TO = "x_to";
|
||||
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)
|
||||
throws JSONException {
|
||||
|
||||
writer.object();
|
||||
writer.key("name"); writer.value(_name);
|
||||
writer.key("expression"); writer.value(_expression);
|
||||
writer.key("columnName"); writer.value(_columnName);
|
||||
writer.key("mode"); writer.value(_mode);
|
||||
writer.key("x_expression"); writer.value(_x_expression);
|
||||
writer.key("x_columnName"); writer.value(_x_columnName);
|
||||
|
||||
if (_errorMessage != null) {
|
||||
writer.key("error"); writer.value(_errorMessage);
|
||||
if (_x_errorMessage != null) {
|
||||
writer.key("x_error"); writer.value(_x_errorMessage);
|
||||
} else {
|
||||
if (!Double.isInfinite(_min) && !Double.isInfinite(_max)) {
|
||||
writer.key(MIN); writer.value(_min);
|
||||
writer.key(MAX); writer.value(_max);
|
||||
writer.key("step"); writer.value(_step);
|
||||
|
||||
writer.key("bins"); writer.array();
|
||||
for (int b : _bins) {
|
||||
writer.value(b);
|
||||
}
|
||||
writer.endArray();
|
||||
|
||||
writer.key("baseBins"); writer.array();
|
||||
for (int b : _baseBins) {
|
||||
writer.value(b);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (!Double.isInfinite(_x_min) && !Double.isInfinite(_x_max)) {
|
||||
writer.key(X_MIN); writer.value(_x_min);
|
||||
writer.key(X_MAX); writer.value(_x_max);
|
||||
writer.key(X_FROM); writer.value(_x_from);
|
||||
writer.key(X_TO); writer.value(_x_to);
|
||||
}
|
||||
if (!Double.isInfinite(_y_min) && !Double.isInfinite(_y_max)) {
|
||||
writer.key(Y_MIN); writer.value(_y_min);
|
||||
writer.key(Y_MAX); writer.value(_y_max);
|
||||
writer.key(Y_FROM); writer.value(_y_from);
|
||||
writer.key(Y_TO); writer.value(_y_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();
|
||||
}
|
||||
|
||||
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
|
||||
_name = o.getString("name");
|
||||
_expression = o.getString("expression");
|
||||
_columnName = o.getString("columnName");
|
||||
|
||||
if (_columnName.length() > 0) {
|
||||
Column column = project.columnModel.getColumnByName(_columnName);
|
||||
if (column != null) {
|
||||
_cellIndex = column.getCellIndex();
|
||||
_x_expression = o.getString("x_expression");
|
||||
_x_columnName = o.getString("x_columnName");
|
||||
|
||||
if (_x_columnName.length() > 0) {
|
||||
Column x_column = project.columnModel.getColumnByName(_x_columnName);
|
||||
if (x_column != null) {
|
||||
_x_cellIndex = x_column.getCellIndex();
|
||||
} else {
|
||||
_errorMessage = "No column named " + _columnName;
|
||||
_x_errorMessage = "No column named " + _x_columnName;
|
||||
}
|
||||
} else {
|
||||
_cellIndex = -1;
|
||||
_x_cellIndex = -1;
|
||||
}
|
||||
|
||||
try {
|
||||
_eval = MetaParser.parse(_expression);
|
||||
_x_eval = MetaParser.parse(_x_expression);
|
||||
} catch (ParsingException e) {
|
||||
_errorMessage = e.getMessage();
|
||||
_x_errorMessage = e.getMessage();
|
||||
}
|
||||
|
||||
_mode = o.getString("mode");
|
||||
if (MIN.equals(_mode)) {
|
||||
if (o.has(FROM)) {
|
||||
_from = o.getDouble(FROM);
|
||||
_selected = true;
|
||||
}
|
||||
} else if (MAX.equals(_mode)) {
|
||||
if (o.has(TO)) {
|
||||
_to = o.getDouble(TO);
|
||||
_selected = true;
|
||||
if (o.has(X_FROM) && o.has(X_TO)) {
|
||||
_x_from = o.getDouble(X_FROM);
|
||||
_x_to = o.getDouble(X_TO);
|
||||
_selected = true;
|
||||
}
|
||||
|
||||
_y_expression = o.getString("y_expression");
|
||||
_y_columnName = o.getString("y_columnName");
|
||||
|
||||
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 {
|
||||
if (o.has(FROM) && o.has(TO)) {
|
||||
_from = o.getDouble(FROM);
|
||||
_to = o.getDouble(TO);
|
||||
_selected = true;
|
||||
}
|
||||
_y_cellIndex = -1;
|
||||
}
|
||||
|
||||
_selectNumeric = JSONUtilities.getBoolean(o, "selectNumeric", true);
|
||||
_selectNonNumeric = JSONUtilities.getBoolean(o, "selectNonNumeric", true);
|
||||
_selectBlank = JSONUtilities.getBoolean(o, "selectBlank", true);
|
||||
_selectError = JSONUtilities.getBoolean(o, "selectError", true);
|
||||
try {
|
||||
_y_eval = MetaParser.parse(_y_expression);
|
||||
} catch (ParsingException e) {
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
public RowFilter getRowFilter() {
|
||||
if (_eval != null && _errorMessage == null && _selected) {
|
||||
if (MIN.equals(_mode)) {
|
||||
return new ExpressionNumberComparisonRowFilter(
|
||||
_eval, _columnName, _cellIndex, _selectNumeric, _selectNonNumeric, _selectBlank, _selectError) {
|
||||
|
||||
protected boolean checkValue(double d) {
|
||||
return d >= _from;
|
||||
};
|
||||
if (_selected &&
|
||||
_x_eval != null && _x_errorMessage == null &&
|
||||
_y_eval != null && _y_errorMessage == null)
|
||||
{
|
||||
return new DualExpressionsNumberComparisonRowFilter(_x_eval, _x_columnName, _x_cellIndex, _y_eval, _y_columnName, _y_cellIndex) {
|
||||
protected boolean checkValues(double x, double y) {
|
||||
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 {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void computeChoices(Project project, FilteredRows filteredRows) {
|
||||
if (_eval != null && _errorMessage == null) {
|
||||
Column column = project.columnModel.getColumnByCellIndex(_cellIndex);
|
||||
|
||||
String key = "numeric-bin:" + _expression;
|
||||
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
||||
if (index == null) {
|
||||
index = new NumericBinIndex(project, _columnName, _cellIndex, _eval);
|
||||
column.setPrecompute(key, index);
|
||||
if (_x_eval != null && _y_eval != null && _x_errorMessage == null && _y_errorMessage == null) {
|
||||
Column column_x = project.columnModel.getColumnByCellIndex(_x_cellIndex);
|
||||
String key_x = "numeric-bin:" + _x_expression;
|
||||
NumericBinIndex index_x = (NumericBinIndex) column_x.getPrecompute(key_x);
|
||||
if (index_x == null) {
|
||||
index_x = new NumericBinIndex(project, _x_columnName, _x_cellIndex, _x_eval);
|
||||
column_x.setPrecompute(key_x, index_x);
|
||||
}
|
||||
|
||||
_min = index.getMin();
|
||||
_max = index.getMax();
|
||||
_step = index.getStep();
|
||||
_baseBins = index.getBins();
|
||||
_x_min = index_x.getMin();
|
||||
_x_max = index_x.getMax();
|
||||
|
||||
if (_selected) {
|
||||
_from = Math.max(_from, _min);
|
||||
_to = Math.min(_to, _max);
|
||||
_x_from = Math.max(_x_from, _x_min);
|
||||
_x_to = Math.min(_x_to, _x_max);
|
||||
} else {
|
||||
_from = _min;
|
||||
_to = _max;
|
||||
_x_from = _x_min;
|
||||
_x_to = _x_max;
|
||||
}
|
||||
|
||||
ExpressionNumericRowBinner binner =
|
||||
new ExpressionNumericRowBinner(_eval, _columnName, _cellIndex, index);
|
||||
Column column_y = project.columnModel.getColumnByCellIndex(_y_cellIndex);
|
||||
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;
|
||||
_numericCount = binner.numericCount;
|
||||
_nonNumericCount = binner.nonNumericCount;
|
||||
_blankCount = binner.blankCount;
|
||||
_errorCount = binner.errorCount;
|
||||
if (_selected) {
|
||||
_y_from = Math.max(_y_from, _y_min);
|
||||
_y_to = Math.min(_y_to, _y_max);
|
||||
} else {
|
||||
_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) {
|
||||
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++) {
|
||||
var tr = table.insertRow(table.rows.length);
|
||||
for (var j = 0; j < i; j++) {
|
||||
var cx = columns[i];
|
||||
var cy = columns[j];
|
||||
var cx = columns[i].name;
|
||||
var cy = columns[j].name;
|
||||
var plotter_params = {
|
||||
'cx' : cx.name,
|
||||
'cy' : cy.name,
|
||||
'cx' : cx,
|
||||
'cy' : cy,
|
||||
'w' : self._plot_size,
|
||||
'h' : self._plot_size,
|
||||
'dot': self._dot_size,
|
||||
@ -111,21 +125,9 @@ ScatterplotDialog.prototype._renderMatrix = function() {
|
||||
plotter: JSON.stringify(plotter_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 link = $('<a href="javascript:{}"></a>').attr("title",name).click(function() {
|
||||
ui.browsingEngine.addFacet(
|
||||
"scatterplot",
|
||||
{
|
||||
"name" : name,
|
||||
"x_column" : cx.name,
|
||||
"y_column" : cy.name,
|
||||
"expression" : "value",
|
||||
"mode" : "scatterplot"
|
||||
}
|
||||
);
|
||||
//self._dismiss();
|
||||
});
|
||||
var link = wrap($('<a href="javascript:{}"></a>').attr("title",name),cx,cy);
|
||||
var plot = $('<img src="' + url + '" />').addClass("scatterplot").appendTo(link);
|
||||
link.appendTo(cell);
|
||||
}
|
||||
|
@ -29,15 +29,14 @@ ScatterplotFacet.prototype.getUIState = function() {
|
||||
return json;
|
||||
};
|
||||
|
||||
|
||||
ScatterplotFacet.prototype.getJSON = function() {
|
||||
var o = {
|
||||
type: "scatterplot",
|
||||
name: this._config.name,
|
||||
mode: this._config.mode,
|
||||
expression: this._config.expression,
|
||||
x_column : this._config.x_column,
|
||||
y_column : this._config.y_column,
|
||||
x_columnName : this._config.x_columnName,
|
||||
y_columnName : this._config.y_columnName,
|
||||
x_expression: this._config.x_expression,
|
||||
y_expression: this._config.y_expression,
|
||||
};
|
||||
|
||||
return o;
|
||||
@ -73,39 +72,32 @@ ScatterplotFacet.prototype._initializeUI = function() {
|
||||
this._plotDiv = $('<div>').addClass("facet-scatterplot-plot").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) {
|
||||
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._config.min = data.min;
|
||||
this._config.max = data.max;
|
||||
this._config.step = data.step;
|
||||
this._baseBins = data.baseBins;
|
||||
this._bins = data.bins;
|
||||
this._config.min_x = data.min_x;
|
||||
this._config.max_x = data.max_x;
|
||||
this._config.min_y = data.min_y;
|
||||
this._config.max_y = data.max_y;
|
||||
|
||||
switch (this._config.mode) {
|
||||
case "min":
|
||||
this._from = Math.max(data.from, this._config.min);
|
||||
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 {
|
||||
this._to = data.max;
|
||||
}
|
||||
this._from_x = Math.max(data.from_x, this._config.min_x);
|
||||
if ("to_x" in data) {
|
||||
this._to_x = Math.min(data.to_x, this._config.max_x);
|
||||
} else {
|
||||
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 {
|
||||
this._error = true;
|
||||
this._errorMessage = "error" in data ? data.error : "Unknown error.";
|
||||
@ -122,10 +114,8 @@ ScatterplotFacet.prototype.render = function() {
|
||||
|
||||
if (this._error) {
|
||||
this._messageDiv.text(this._errorMessage).show();
|
||||
this._sliderDiv.hide();
|
||||
this._histogramDiv.hide();
|
||||
this._plotDiv.hide();
|
||||
this._statusDiv.hide();
|
||||
this._otherChoicesDiv.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -134,12 +124,14 @@ ScatterplotFacet.prototype.render = function() {
|
||||
this._statusDiv.show();
|
||||
|
||||
this._plot.update(
|
||||
this._config.min,
|
||||
this._config.max,
|
||||
this._config.step,
|
||||
[ this._baseBins, this._bins ],
|
||||
this._from,
|
||||
this._to
|
||||
this._config.x_min,
|
||||
this._config.x_max,
|
||||
this._x_from,
|
||||
this._x_to,
|
||||
this._config.y_min,
|
||||
this._config.y_max,
|
||||
this._y_from,
|
||||
this._y_to
|
||||
);
|
||||
};
|
||||
|
||||
@ -148,7 +140,6 @@ ScatterplotFacet.prototype._remove = function() {
|
||||
|
||||
this._div = null;
|
||||
this._config = null;
|
||||
this._data = null;
|
||||
};
|
||||
|
||||
ScatterplotFacet.prototype._updateRest = function() {
|
||||
|
@ -84,77 +84,77 @@ HistogramWidget.prototype._render = function() {
|
||||
ctx.translate(0, canvas.height);
|
||||
ctx.scale(1, -1);
|
||||
|
||||
var stepPixels = canvas.width / this._binMatrix[0].length;
|
||||
var stepScale = stepPixels / this._range.step;
|
||||
var stepPixels = canvas.width / this._binMatrix[0].length;
|
||||
var stepScale = stepPixels / this._range.step;
|
||||
|
||||
/*
|
||||
* Draw axis
|
||||
*/
|
||||
/*
|
||||
* 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.strokeStyle = "emptyBinColor" in options ? options.emptyBinColor : "#faa";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.moveTo(0, 0);
|
||||
ctx.lineTo(canvas.width, 0);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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.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)
|
||||
}
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
);
|
||||
}
|
||||
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();
|
||||
};
|
||||
|
@ -2,39 +2,37 @@ function ScatterplotWidget(elmt, options) {
|
||||
this._elmt = elmt;
|
||||
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._binMatrix = null;
|
||||
this._highlight = null;
|
||||
|
||||
this._initializeUI();
|
||||
}
|
||||
|
||||
ScatterplotWidget.prototype.highlight = function(from, to) {
|
||||
this._highlight = { from: from, to: to };
|
||||
ScatterplotWidget.prototype.highlight = function(from_x, to_x, from_y, to_y) {
|
||||
this._highlight = { from_x: from_x, to_x: to_x, from_y: from_y, to_y: to_y };
|
||||
this._update();
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype.update = function(min, max, step, binMatrix, from, to) {
|
||||
if (typeof min == "undefined" || typeof binMatrix == "undefined" || binMatrix.length === 0 || binMatrix[0].length === 0) {
|
||||
ScatterplotWidget.prototype.update = function(x_min, x_max, x_from, x_to, y_min, y_max, y_from, y_to) {
|
||||
if (typeof x_min == "undefined" || typeof y_min == "undefined") {
|
||||
this._range = null;
|
||||
this._binMatrix = null;
|
||||
this._highlight = null;
|
||||
|
||||
this._elmt.hide();
|
||||
} else {
|
||||
this._range = { min: min, max: max, step: step };
|
||||
this._binMatrix = binMatrix;
|
||||
this._range = { x_min: x_min, x_max: x_max, y_min: y_min, y_max: y_max };
|
||||
|
||||
this._peak = 0;
|
||||
for (var r = 0; r < binMatrix.length; r++) {
|
||||
var row = binMatrix[r];
|
||||
for (var c = 0; c < row.length; c++) {
|
||||
this._peak = Math.max(this._peak, row[c]);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof from != "undefined" && typeof to != "undefined") {
|
||||
this._highlight = { from: from, to: to };
|
||||
if (typeof from_x != "undefined" && typeof to_x != "undefined" &&
|
||||
typeof from_y != "undefined" && typeof to_y != "undefined")
|
||||
{
|
||||
this._highlight = { from_x: from_x, to_x: to_x, from_y: from_y, to_y: to_y };
|
||||
}
|
||||
|
||||
this._update();
|
||||
@ -42,16 +40,16 @@ ScatterplotWidget.prototype.update = function(min, max, step, binMatrix, from, t
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype._update = function() {
|
||||
if (this._binMatrix !== null) {
|
||||
if (this._highlight !== null) {
|
||||
this._highlight.from = Math.max(this._highlight.from, this._range.min);
|
||||
this._highlight.to = Math.min(this._highlight.to, this._range.max);
|
||||
}
|
||||
|
||||
this._elmt.show();
|
||||
this._resize();
|
||||
this._render();
|
||||
if (this._highlight !== null) {
|
||||
this._highlight.from_x = Math.max(this._highlight.from_x, this._range.min_x);
|
||||
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._resize();
|
||||
this._render();
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype._initializeUI = function() {
|
||||
@ -59,16 +57,16 @@ ScatterplotWidget.prototype._initializeUI = function() {
|
||||
.empty()
|
||||
.hide()
|
||||
.addClass("scatterplot-widget")
|
||||
.html(
|
||||
'<canvas bind="canvas"></canvas>'
|
||||
);
|
||||
.html('<canvas bind="canvas"></canvas>');
|
||||
|
||||
this._elmts = DOM.bind(this._elmt);
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype._resize = function() {
|
||||
this._elmts.canvas.attr("height", "height" in this._options ? this._options.height : 50);
|
||||
this._elmts.canvas.attr("width", this._elmts.canvas.width());
|
||||
this._plotter.w = 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() {
|
||||
@ -81,80 +79,31 @@ ScatterplotWidget.prototype._render = function() {
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(0, canvas.height);
|
||||
ctx.scale(1, -1);
|
||||
|
||||
var stepPixels = canvas.width / this._binMatrix[0].length;
|
||||
var stepScale = stepPixels / this._range.step;
|
||||
var img = new Image();
|
||||
img.onload = function(){
|
||||
ctx.drawImage(img,0,0);
|
||||
var img2 = new Image();
|
||||
img2.onload = function(){
|
||||
ctx.drawImage(img2,0,0);
|
||||
|
||||
/*
|
||||
* 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();
|
||||
ctx.translate(0, canvas.height);
|
||||
ctx.scale(1, -1);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
// draw something else
|
||||
|
||||
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();
|
||||
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