Skip to content

Commit e9575c1

Browse files
author
minjk-bl
committed
Add Discretize menu
1 parent cee048c commit e9575c1

File tree

1 file changed

+227
-27
lines changed

1 file changed

+227
-27
lines changed

visualpython/js/m_apps/Frame.js

Lines changed: 227 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -648,33 +648,125 @@ define([
648648
$(document).off('change', this.wrapSelector('.vp-inner-popup-var2'));
649649
}
650650

651-
bindEventForPopupPage() {
651+
bindEventForPopupPage(menuType) {
652652
var that = this;
653-
///// add page
654-
// 1. add type
655-
$(this.wrapSelector('.vp-inner-popup-addtype')).on('change', function() {
656-
var tab = $(this).val();
657-
$(that.wrapSelector('.vp-inner-popup-tab')).hide();
658-
$(that.wrapSelector('.vp-inner-popup-tab.' + tab)).show();
659-
});
660-
661-
// 2-1. hide column selection box
662-
$(this.wrapSelector('.vp-inner-popup-var1box .vp-vs-data-type')).on('change', function() {
663-
var type = $(this).val();
664-
if (type == 'DataFrame') {
665-
$(that.wrapSelector('.vp-inner-popup-var1col')).show();
666-
} else {
667-
$(that.wrapSelector('.vp-inner-popup-var1col')).hide();
668-
}
669-
});
670-
671-
$(this.wrapSelector('.vp-inner-popup-var2box .vp-vs-data-type')).on('change', function() {
672-
var type = $(this).val();
673-
if (type == 'DataFrame') {
674-
$(that.wrapSelector('.vp-inner-popup-var2col')).show();
675-
} else {
676-
$(that.wrapSelector('.vp-inner-popup-var2col')).hide();
677-
}
653+
654+
if (menuType === FRAME_EDIT_TYPE.ADD_COL
655+
|| menuType === FRAME_EDIT_TYPE.ADD_ROW
656+
|| menuType === FRAME_EDIT_TYPE.REPLACE) {
657+
///// add page
658+
// 1. add type
659+
$(this.wrapSelector('.vp-inner-popup-addtype')).on('change', function() {
660+
var tab = $(this).val();
661+
$(that.wrapSelector('.vp-inner-popup-tab')).hide();
662+
$(that.wrapSelector('.vp-inner-popup-tab.' + tab)).show();
663+
});
664+
665+
// 2-1. hide column selection box
666+
$(this.wrapSelector('.vp-inner-popup-var1box .vp-vs-data-type')).on('change', function() {
667+
var type = $(this).val();
668+
if (type == 'DataFrame') {
669+
$(that.wrapSelector('.vp-inner-popup-var1col')).show();
670+
} else {
671+
$(that.wrapSelector('.vp-inner-popup-var1col')).hide();
672+
}
673+
});
674+
675+
$(this.wrapSelector('.vp-inner-popup-var2box .vp-vs-data-type')).on('change', function() {
676+
var type = $(this).val();
677+
if (type == 'DataFrame') {
678+
$(that.wrapSelector('.vp-inner-popup-var2col')).show();
679+
} else {
680+
$(that.wrapSelector('.vp-inner-popup-var2col')).hide();
681+
}
682+
});
683+
} else if (menuType === FRAME_EDIT_TYPE.DISCRETIZE) {
684+
// change bins
685+
$(this.wrapSelector('.vp-inner-popup-bins')).on('change', function() {
686+
let binsCount = $(this).val();
687+
that.handleDiscretizeEdges(binsCount);
688+
});
689+
690+
// change cut to qcut(quantile based discretization)
691+
$(this.wrapSelector('.vp-inner-popup-qcut')).on('change', function() {
692+
let qcut = $(this).prop('checked');
693+
// disable right and range table
694+
if (qcut === true) {
695+
$(that.wrapSelector('.vp-inner-popup-right')).prop('disabled', true);
696+
$(that.wrapSelector('.vp-inner-popup-range-table input:not(.vp-inner-popup-label):disabled')).addClass('already-disabled');
697+
$(that.wrapSelector('.vp-inner-popup-range-table input:not(.vp-inner-popup-label)')).prop('disabled', true);
698+
} else {
699+
$(that.wrapSelector('.vp-inner-popup-right')).prop('disabled', false);
700+
$(that.wrapSelector('.vp-inner-popup-range-table input:not(.vp-inner-popup-label):not(.already-disabled)')).prop('disabled', false);
701+
$(that.wrapSelector('.vp-inner-popup-range-table input:not(.vp-inner-popup-label).already-disabled')).removeClass('already-disabled');
702+
}
703+
});
704+
705+
// change right option
706+
$(this.wrapSelector('.vp-inner-popup-right')).on('change', function() {
707+
let binsCount = $(that.wrapSelector('.vp-inner-popup-bins')).val();
708+
let right = $(this).prop('checked');
709+
that.handleDiscretizeEdges(binsCount, right);
710+
});
711+
}
712+
713+
}
714+
715+
handleDiscretizeEdges(binsCount=1, right=true) {
716+
let that = this;
717+
$(this.wrapSelector('.vp-inner-popup-range-table tbody')).html('');
718+
$(this.wrapSelector('.vp-inner-popup-islabelchanged')).val("false");
719+
$(that.wrapSelector('.vp-inner-popup-isedgechanged')).val("false");
720+
721+
let code = new com_String();
722+
code.appendFormatLine("_out, _bins = pd.cut({0}[{1}], bins={2}, right={3}, retbins=True)"
723+
, this.state.tempObj, this.state.selected[0].code, binsCount, right?'True':'False');
724+
code.append("_vp_print({'labels': [str(o) for o in _out.cat.categories], 'edges': list(_bins)})");
725+
vpKernel.execute(code.toString()).then(function(resultObj) {
726+
let { result } = resultObj;
727+
let { labels, edges } = JSON.parse(result);
728+
729+
let edgeTbody = new com_String();
730+
labels && labels.forEach((label, idx) => {
731+
let leftDisabled = 'disabled';
732+
let rightDisabled = '';
733+
if (idx === (labels.length - 1)) {
734+
rightDisabled = 'disabled';
735+
}
736+
if (right===false) {
737+
[leftDisabled, rightDisabled] = [rightDisabled, leftDisabled];
738+
}
739+
edgeTbody.append('<tr>');
740+
edgeTbody.appendFormatLine('<td><input type="text" class="vp-input m vp-inner-popup-label" data-idx="{0}" value="{1}"/></td>', idx, label);
741+
edgeTbody.appendLine('<td>:</td>');
742+
edgeTbody.appendFormatLine('<td><input type="number" class="vp-input m vp-inner-popup-left-edge" data-idx="{0}" value="{1}" {2}/></td>', idx, edges[idx], leftDisabled);
743+
edgeTbody.appendLine('<td>~</td>');
744+
edgeTbody.appendFormatLine('<td><input type="number" class="vp-input m vp-inner-popup-right-edge" data-idx="{0}" value="{1}" {2}/></td>', idx + 1, edges[idx+1], rightDisabled);
745+
edgeTbody.append('</tr>');
746+
});
747+
$(that.wrapSelector('.vp-inner-popup-range-table tbody')).html(edgeTbody.toString());
748+
749+
// label change event
750+
$(that.wrapSelector('.vp-inner-popup-label')).change(function() {
751+
$(that.wrapSelector('.vp-inner-popup-islabelchanged')).val("true");
752+
});
753+
754+
// edge change event
755+
$(that.wrapSelector('.vp-inner-popup-left-edge')).change(function() {
756+
let idx = $(this).data('idx');
757+
let val = $(this).val();
758+
$(that.wrapSelector(`.vp-inner-popup-right-edge[data-idx=${idx}]`)).val(val);
759+
$(that.wrapSelector('.vp-inner-popup-isedgechanged')).val("true");
760+
});
761+
$(that.wrapSelector('.vp-inner-popup-right-edge')).change(function() {
762+
let idx = $(this).data('idx');
763+
let val = $(this).val();
764+
$(that.wrapSelector(`.vp-inner-popup-left-edge[data-idx=${idx}]`)).val(val);
765+
$(that.wrapSelector('.vp-inner-popup-isedgechanged')).val("true");
766+
});
767+
768+
}).catch(function(errObj) {
769+
// TODO:
678770
});
679771
}
680772

@@ -1014,6 +1106,53 @@ define([
10141106
return content.toString();
10151107
}
10161108

1109+
renderDiscretizePage() {
1110+
var content = new com_String();
1111+
content.appendLine(`
1112+
<div class="vp-inner-popup-discretize-page vp-grid-box">
1113+
<div class="vp-grid-col-110">
1114+
<label class="vp-orange-text">Column name</label>
1115+
<input type="text" class="vp-input" value="${this.state.selected[0].label}" disabled />
1116+
<label>Bins count</label>
1117+
<input type="number" class="vp-input vp-inner-popup-bins" placeholder="Input count of bins"/>
1118+
</div>
1119+
<label title="pd.qcut() option">
1120+
<input type="checkbox" class="vp-inner-popup-qcut">
1121+
<span>Quantile-based discretization</span>
1122+
</label>
1123+
<label title="right option">
1124+
<input type="checkbox" class="vp-inner-popup-right" checked>
1125+
<span>Include the rightmost edge</span>
1126+
</label>
1127+
<hr style="margin: 5px 0;"/>
1128+
<table class="vp-tbl-gap5 vp-inner-popup-range-table">
1129+
<colgroup><col width="116px"><col width="5px"><col width="116px"><col width="5px"><col width="*"></colgroup>
1130+
<thead>
1131+
<tr>
1132+
<th>Label</th>
1133+
<th></th>
1134+
<th>Left edge</th>
1135+
<th></th>
1136+
<th>Right edge</th>
1137+
</tr>
1138+
</thead>
1139+
<tbody>
1140+
</tbody>
1141+
</table>
1142+
<label title="Set all labels as text">
1143+
<input type="checkbox" class="vp-inner-popup-labelastext" checked>
1144+
<span>Label as Text</span>
1145+
</label>
1146+
<input type="hidden" class="vp-inner-popup-islabelchanged" value=false />
1147+
<input type="hidden" class="vp-inner-popup-isedgechanged" value=false />
1148+
</div>
1149+
`)
1150+
1151+
// set content
1152+
$(this.wrapSelector('.vp-inner-popup-body')).html(content.toString());
1153+
return content.toString();
1154+
}
1155+
10171156
renderSortPage() {
10181157
var content = new com_String();
10191158
content.appendFormatLine('<div class="{0}">', 'vp-inner-popup-sort-page');
@@ -1152,6 +1291,16 @@ define([
11521291
title = 'Rename';
11531292
content = this.renderRenamePage();
11541293
break;
1294+
case FRAME_EDIT_TYPE.DISCRETIZE:
1295+
title = 'Discretize';
1296+
size = { width: 450, height: 450 };
1297+
content = this.renderDiscretizePage();
1298+
break;
1299+
case FRAME_EDIT_TYPE.DATA_SHIFT:
1300+
title = 'Data shift';
1301+
// TODO:
1302+
content = 'WIP';
1303+
break;
11551304
case FRAME_EDIT_TYPE.SORT_INDEX:
11561305
title = 'Sort by index';
11571306
content = this.renderSortPage();
@@ -1206,6 +1355,11 @@ define([
12061355
title = 'Convert type';
12071356
content = this.renderAsType();
12081357
break;
1358+
case FRAME_EDIT_TYPE.FILL_NA:
1359+
title = 'Fill NA';
1360+
// TODO:
1361+
content = 'WIP';
1362+
break;
12091363
default:
12101364
type = FRAME_EDIT_TYPE.NONE;
12111365
break;
@@ -1217,7 +1371,7 @@ define([
12171371
$(this.wrapSelector('.vp-inner-popup-box')).css(size);
12181372

12191373
// bindEventForAddPage
1220-
this.bindEventForPopupPage();
1374+
this.bindEventForPopupPage(type);
12211375

12221376
// set column list
12231377
vpKernel.getColumnList(this.state.tempObj).then(function(resultObj) {
@@ -1344,6 +1498,30 @@ define([
13441498
};
13451499
});
13461500
break;
1501+
case FRAME_EDIT_TYPE.DISCRETIZE:
1502+
content['bins'] = $(this.wrapSelector('.vp-inner-popup-bins')).val();
1503+
content['isqcut'] = $(this.wrapSelector('.vp-inner-popup-qcut')).prop('checked');
1504+
content['isright'] = $(this.wrapSelector('.vp-inner-popup-right')).prop('checked');
1505+
let labelastext = $(this.wrapSelector('.vp-inner-popup-labelastext')).prop('checked');
1506+
let islabelchanged = $(this.wrapSelector('.vp-inner-popup-islabelchanged')).val() === 'true';
1507+
let isedgechanged = $(this.wrapSelector('.vp-inner-popup-isedgechanged')).val() === 'true';
1508+
let rangeTableTags = $(this.wrapSelector('.vp-inner-popup-range-table tbody tr'));
1509+
let labels = [];
1510+
let edges = [];
1511+
rangeTableTags && rangeTableTags.each((idx, tag) => {
1512+
if (islabelchanged === true) {
1513+
labels.push(com_util.convertToStr($(tag).find('.vp-inner-popup-label').val(), labelastext));
1514+
}
1515+
if (content['isqcut'] === false && isedgechanged === true) {
1516+
edges.push($(tag).find('.vp-inner-popup-left-edge').val());
1517+
if (idx === (rangeTableTags.length - 1)) {
1518+
edges.push($(tag).find('.vp-inner-popup-right-edge').val());
1519+
}
1520+
}
1521+
});
1522+
content['labels'] = labels;
1523+
content['edges'] = edges;
1524+
break;
13471525
default:
13481526
break;
13491527
}
@@ -1601,6 +1779,28 @@ define([
16011779
});
16021780
code.appendFormat("{0} = {1}.astype({{2}})", tempObj, tempObj, astypeStr.toString());
16031781
break;
1782+
case FRAME_EDIT_TYPE.DISCRETIZE:
1783+
let method = 'cut';
1784+
let bins = content['bins'];
1785+
if (content['isqcut'] === true) {
1786+
method = 'qcut';
1787+
} else {
1788+
if (content['isedgechanged'] === true) {
1789+
bins = "[" + content['edges'].join(',') + "]";
1790+
}
1791+
}
1792+
1793+
code.appendFormat("{0}[{1}] = pd.{2}({3}[{4}], {5}"
1794+
, tempObj, selectedName, method, tempObj, selectedName, bins);
1795+
1796+
if (method === 'cut' && content['isright'] === false) {
1797+
code.append(", right=False");
1798+
}
1799+
if (content['labels'] && content['labels'].length > 0) {
1800+
code.appendFormat(", labels=[{0}]", content['labels'].join(', '));
1801+
}
1802+
code.append(')');
1803+
break;
16041804
case FRAME_EDIT_TYPE.SHOW:
16051805
break;
16061806
}

0 commit comments

Comments
 (0)