Skip to content

Commit a7e7328

Browse files
author
minjk-bl
committed
Add to_datetime to Frame app
1 parent 5a23518 commit a7e7328

File tree

2 files changed

+220
-6
lines changed

2 files changed

+220
-6
lines changed

visualpython/css/m_apps/frame.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@
145145
top: 0;
146146
background-color: var(--vp-background-color);
147147
border-bottom: 1px solid var(--vp-border-gray-color);
148+
border-right: 1px solid var(--vp-border-gray-color);
148149

149150
text-align: right;
150151
text-overflow: ellipsis;
@@ -168,6 +169,10 @@
168169
/* background: var(--vp-light-gray-color); */
169170
/* background: rgba(66, 165, 245, 0.2); */
170171
}
172+
.vp-fe-table-column-isnumeric {
173+
float: left;
174+
margin-right: 5px;
175+
}
171176

172177
/* Row Hover */
173178
.vp-fe-table tbody tr:hover {
@@ -302,6 +307,18 @@
302307
float: right;
303308
display: inline-block;
304309
}
310+
/* to datetime */
311+
.vp-inner-popup-todt-addcol-content {
312+
display: grid;
313+
row-gap: 5px;
314+
max-height: 105px;
315+
}
316+
.vp-inner-popup-todt-addcol-head,
317+
.vp-inner-popup-todt-addcol-item {
318+
display: grid;
319+
grid-template-columns: 160px 160px auto;
320+
column-gap: 5px;
321+
}
305322

