/* * Project Name : Visual Python * Description : GUI-based Python code generator * File Name : Groupby.js * Author : Black Logic * Note : Apps > Groupby * License : GNU GPLv3 with Visual Python special exception * Date : 2021. 11. 18 * Change Date : */ //============================================================================ // [CLASS] Groupby //============================================================================ define([ __VP_TEXT_LOADER__('vp_base/html/m_apps/groupby.html'), // INTEGRATION: unified version of text loader __VP_CSS_LOADER__('vp_base/css/m_apps/groupby'), // INTEGRATION: unified version of css loader 'vp_base/js/com/com_Const', 'vp_base/js/com/com_String', 'vp_base/js/com/com_util', 'vp_base/js/com/component/PopupComponent', 'vp_base/js/com/component/SuggestInput', 'vp_base/js/com/component/MultiSelector' ], function(gbHtml, gbCss, com_Const, com_String, com_util, PopupComponent, SuggestInput, MultiSelector) { /** * Groupby */ class Groupby extends PopupComponent { _init() { super._init(); /** Write codes executed before rendering */ this.config.size = { width: 700, height: 550 }; this.config.checkModules = ['pd']; this.periodList = [ { label: 'business day', value: 'B'}, { label: 'custom business day', value: 'C'}, { label: 'calendar day', value: 'D'}, { label: 'weekly', value: 'W'}, { label: 'month end', value: 'M'}, { label: 'semi-month end', value: 'SM'}, { label: 'business month end', value: 'BM'}, { label: 'custom business month end', value: 'CBM'}, { label: 'month start', value: 'MS'}, { label: 'semi-month start', value: 'SMS'}, { label: 'business month start', value: 'BMS'}, { label: 'custom business month start', value: 'CBMS'}, { label: 'quarter end', value: 'Q'}, { label: 'business quarter end', value: 'BQ'}, { label: 'quarter start', value: 'QS'}, { label: 'business quarter start', value: 'BQS'}, { label: 'year end', value: 'Y'}, { label: 'business year end', value: 'BY'}, { label: 'year start', value: 'YS'}, { label: 'business year start', value: 'BYS'}, { label: 'business hour', value: 'BH'}, { label: 'hourly', value: 'H'}, { label: 'minutely', value: 'min'}, { label: 'secondly', value: 'S'}, { label: 'milliseconds', value: 'ms'}, { label: 'microseconds', value: 'us'}, { label: 'nanoseconds', value: 'N'} ] this.methodList = [ { label: 'None', value: '' }, { label: 'count', value: "count" }, { label: 'first', value: "first" }, { label: 'last', value: "last" }, { label: 'size', value: "size" }, { label: 'std', value: "std" }, { label: 'sum', value: "sum" }, { label: 'max', value: "max" }, { label: 'mean', value: "mean" }, { label: 'median', value: "median" }, { label: 'min', value: "min" }, { label: 'quantile', value: "quantile" }, ] this.state = { variable: '', groupby: [], useGrouper: false, grouperNumber: 0, grouperPeriod: this.periodList[0].value, display: [], method: this.methodList[0].value, advanced: false, allocateTo: '', resetIndex: false, advPageDom: '', advColList: [], advMethodList: [], advMethodUserList: [], advNamingList: [], ...this.state }; this.popup = { type: '', targetSelector: '', ColSelector: undefined } } _bindEvent() { super._bindEvent(); /** Implement binding events */ let that = this; //==================================================================== // User operation Events //==================================================================== // variable change event $(document).on('change', this.wrapSelector('#vp_gbVariable'), function() { // if variable changed, clear groupby, display var newVal = $(this).val(); if (newVal != that.state.variable) { $(that.wrapSelector('#vp_gbBy')).val(''); $(that.wrapSelector('#vp_gbDisplay')).val(''); that.state.variable = newVal; that.state.groupby = []; that.state.display = []; } }); // variable refresh event $(document).on('click', this.wrapSelector('.vp-gb-df-refresh'), function() { that.loadVariableList(); }); // groupby change event $(document).on('change', this.wrapSelector('#vp_gbBy'), function(event) { var colList = event.dataList; that.state.groupby = colList; if (colList && colList.length == 1 && colList[0].type.includes('datetime')) { $(that.wrapSelector('#vp_gbByGrouper')).removeAttr('disabled'); } else { $(that.wrapSelector('#vp_gbByGrouper')).attr('disabled', true); } }); // groupby select button event $(document).on('click', this.wrapSelector('#vp_gbBy'), function() { that.openColumnSelector($(that.wrapSelector('#vp_gbBy')), 'Select columns to group'); }); // groupby grouper event $(document).on('change', this.wrapSelector('#vp_gbByGrouper'), function() { var useGrouper = $(this).prop('checked'); that.state.useGrouper = useGrouper; if (useGrouper == true) { $(that.wrapSelector('.vp-gb-by-grouper-box')).show(); } else { $(that.wrapSelector('.vp-gb-by-grouper-box')).hide(); } }); // grouper number change event $(document).on('change', this.wrapSelector('#vp_gbByGrouperNumber'), function() { that.state.grouperNumber = $(this).val(); }); // grouper period change event $(document).on('change', this.wrapSelector('#vp_gbByGrouperPeriod'), function() { that.state.grouperPeriod = $(this).val(); }); // display change event $(document).on('change', this.wrapSelector('#vp_gbDisplay'), function(event) { var colList = event.dataList; that.state.display = colList; if ((colList && colList.length == 1) || that.state.method === 'size') { $(that.wrapSelector('#vp_gbToFrame')).parent().show(); } else { $(that.wrapSelector('#vp_gbToFrame')).parent().hide(); } }); // display select button event $(document).on('click', this.wrapSelector('#vp_gbDisplay'), function() { // exclude groupby columns let excludeList = that.state.groupby.map(x => x.code); that.openColumnSelector($(that.wrapSelector('#vp_gbDisplay')), 'Select columns to display', [], excludeList); }); // method select event $(document).on('change', this.wrapSelector('#vp_gbMethodSelect'), function() { var method = $(this).val(); that.state.method = method; $(that.wrapSelector('#vp_gbMethod')).val(method); if (method === 'size' || (that.state.display && that.state.display.length == 1)) { $(that.wrapSelector('#vp_gbToFrame')).parent().show(); } else { $(that.wrapSelector('#vp_gbToFrame')).parent().hide(); } }); // advanced checkbox event $(document).on('change', this.wrapSelector('#vp_gbAdvanced'), function() { var advanced = $(this).prop('checked'); that.state.advanced = advanced; if (advanced == true) { // change method display $(that.wrapSelector('#vp_gbMethod')).val('aggregate'); $(that.wrapSelector('#vp_gbMethodSelect')).hide(); $(that.wrapSelector('#vp_gbMethod')).show(); // show advanced box $(that.wrapSelector('.vp-gb-adv-box')).show(); } else { $(that.wrapSelector('#vp_gbMethod')).val('sum'); $(that.wrapSelector('#vp_gbMethodSelect')).show(); $(that.wrapSelector('#vp_gbMethod')).hide(); // hide advanced box $(that.wrapSelector('.vp-gb-adv-box')).hide(); } }); // allocateTo event $(document).on('change', this.wrapSelector('#vp_gbAllocateTo'), function() { that.state.allocateTo = $(this).val(); }); // to dataframe event $(document).on('change', this.wrapSelector('#vp_gbToFrame'), function() { that.state.toFrame = $(this).prop('checked') == true; }); // reset index checkbox event $(document).on('change', this.wrapSelector('#vp_gbResetIndex'), function() { that.state.resetIndex = $(this).prop('checked'); }); //==================================================================== // Advanced box Events //==================================================================== // add advanced item $(document).on('click', this.wrapSelector('#vp_gbAdvAdd'), function() { that.renderAdvancedItem(); }); // advanced item - column change event $(document).on('change', this.wrapSelector('.vp-gb-adv-col'), function(event) { var colList = event.dataList; var idx = $(that.wrapSelector('.vp-gb-adv-col')).index(this); // if there's change, reset display namings // var previousList = that.state.advColList[idx]; // if (!previousList || colList.length !== previousList.length // || !colList.map(col=>col.code).slice().sort().every((val, idx) => { // return val === previousList.map(col=>col.code).slice().sort()[idx] // })) { // that.state.advNamingList = [] // $(this).parent().find('.vp-gb-adv-naming').val(''); // $(this).parent().find('.vp-gb-adv-naming').data('dict', {}); // } var namingDict = that.state.advNamingList[idx]; if (namingDict) { // namingDict = namingDict.filter(key => colList.map(col=>col.code).includes(key)); Object.keys(namingDict).forEach(key => { if (!colList.map(col=>col.code).includes(key)) { delete namingDict[key]; } }); that.state.advNamingList[idx] = namingDict; $(this).parent().find('.vp-gb-adv-naming').val(Object.values(namingDict).map(val => "'" + val +"'").join(',')); $(this).parent().find('.vp-gb-adv-naming').data('dict', namingDict); } that.state.advColList[idx] = colList; }); // edit target columns $(document).on('click', this.wrapSelector('.vp-gb-adv-col'), function() { var includeList = that.state.display; if (includeList && includeList.length > 0) { includeList = includeList.map(col => col.code); } // exclude groupby columns let excludeList = that.state.groupby.map(x => x.code); that.openColumnSelector($(this).parent().find('.vp-gb-adv-col'), 'Select columns', includeList, excludeList); }); // select method $(document).on('click', this.wrapSelector('.vp-gb-adv-method'), function() { // var method = $(this).val(); // var parentDiv = $(this).parent(); // if (method == 'typing') { // // change it to typing input // $(parentDiv).find('.vp-gb-adv-method-selector').hide(); // $(parentDiv).find('.vp-gb-adv-method').val(''); // $(parentDiv).find('.vp-gb-adv-method-box').show(); // } else { // $(parentDiv).find('.vp-gb-adv-method').val(com_util.formatString("'{0}'", method)); // } that.openMethodSelector($(this).parent().find('.vp-gb-adv-method'), 'Select methods'); }); // return to selecting method // $(document).on('click', this.wrapSelector('.vp-gb-adv-method-return'), function() { // var defaultValue = ''; // var parentDiv = $(this).parent().parent(); // $(parentDiv).find('.vp-gb-adv-method-selector').val(defaultValue); // $(parentDiv).find('.vp-gb-adv-method').val(defaultValue); // // show and hide // $(parentDiv).find('.vp-gb-adv-method-selector').show(); // $(parentDiv).find('.vp-gb-adv-method-box').hide(); // }); // advanced item - method change event $(document).on('change', this.wrapSelector('.vp-gb-adv-method'), function(event) { var { list, userList } = event; var idx = $(that.wrapSelector('.vp-gb-adv-method')).index(this); that.state.advMethodList[idx] = list; that.state.advMethodUserList[idx] = userList; }); // advanced item - user method add event $(document).on('click', this.wrapSelector('#vp_gbMethodUserAdd'), function(event) { let userMethod = $(that.wrapSelector('#vp_gbMethodUser')).val(); let useText = $(that.wrapSelector('#vp_gbMethodUserAsText')).prop('checked'); let userCode = userMethod; if (useText) { userCode = "'" + userMethod + "'"; } that._addUserMethod(userCode); }); // advanced item - user method add event by enter $(document).on('keyup', this.wrapSelector('#vp_gbMethodUser'), function(event) { var keycode = event.keyCode ? event.keyCode : event.which; if (keycode == 13) { // enter let userMethod = $(this).val(); let useText = $(that.wrapSelector('#vp_gbMethodUserAsText')).prop('checked'); let userCode = userMethod; if (useText) { userCode = "'" + userMethod + "'"; } that._addUserMethod(userCode); } }); // advanced item - naming change event $(document).on('change', this.wrapSelector('.vp-gb-adv-naming'), function(event) { var namingDict = event.namingDict; var idx = $(that.wrapSelector('.vp-gb-adv-naming')).index(this); that.state.advNamingList[idx] = namingDict; }); // edit columns naming $(document).on('click', this.wrapSelector('.vp-gb-adv-naming'), function() { var parentDiv = $(this).parent(); var columns = $(parentDiv).find('.vp-gb-adv-col').data('list'); if (columns && columns.length > 0) { columns = columns.map(col => col.code); } var method = $(parentDiv).find('.vp-gb-adv-method').data('list'); var userMethod = $(parentDiv).find('.vp-gb-adv-method').data('userList'); method = [ ...method, ...userMethod ]; if (method == undefined || method.length <= 0) { // set focus on selecting method tag $(parentDiv).find('.vp-gb-adv-method').focus(); return; } that.openNamingPopup($(parentDiv).find('.vp-gb-adv-naming'), columns, method); }); // delete advanced item $(document).on('click', this.wrapSelector('.vp-gb-adv-item-delete'), function() { if ($(that.wrapSelector('.vp-gb-adv-item')).length > 1) { $(this).closest('.vp-gb-adv-item').remove(); } }); } _addUserMethod(userMethod) { var addedMethodTag = $(this.wrapSelector(`.vp-gb-method-user-func[value="${userMethod}"]`)); if (addedMethodTag.length > 0) { // already added addedMethodTag.prop('checked', true); $(this.wrapSelector('#vp_gbMethodUser')).val(''); return; } $(`