Commit 34530f08 authored by Anze Vavpetic's avatar Anze Vavpetic

fixed bogdan's 'select attributes' and 'select data', since they didn't work...

fixed bogdan's 'select attributes' and 'select data', since they didn't work when multiple instances of the same widgets were on the canvas, because of global scoping. 'select data' was completely rewritten in jquery, while 'select attributes' was (for the moment) only patched. some refactoring was done on the server-side of the widgets as well.
parent 0700be18
......@@ -21,8 +21,7 @@ def select_attrs(request, input_dict, output_dict, widget):
import orange, Orange
data = Orange.data.Table(input_dict['data'])
d = data.domain
classes = d.class_var.name
classes = d.class_var.name if d.class_var else None
metas = []
for m in d.getmetas().values():
......@@ -38,38 +37,30 @@ def select_attrs(request, input_dict, output_dict, widget):
return render(request, 'interactions/select_attrs.html',{'widget':widget, 'input_dict':input_dict})
def select_data(request, input_dict, output_dict, widget):
import Orange
data = Orange.data.Table(input_dict['data'])
attrs = {}
for att in data.domain.variables:
values = att.values if hasattr(att, 'values') else []
attrs[att.name] = {'feature' : 1, 'type' : str(att.var_type),
'values' : list(values)}
for a in data.domain.variables:
values = []
try:
for v in a.values:
values.append(v)
except:
pass
attrs[a.name] = {'feature':1, 'type':str(a.var_type), 'values':values}
for a in data.domain.get_metas():
meta = data.domain.get_meta(a)
values = []
try:
for v in meta.values:
values.append(v)
except:
pass
for att in data.domain.get_metas():
meta = data.domain.get_meta(att)
values = meta.values if hasattr(meta, 'values') else []
attrs[meta.name] = {'feature' : 0, 'type' : str(meta.var_type),
'values' : list(values)}
attrs[meta.name] = {'feature':0, 'type':str(meta.var_type), 'values':values}
cls = data.domain.class_var
if cls:
values = cls.values if hasattr(cls, 'values') else []
attrs[cls.name] = {'feature' : 1, 'type':str(cls.var_type),
'values': list(values)}
sorted_attrs = sorted(attrs.items())
input_dict = {'data': data, 'attrs':attrs, 'sorted_attrs':sorted_attrs}
return render(request, 'interactions/select_data.html',{'widget':widget, 'input_dict':input_dict})
return render(request, 'interactions/select_data_2.html',
{'widget' : widget, 'attrs' : sorted_attrs})
def alter_table(request, input_dict, output_dict, widget):
from visualization_views import orng_table_to_dict
......
......@@ -159,7 +159,6 @@ def build_filter(val, attr, data):
import Orange
pos = 0
try:
pos = data.domain.meta_id(attr)
except Exception, e:
......@@ -339,47 +338,27 @@ def select_data_post(postdata, input_dict, output_dict):
import Orange, json
data = input_dict['data']
try:
conditions = json.loads(str(postdata['conditions'][0]))
for c in conditions['conditions']:
if c['condition'][0]['operator'] in ["is defined", "sis defined"]:
# if the operator is "is defined"
fil = Orange.data.filter.IsDefined(domain = data.domain)
for v in range(len(data.domain.variables)):
fil.check[int(v)] = 0
if c['negate']:
fil.negate = True
fil.check[str(c['condition'][0]['attr'])] = 1
else:
fil = Orange.data.filter.Values()
fil.domain = data.domain
if c['negate']:
fil.negate = True
if len(c['condition']) > 1:
fil.conjunction = False
for val in c['condition']:
attr = data.domain[str(val['attr'])]
fil.conditions.append(build_filter(val, attr, data))
else:
for val in c['condition']:
attr = data.domain[str(val['attr'])]
fil.conditions.append(build_filter(val, attr, data))
data = fil(data)
except Exception, e:
pass
output_dict = {'data': data}
return output_dict
conditions = json.loads(str(postdata['conditions'][0]))
for cond in conditions['conditions']:
data_filter = None
if cond['condition'][0]['operator'] in ["is defined", "sis defined"]:
data_filter = Orange.data.filter.IsDefined(domain = data.domain)
data_filter.negate = cond['negate']
data_filter.check[str(cond['condition'][0]['attr'])] = 1
for v in range(len(data.domain.variables)):
data_filter.check[int(v)] = 0
else:
data_filter = Orange.data.filter.Values()
data_filter.domain = data.domain
data_filter.negate = cond['negate']
data_filter.conjunction = False
for or_cond in cond['condition']:
attr = data.domain[str(or_cond['attr'])]
data_filter.conditions.append(build_filter(or_cond, attr, data))
data = data_filter(data)
return {'data': data}
def build_classifier(input_dict):
learner = input_dict['learner']
......
......@@ -15,7 +15,7 @@
var count = 0;
for (var i = selObj.options.length - 1; i >= 0; i--) {
if (selObj.options[i].selected) {
if (dest == "ca_list" && (destObj.options.length != 0 || count >= 1) ) {
if (dest == "ca_list{{widget.pk}}" && (destObj.options.length != 0 || count >= 1) ) {
msgDisplay("Class Attribute already assigned!")
break;
};
......@@ -31,14 +31,14 @@
}
function msgDisplay (msg) {
document.getElementById("msg").innerHTML = msg;
document.getElementById("msg{{widget.pk}}").innerHTML = msg;
}
function prepareForm () {
var selObj_ma = document.getElementById('ma_list');
var hideObj_ma = document.getElementById('ma_values');
var selObj_attrs = document.getElementById('attrs_list');
var hideObj_attrs = document.getElementById('attrs_values');
var selObj_ma = document.getElementById('ma_list{{widget.pk}}');
var hideObj_ma = document.getElementById('ma_values{{widget.pk}}');
var selObj_attrs = document.getElementById('attrs_list{{widget.pk}}');
var hideObj_attrs = document.getElementById('attrs_values{{widget.pk}}');
hideObj_ma.value = '';
hideObj_attrs.value = '';
for (var i = selObj_ma.options.length - 1; i >= 0; i--) {
......@@ -58,9 +58,9 @@
};
}
function prepareForm2{{widget.id}} () {
var selObj_ma = document.getElementById('ma_list');
var selObj_attrs = document.getElementById('attrs_list');
function prepareForm2{{widget.pk}} () {
var selObj_ma = document.getElementById('ma_list{{widget.pk}}');
var selObj_attrs = document.getElementById('attrs_list{{widget.pk}}');
for (var i = selObj_ma.options.length - 1; i >= 0; i--) {
selObj_ma.options[i].selected = true;
};
......@@ -71,8 +71,8 @@
</script>
<p>Arrange the attributes. The attributes on the right side are the ones that are included in the dataset.<br><br></p>
<p id="msg" style="color:red;font-weight:bold" ></p>
<form id="interactionform-{{widget.pk}}" name="interactionform-{{widget.pk}}" onsubmit="prepareForm2{{widget.id}}();" >
<p id="msg{{widget.pk}}" style="color:red;font-weight:bold" ></p>
<form id="interactionform-{{widget.pk}}" name="interactionform-{{widget.pk}}" onsubmit="prepareForm2{{widget.pk}}();" >
<table>
<tr>
......@@ -84,30 +84,32 @@
<tr>
<td rowspan="3" >
<h2>Attributes (not in the dataset)</h2>
<select name="att" id="attr_list" style="width: 250px" size="29" multiple="multiple" >
<select name="att" id="attr_list{{widget.pk}}" style="width: 250px" size="29" multiple="multiple" >
</select>
</td>
<td style = "vertical-align:middle; text-align:center" >
<button type="button" onclick="movAttr('ca_list', 'attr_list', 'No Class Attributes available!');" > <-- </button>
<button type="button" onclick="movAttr('ca_list{{widget.pk}}', 'attr_list{{widget.pk}}', 'No Class Attributes available!');" > <-- </button>
</br>
<button type="button" onclick="movAttr('attr_list', 'ca_list', 'No more unsorted Attributes available!');" > --> </button>
<button type="button" onclick="movAttr('attr_list{{widget.pk}}', 'ca_list{{widget.pk}}', 'No more unsorted Attributes available!');" > --> </button>
</td>
<td>
<h2>Class Attribute</h2>
<SELECT name="ca" id="ca_list" style="width: 250px" SIZE="1" >
<SELECT name="ca" id="ca_list{{widget.pk}}" style="width: 250px" SIZE="1" >
{% if input_dict.ca %}
<OPTION value="{{input_dict.ca}}" SELECTED> {{input_dict.ca}}
{% endif %}
</SELECT>
</td>
</tr>
<tr>
<td style = "vertical-align:middle; text-align:center">
<button type="button" onclick="movAttr('ma_list', 'attr_list', 'No more Meta Attributes available!');" > <-- </button>
<button type="button" onclick="movAttr('ma_list{{widget.pk}}', 'attr_list{{widget.pk}}', 'No more Meta Attributes available!');" > <-- </button>
</br>
<button type="button" onclick="movAttr('attr_list', 'ma_list', 'No more unsorted Attributes available!');" > --> </button>
<button type="button" onclick="movAttr('attr_list{{widget.pk}}', 'ma_list{{widget.pk}}', 'No more unsorted Attributes available!');" > --> </button>
</td>
<td>
<h2>Meta Attributes</h2>
<select name="ma" id="ma_list" style="width: 250px" size="10" multiple="multiple" >
<select name="ma" id="ma_list{{widget.pk}}" style="width: 250px" size="10" multiple="multiple" >
{% for attr in input_dict.ma %}
<option value="{{attr}}">
{{attr}}
......@@ -118,13 +120,13 @@
</tr>
<tr>
<td style = "vertical-align:middle; text-align:center" >
<button type="button" onclick="movAttr('attrs_list', 'attr_list', 'No more Attributes available!');" > <-- </button>
<button type="button" onclick="movAttr('attrs_list{{widget.pk}}', 'attr_list{{widget.pk}}', 'No more Attributes available!');" > <-- </button>
</br>
<button type="button" onclick="movAttr('attr_list', 'attrs_list', 'No more unsorted Attributes available!');" > --> </button>
<button type="button" onclick="movAttr('attr_list{{widget.pk}}', 'attrs_list{{widget.pk}}', 'No more unsorted Attributes available!');" > --> </button>
</td>
<td>
<h2>Attributes (in the dataset)</h2>
<select name="attrs" id="attrs_list" style="width: 250px" size="15" multiple="multiple" >
<select name="attrs" id="attrs_list{{widget.pk}}" style="width: 250px" size="15" multiple="multiple" >
{% for k, v in input_dict.sorted_attrs %}
<option value="{{k}}">
{{k}}
......@@ -135,7 +137,7 @@
</tr>
</table>
<input class="runfunction" type="hidden" name="runfunction" value="prepareForm2{{widget.id}}();">
<input class="runfunction" type="hidden" name="runfunction" value="prepareForm2{{widget.pk}}();">
<input type="hidden" name="widget_id" value="{{widget.pk}}">
</center>
......
......@@ -10,309 +10,287 @@ select {width: 250px;}
</style>
<script type="text/javascript">
var SelectData = function()
{
var that = {}
that.init = function(pk)
{
that.pk = pk;
that.add_clicked = false;
that.attr_select = $('#attr_list' + that.pk);
that.operators_select = $('#operator' + that.pk);
that.values_select = $('#values' + that.pk);
that.val1_input = $('#val1' + that.pk);
that.val2_input = $('#val2' + that.pk);
that.values = $('#values' + that.pk);
that.case_sensitive = $('#case' + that.pk);
that.filters = $('#filters' + that.pk);
that.json_conditions = $('#conditions' + that.pk);
// Object containing the filtering rules
that.rules = [];
// Next position to add rule
that.index = 0;
$('#btn_add' + that.pk).click(function() {
that.add_cond('and');
});
$('#btn_or' + that.pk).click(function() {
if (that.add_clicked) {
that.add_cond('or');
} else {
that.add_cond('and');
}
});
$('#btn_del' + that.pk).click(that.del_last);
$('#btn_neg' + that.pk).click(that.neg_last);
};
that.attr_change = function(attr)
{
// Clear the select lists
that.operators_select.empty();
that.values_select.empty();
var is_string = false;
var operators = [];
if (attr['type'] == 'Discrete') {
operators = ['in', 'equals'];
that.val1_input.hide();
that.val2_input.hide();
that.values.show();
that.case_sensitive.show();
$.each(attr['values'], function(idx, value) {
var opt = $('<option></option>')
.text(value)
.val(value);
that.values_select.append(opt);
});
} else if(attr['type'] == 'Continuous') {
operators = ['outside', 'between', '<=', '<', '>=', '>', '='];
that.val1_input.show();
that.values.hide();
that.case_sensitive.hide();
} else {
is_string = true;
operators = ['ends with', 'begins with', 'not contains', 'contains',
'outside', 'between', '<=', '<', '>=', '>', '='];
that.val1_input.show();
that.values.hide();
that.case_sensitive.show();
}
function attrChange (attr) {
//clear operators list
var op_list = document.getElementById('operator');
for (var i = op_list.options.length - 1; i >= 0; i--) {
op_list.remove(i);
};
//clear values list
var vl_list = document.getElementById('values');
for (var i = vl_list.length - 1; i >= 0; i--) {
vl_list.remove(i);
};
var operators = [];
if (attr['type'] == 'Discrete') {
//for discrete attributes
operators = ['in', 'equals'];
//if the attribute is a feature
if (attr['feature']) {
operators.unshift('is defined');
};
//prepare form elements
document.getElementById('val1').className="hidden";
document.getElementById('val2').className="hidden";
document.getElementById('values').className="shown";
document.getElementById('case').className="hidden";
//fill in operators
for (var i = operators.length - 1; i >= 0; i--) {
var opt = document.createElement('option');
opt.text = operators[i];
opt.value = operators[i];
if (operators[i] == 'equals') {
opt.onclick = "document.getElementById('values').multiple = false;";
} else {
opt.onclick = "document.getElementById('values').multiple = true;";
};
op_list.options[op_list.options.length] = opt;
};
//fill in values
for (var i = attr['values'].length - 1; i >= 0; i--) {
var opt = document.createElement('option');
opt.value = attr['values'][i];
opt.text = attr['values'][i];
vl_list.options[vl_list.options.length] = opt;
};
} else if(attr['type'] == 'Continuous') {
// for continuous attributes
operators = ['outside', 'between', '<=', '<', '>=', '>', '='];
//if the attribute is a feature
if (attr['feature']) {
operators.unshift('is defined');
};
//prepare form elements
document.getElementById('val1').className="shown";
document.getElementById('values').className="hidden";
document.getElementById('case').className="hidden";
//fill in operators
for (var i = operators.length - 1; i >= 0; i--) {
var opt = document.createElement('option');
opt.text = operators[i];
opt.value = operators[i];
if (operators[i] == 'outside' || operators[i] == 'between') {
opt.onclick = "document.getElementById('val2').className='shown';";
} else {
opt.onclick = "document.getElementById('val2').className='hidden';";
};
op_list.options[op_list.options.length] = opt;
};
} else {
// for string attributes
operators = ['ends with', 'begins with', 'not contains', 'contains', 'outside', 'between', '<=', '<', '>=', '>', '='];
//if the attribute is a feature
if (attr['feature']) {
operators.unshift('is defined');
};
//prepare form elements
document.getElementById('val1').className="shown";
document.getElementById('values').className="hidden";
document.getElementById('case').className="shown";
//fill in operators
for (var i = operators.length - 1; i >= 0; i--) {
var opt = document.createElement('option');
opt.text = operators[i];
opt.value = 's' + operators[i];
if (operators[i] == 'outside' || operators[i] == 'between') {
opt.onclick = "document.getElementById('val2').className='shown';";
} else {
opt.onclick = "document.getElementById('val2').className='hidden';";
};
op_list.options[op_list.options.length] = opt;
};
};
}
var JSON_txt = '{"conditions":[]}';
var obj = JSON.parse(JSON_txt);
var index = 0;
addclicked{{widget.id}} = false;
function addCond (op) {
if (op=='and') {
addclicked{{widget.id}}=true;
if (attr['feature']) {
operators.push('is defined');
}
var attr_list = document.getElementById('attr_list');
var att_name = attr_list.value;
var op_name = document.getElementById('operator').value;
if (obj['conditions'].length > 0) {
//'is defined' is not supposed to be used in disjunction here
var last_conds = obj['conditions'][obj['conditions'].length-1];
var last_cond = last_conds['condition'][last_conds['condition'].length-1];
if (op=="or" &&
(last_cond['operator'].indexOf('defined') != -1 ||
op_name.indexOf('defined') != -1)
){
alert("Invalid action: operator 'is defined' is not allowed in a disjunction statement!");
return true;
};
};
var vl_list = document.getElementById('values');
var values = new Array ();
//add AND or OR if 'filters' is not empty
if (op != 'or') {
obj.conditions.push({"no":index, "condition":[], 'negate':0})
} else{
index--;
};
//copy values in values array
for (var i = vl_list.options.length - 1; i >= 0; i--) {
if (vl_list.options[i].selected) {
values[values.length] = vl_list.options[i].value;
};
};
var caseSens = document.getElementById('caseSens').checked;
var negate = document.getElementById('neg').checked;
//save selected condition
if (op_name == 'in' || op_name == 'equals')
{
//if attribute is discrete
obj['conditions'][index].condition.push({
'attr':att_name,
'operator':op_name,
'values':values,
'negate':negate
});
} else if (op_name == 'between' || op_name == 'outside' || op_name == 'sbetween' || op_name == 'soutside')
{
//if attribute is non-discrete and selected operator == between or outside
obj['conditions'][index].condition.push({
'attr':att_name,
'operator':op_name,
'values':[document.getElementById('val1').value, document.getElementById('val2').value],
'case':caseSens,
'negate':negate
});
} else {
//if attribute is non-discrete and selected operator is NOT between or outside
obj['conditions'][index].condition.push({
'attr':att_name,
'operator':op_name,
'values':[document.getElementById('val1').value],
'case':caseSens,
'negate':negate
});
};
index ++;
write_conds();
}
function undo () {
if (obj['conditions'].length>0) {
//delete the last statement
obj['conditions'].splice(--index ,1);
write_conds();
if ((obj['conditions'].length==0)) {
addclicked{{widget.id}}=false;
// Fill operators
$.each(operators, function(idx, op) {
var opt = $('<option></option>').text(op);
if (is_string) {
opt.val('s' + op);
} else {
opt.val(op);
}
var multipleSelect = (op != 'equals');
var showVal2 = (op == 'outside' || op == 'between');
opt.click(function() {
that.values.attr('multiple', op != 'equals');
if (op == 'outside' || op == 'between') {
that.val2_input.show();
} else {
that.val2_input.hide();
}
});
that.operators_select.append(opt);
});
};
that.add_cond = function(op)
{
if (op == 'and') {
that.add_clicked = true;
}
}
function negate () {
if (obj['conditions'].length>0) {
//negate the last statement
obj['conditions'][index-1]['negate'] = 1;
write_conds();
var att_name = that.attr_select
.find('option:selected')
.val();
var op_name = that.operators_select
.find('option:selected')
.val();
if (that.rules.length > 0) {
var last_rule = that.rules[that.rules.length-1];
var rule_cond = last_rule.condition;
var last_cond = rule_cond[rule_cond.length - 1];
// Don't allow 'is defined' with 'or'
if (op == 'or' && (last_cond['operator'].indexOf('defined') != -1 ||
op_name.indexOf('defined') != -1))
{
alert("Invalid action: operator 'is defined' is not allowed in a disjunction statement!");
return true;
}
}
}
function write_conds () {
//write all the set conditions in the textbox
var filters = document.getElementById('filters');