306323
/* UDF Editor - CodeMirror */
307324
.vp-fr-subset-box {

visualpython/js/m_apps/Frame.js

Lines changed: 203 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ define([
8787
{ id: 'add_row', label: 'Add row', selection: FRAME_SELECT_TYPE.NONE, menuType: FRAME_EDIT_TYPE.ADD_ROW },
8888
{ id: 'delete', label: 'Delete', selection: FRAME_SELECT_TYPE.MULTI, menuType: FRAME_EDIT_TYPE.DROP },
8989
{ id: 'rename', label: 'Rename', selection: FRAME_SELECT_TYPE.NONE, menuType: FRAME_EDIT_TYPE.RENAME },
90-
{ id: 'asType', label: 'As type', selection: FRAME_SELECT_TYPE.NONE, axis: FRAME_AXIS.COLUMN, menuType: FRAME_EDIT_TYPE.AS_TYPE },
90+
{ id: 'as_type', label: 'As type', selection: FRAME_SELECT_TYPE.NONE, axis: FRAME_AXIS.COLUMN, menuType: FRAME_EDIT_TYPE.AS_TYPE },
91+
{ id: 'to_datetime', label: 'To datetime', selection: FRAME_SELECT_TYPE.SINGLE, axis: FRAME_AXIS.COLUMN, menuType: FRAME_EDIT_TYPE.TO_DATETIME },
9192
{ id: 'replace', label: 'Replace', selection: FRAME_SELECT_TYPE.SINGLE, axis: FRAME_AXIS.COLUMN, menuType: FRAME_EDIT_TYPE.REPLACE },
9293
{ id: 'discretize', label: 'Discretize', selection: FRAME_SELECT_TYPE.SINGLE, axis: FRAME_AXIS.COLUMN, numeric_only: true, menuType: FRAME_EDIT_TYPE.DISCRETIZE }
9394
]
@@ -618,6 +619,7 @@ define([
618619
case FRAME_EDIT_TYPE.RENAME:
619620
case FRAME_EDIT_TYPE.REPLACE:
620621
case FRAME_EDIT_TYPE.AS_TYPE:
622+
case FRAME_EDIT_TYPE.TO_DATETIME:
621623
case FRAME_EDIT_TYPE.DISCRETIZE:
622624
case FRAME_EDIT_TYPE.DATA_SHIFT:
623625
case FRAME_EDIT_TYPE.SORT_INDEX:
@@ -1106,6 +1108,73 @@ define([
11061108
$(that.wrapSelector('.vp-inner-popup-fill-row')).hide();
11071109
}
11081110
});
1111+
} else if (menuType === FRAME_EDIT_TYPE.TO_DATETIME) {
1112+
// bind event for selecting format
1113+
$(this.wrapSelector('.vp-inner-popup-todt-format')).on('change', function() {
1114+
let format = $(this).val();
1115+
if (format === 'auto') {
1116+
$(that.wrapSelector('.vp-inner-popup-todt-dayfirst')).prop('disabled', false);
1117+
} else {
1118+
$(that.wrapSelector('.vp-inner-popup-todt-dayfirst')).prop('disabled', true);
1119+
$(that.wrapSelector('.vp-inner-popup-todt-dayfirst')).val('');
1120+
}
1121+
1122+
if (format === 'typing') {
1123+
$(that.wrapSelector('.vp-inner-popup-todt-format-typing')).prop('disabled', false);
1124+
} else {
1125+
$(that.wrapSelector('.vp-inner-popup-todt-format-typing')).prop('disabled', true);
1126+
}
1127+
});
1128+
1129+
// bind event for checking add column
1130+
$(this.wrapSelector('.vp-inner-popup-todt-use-addcol')).on('change', function() {
1131+
let checked = $(this).prop('checked');
1132+
if (checked === true) {
1133+
$(that.wrapSelector('.vp-inner-popup-todt-addcol-box')).show();
1134+
} else {
1135+
$(that.wrapSelector('.vp-inner-popup-todt-addcol-box')).hide();
1136+
}
1137+
});
1138+
1139+
// Add column set event
1140+
$(this.wrapSelector('.vp-inner-popup-todt-addcol')).on('click', function() {
1141+
let dateTypeList = [ // df[col].dt[{dateType}]
1142+
{ label: 'Year', value: 'year' },
1143+
{ label: 'Month', value: 'month' },
1144+
{ label: 'Day', value: 'day' },
1145+
{ label: 'Date', value: 'date' },
1146+
{ label: 'DayOfWeek', value: 'dayofweek' },
1147+
{ label: 'DayOfYear', value: 'dayofyear' },
1148+
{ label: 'DaysInMonth', value: 'daysinmonth' },
1149+
{ label: 'Quarter', value: 'quarter' },
1150+
{ label: 'Time', value: 'time' },
1151+
{ label: 'Hour', value: 'hour' },
1152+
{ label: 'Minute', value: 'minute' },
1153+
{ label: 'Second', value: 'second' },
1154+
{ label: 'Nanosecond', value: 'nanosecond' },
1155+
];
1156+
let dateTypeOptionTag = new com_String();
1157+
dateTypeList.forEach(opt => {
1158+
dateTypeOptionTag.appendFormat('<option value="{0}">{1}</option>', opt.value, opt.label);
1159+
});
1160+
1161+
let addColItemTag = $(`<div class="vp-inner-popup-todt-addcol-item">
1162+
<input type="text" class="vp-input vp-inner-popup-todt-addcol-colname" placeholder="Type column name" />
1163+
<select class="vp-select vp-inner-popup-todt-addcol-type">
1164+
${dateTypeOptionTag.toString()}
1165+
</select>
1166+
<span class="vp-icon-close-small vp-inner-popup-todt-addcol-del mt5 vp-cursor"></span>
1167+
</div>`);
1168+
$(that.wrapSelector('.vp-inner-popup-todt-addcol-content')).append(addColItemTag);
1169+
$(addColItemTag)[0].scrollIntoView();
1170+
1171+
// bind event for deleting
1172+
$(that.wrapSelector('.vp-inner-popup-todt-addcol-del')).off('click');
1173+
$(that.wrapSelector('.vp-inner-popup-todt-addcol-del')).on('click', function() {
1174+
// delete item
1175+
$(this).closest('.vp-inner-popup-todt-addcol-item').remove();
1176+
});
1177+
});
11091178
}
11101179

11111180
}
@@ -2113,6 +2182,75 @@ define([
21132182
return content.toString();
21142183
}
21152184

2185+
renderToDatetime() {
2186+
var content = new com_String();
2187+
let formatList = [
2188+
{ label: 'Auto', value: 'auto' },
2189+
{ label: 'Year', value: '%Y' },
2190+
{ label: 'Month', value: '%m' },
2191+
{ label: 'Day', value: '%d' },
2192+
{ label: 'Day Of Week', value: '%w' },
2193+
{ label: '%Y/%m/%d', value: '%Y/%m/%d' },
2194+
{ label: '%Y-%m-%d', value: '%Y-%m-%d' },
2195+
{ label: '%d/%m/%Y', value: '%d/%m/%Y' },
2196+
{ label: '%d-%m-%Y', value: '%d-%m-%Y' },
2197+
{ label: 'Typing', value: 'typing' },
2198+
];
2199+
let formatOptionTag = new com_String();
2200+
formatList.forEach(opt => {
2201+
formatOptionTag.appendFormat('<option value="{0}">{1}</option>', opt.value, opt.label);
2202+
});
2203+
2204+
content.appendFormat(`<div class="vp-inner-popup-todt vp-grid-box">
2205+
<div class="vp-grid-col-110">
2206+
<label>Target column</label>
2207+
<input type="text" class="vp-input" value="{0}" readonly />
2208+
</div>
2209+
<div class="vp-grid-col-110">
2210+
<label>Format</label>
2211+
<div>
2212+
<select class="vp-inner-popup-todt-format">
2213+
{1}
2214+
</select>
2215+
<input type="text" class="vp-input vp-inner-popup-todt-format-typing" value="" placeholder="Type format" disabled/>
2216+
</div>
2217+
</div>
2218+
<div class="vp-grid-col-110">
2219+
<label>Day first</label>
2220+
<select class="vp-inner-popup-todt-dayfirst">
2221+
<option value="">Select option...</option>
2222+
<option value="True">True</option>
2223+
<option value="False">False</option>
2224+
</select>
2225+
</div>
2226+
<hr style="margin: 5px 0;"/>
2227+
<div>
2228+
<label>
2229+
<input type="checkbox" class="vp-inner-popup-todt-use-addcol" />
2230+
<span>
2231+
Add column with date type
2232+
</span>
2233+
</label>
2234+
</div>
2235+
<div class="vp-inner-popup-todt-addcol-box vp-grid-border-box" style="display: none;">
2236+
<div class="vp-inner-popup-todt-addcol-head">
2237+
<label>New column name</label>
2238+
<label>Date type</label>
2239+
<label></label>
2240+
</div>
2241+
<div class="vp-inner-popup-todt-addcol-content vp-scrollbar">
2242+
2243+
</div>
2244+
<button class="vp-button vp-inner-popup-todt-addcol">+ Add column</button>
2245+
</div>
2246+
</div>
2247+
`, this.state.selected[0].label, formatOptionTag.toString(), );
2248+
2249+
// set content
2250+
$(this.wrapSelector('.vp-inner-popup-body')).html(content.toString());
2251+
return content.toString();
2252+
}
2253+
21162254
renderFillNAPage() {
21172255
var content = new com_String();
21182256
content.appendFormatLine('<div class="{0}">', 'vp-inner-popup-fillna-page');
@@ -2454,6 +2592,11 @@ define([
24542592
title = 'Convert type';
24552593
content = this.renderAsType();
24562594
break;
2595+
case FRAME_EDIT_TYPE.TO_DATETIME:
2596+
title = 'Convert to datetime';
2597+
size = { width: 500, height: 450 };
2598+
content = this.renderToDatetime();
2599+
break;
24572600
case FRAME_EDIT_TYPE.FILL_NA:
24582601
title = 'Fill NA';
24592602
content = this.renderFillNAPage();
@@ -2823,6 +2966,22 @@ define([
28232966
}
28242967
});
28252968
break;
2969+
case FRAME_EDIT_TYPE.TO_DATETIME:
2970+
content['format'] = $(this.wrapSelector('.vp-inner-popup-todt-format')).val();
2971+
content['format_typing'] = $(this.wrapSelector('.vp-inner-popup-todt-format-typing')).val();
2972+
content['dayfirst'] = $(this.wrapSelector('.vp-inner-popup-todt-dayfirst')).val();
2973+
content['use_addcol'] = $(this.wrapSelector('.vp-inner-popup-todt-use-addcol')).prop('checked');
2974+
var colList = [];
2975+
var addcolItemTags = $(this.wrapSelector('.vp-inner-popup-todt-addcol-item'));
2976+
addcolItemTags && addcolItemTags.each((idx, tag) => {
2977+
let colName = $(tag).find('.vp-inner-popup-todt-addcol-colname').val();
2978+
let dateType = $(tag).find('.vp-inner-popup-todt-addcol-type').val();
2979+
if (colName !== '' && dateType !== '') {
2980+
colList.push({ colName: colName, dateType: dateType });
2981+
}
2982+
});
2983+
content['collist'] = colList;
2984+
break;
28262985
case FRAME_EDIT_TYPE.DISCRETIZE:
28272986
content['input'] = $(this.wrapSelector('.vp-inner-popup-input')).val();
28282987
content['inputastext'] = $(this.wrapSelector('.vp-inner-popup-inputastext')).prop('checked');
@@ -3343,6 +3502,31 @@ define([
33433502
});
33443503
code.appendFormat("{0} = {1}.astype({{2}})", tempObj, tempObj, astypeStr.toString());
33453504
break;
3505+
case FRAME_EDIT_TYPE.TO_DATETIME:
3506+
code.appendFormat("{0}[{1}] = pd.to_datetime({2}[{3}]", tempObj, selectedName, tempObj, selectedName);
3507+
let optionList = [];
3508+
if (content['format'] === 'auto') {
3509+
if (content['dayfirst'] !== '') {
3510+
optionList.push(`dayfirst=${content['dayfirst']}`);
3511+
}
3512+
} else if (content['format'] === 'typing') {
3513+
if (content['format_typing'] !== '') {
3514+
optionList.push(`format='${content['format_typing']}'`);
3515+
}
3516+
} else {
3517+
optionList.push(`format='${content['format']}'`);
3518+
}
3519+
if (optionList.length > 0) {
3520+
code.appendFormat(', {0}', optionList.join(', '));
3521+
}
3522+
code.append(')');
3523+
if (content['use_addcol'] === true && content['collist'].length > 0) {
3524+
content['collist'].forEach(obj => {
3525+
code.appendLine();
3526+
code.appendFormat("{0}['{1}'] = {2}[{3}].dt.{4}", tempObj, obj.colName, tempObj, selectedName, obj.dateType);
3527+
});
3528+
}
3529+
break;
33463530
case FRAME_EDIT_TYPE.DISCRETIZE:
33473531
let newColumn = com_util.convertToStr(content['input'], content['inputastext']);
33483532
let method = content['type'];
@@ -3437,7 +3621,7 @@ define([
34373621
var indexList = data.index;
34383622
var dataList = data.data;
34393623

3440-
columnList = columnList.map(col => { return { label: col.label, type: col.dtype, code: col.value } });
3624+
columnList = columnList.map(col => { return { label: col.label, type: col.dtype, code: col.value, isNumeric: col.is_numeric } });
34413625
indexList = indexList.map(idx => { return { label: idx, code: idx } });
34423626

34433627
if (!more) {
@@ -3453,6 +3637,12 @@ define([
34533637
while (colIdx < columnList.length) {
34543638
let col = columnList[colIdx];
34553639
let colCode = col.code.slice(0, colLevIdx + 1).join(',');
3640+
var colIcon = '';
3641+
if (col.isNumeric === true) {
3642+
colIcon = '<span class="vp-fe-table-column-isnumeric vp-icon-numeric" title="Numeric column"></span>';
3643+
} else {
3644+
colIcon = '<span class="vp-fe-table-column-isnumeric vp-icon-non-numeric" title="Non-numeric column"></span>';
3645+
}
34563646
let nextCol = columnList[colIdx + 1];
34573647
if (nextCol && nextCol.code.slice(0, colLevIdx + 1).join(',') === colCode) {
34583648
colSpan++;
@@ -3467,8 +3657,8 @@ define([
34673657
} else {
34683658
colClass = VP_FE_TABLE_COLUMN_GROUP;
34693659
}
3470-
table.appendFormatLine('<th data-code="({0})" data-axis="{1}" data-type="{2}" data-parent="{3}" data-label="{4}" class="{5} {6}" colspan="{7}">{8}</th>'
3471-
, colCode, FRAME_AXIS.COLUMN, col.type, col.label[colLevIdx-1], col.label[colLevIdx], colClass, selected, colSpan, col.label[colLevIdx]);
3660+
table.appendFormatLine('<th data-code="({0})" data-axis="{1}" data-type="{2}" data-parent="{3}" data-label="{4}" class="{5} {6}" colspan="{7}">{8}{9}</th>'
3661+
, colCode, FRAME_AXIS.COLUMN, col.type, col.label[colLevIdx-1], col.label[colLevIdx], colClass, selected, colSpan, colIcon, col.label[colLevIdx]);
34723662
colSpan = 1;
34733663
}
34743664
colIdx++;
@@ -3487,12 +3677,18 @@ define([
34873677
table.appendLine('<tr><th></th>');
34883678
columnList && columnList.forEach(col => {
34893679
var colCode = col.code;
3680+
var colIcon = '';
3681+
if (col.isNumeric === true) {
3682+
colIcon = '<span class="vp-fe-table-column-isnumeric vp-icon-numeric" title="Numeric column"></span>';
3683+
} else {
3684+
colIcon = '<span class="vp-fe-table-column-isnumeric vp-icon-non-numeric" title="Non-numeric column"></span>';
3685+
}
34903686
var colClass = '';
34913687
if (that.state.axis == FRAME_AXIS.COLUMN && that.state.selected.map(col=>col.code).includes(colCode)) {
34923688
colClass = 'selected';
34933689
}
3494-
table.appendFormatLine('<th data-code="{0}" data-axis="{1}" data-type="{2}" data-label="{3}" class="{4} {5}">{6}</th>'
3495-
, colCode, FRAME_AXIS.COLUMN, col.type, col.label, VP_FE_TABLE_COLUMN, colClass, col.label);
3690+
table.appendFormatLine('<th data-code="{0}" data-axis="{1}" data-type="{2}" data-label="{3}" class="{4} {5}">{6}{7}</th>'
3691+
, colCode, FRAME_AXIS.COLUMN, col.type, col.label, VP_FE_TABLE_COLUMN, colClass, colIcon, col.label);
34963692
});
34973693
// // add column
34983694
table.appendFormatLine('<th class="{0}"><div class="{1}"></div></th>', VP_FE_ADD_COLUMN, 'vp-icon-plus');
@@ -3713,6 +3909,7 @@ define([
37133909
DROP: 3,
37143910
RENAME: 2,
37153911
AS_TYPE: 10,
3912+
TO_DATETIME: 19,
37163913
REPLACE: 9,
37173914
DISCRETIZE: 15,
37183915

0 commit comments

Comments
 (0)