2424import tempfile
2525import numpy as np
2626import pandas as pd
27+ from pandas .api .types import is_datetime64_any_dtype as is_datetime
2728import string
2829from PySide2 import QtCore , QtGui
2930from PySide2 .QtCore import QObject , Signal , Slot
3839FONTSIZE = 12
3940FONTSTYLE = ''
4041COLUMNWIDTH = 80
42+ TIMEFORMAT = '%m/%d/%Y'
4143
4244try :
4345 _fromUtf8 = QtCore .QString .fromUtf8
@@ -59,6 +61,13 @@ def _fromUtf8(s):
5961 'subtable' :'subtable' ,'clear' :'clear'
6062 }
6163
64+ timeformats = ['infer' ,'%d/%m/%Y' ,'%d/%m/%y' ,
65+ '%Y/%m/%d' ,'%y/%m/%d' ,'%Y/%d/%m' ,
66+ '%d%m%Y' ,'%Y%m%d' ,'%Y%d%m' ,
67+ '%d-%b-%Y' ,
68+ '%Y-%m-%d %H:%M:%S' ,'%Y-%m-%d %H:%M' ,
69+ '%d-%m-%Y %H:%M:%S' ,'%d-%m-%Y %H:%M' ]
70+
6271class ColumnHeader (QHeaderView ):
6372 def __init__ (self ):
6473 super (QHeaderView , self ).__init__ ()
@@ -323,21 +332,32 @@ def findDuplicates(self):
323332 'tooltip' :'Remove duplicates' },
324333 'useselected' : {'type' :'checkbox' ,'default' :0 ,'label' :'Use selected columns' },
325334 'keep' :{'label' :'Keep' ,'type' :'combobox' ,'default' :'first' ,
326- 'items' :['first' ,'last' ], 'tooltip' :'values to keep' }
335+ 'items' :['first' ,'last' ], 'tooltip' :'values to keep' },
336+ 'inplace' :{'type' :'checkbox' ,'default' :0 ,'label' :'In place' },
327337 }
328338 dlg = dialogs .MultipleInputDialog (self , opts , title = 'Clean Data' )
329339 dlg .exec_ ()
330340 if not dlg .accepted :
331341 return
332342 kwds = dlg .values
333- cols = df .columns
334343 keep = kwds ['keep' ]
335344 remove = kwds ['remove' ]
345+ inplace = kwds ['inplace' ]
346+ if kwds ['useselected' ] == 1 :
347+ idx = self .table .getSelectedColumns ()
348+ cols = df .columns [idx ]
349+ else :
350+ cols = df .columns
351+
336352 new = df [df .duplicated (subset = cols ,keep = keep )]
337353 if remove == True :
338- self .table .model .df = df .drop_duplicates (subset = cols ,keep = keep )
339- self .refresh ()
340- if len (new )> 0 :
354+ new = df .drop_duplicates (subset = cols ,keep = keep )
355+ if inplace == True :
356+ self .table .model .df = new
357+ self .refresh ()
358+ elif len (new )> 0 :
359+ self .showSubTable (new )
360+ else :
341361 self .showSubTable (new )
342362 return
343363
@@ -723,13 +743,11 @@ def convertDates(self, column):
723743 colname = '-'.join(cols)
724744 temp = df[cols]'''
725745
726- timeformats = ['infer' ,'%d/%m/%Y' ,'%Y/%m/%d' ,'%Y/%d/%m' ,
727- '%Y-%m-%d %H:%M:%S' ,'%Y-%m-%d %H:%M' ,
728- '%d-%m-%Y %H:%M:%S' ,'%d-%m-%Y %H:%M' ]
729746 props = ['' ,'day' ,'dayofweek' ,'month' ,'hour' ,'minute' ,'second' ,'microsecond' ,'year' ,
730747 'dayofyear' ,'weekofyear' ,'quarter' ,'days_in_month' ,'is_leap_year' ]
731- opts = {'format' : {'type' :'combobox' ,'default' :'int' ,
748+ opts = {'format' : {'type' :'combobox' ,'default' :'int' ,'editable' : True ,
732749 'items' :timeformats ,'label' :'Conversion format' },
750+ 'errors' :{'type' :'combobox' ,'items' :['ignore' ,'coerce' ],'default' :'ignore' ,'label' :'Errors' },
733751 'prop' : {'type' :'combobox' ,'default' :'int' ,
734752 'items' :props ,'label' :'Extract from datetime' } }
735753
@@ -741,12 +759,16 @@ def convertDates(self, column):
741759
742760 format = kwds ['format' ]
743761 prop = kwds ['prop' ]
762+ errors = kwds ['errors' ]
763+ infer = False
744764 if format == 'infer' :
745765 format = None
746-
766+ infer = True
747767 temp = df [column ]
768+ self .table .storeCurrent ()
748769 if temp .dtype != 'datetime64[ns]' :
749- temp = pd .to_datetime (temp , format = format )
770+ temp = pd .to_datetime (temp , format = format , infer_datetime_format = infer ,
771+ errors = errors )
750772
751773 if prop != '' :
752774 new = getattr (temp .dt , prop )
@@ -1015,13 +1037,14 @@ class DataFrameTable(QTableView):
10151037 QTableView with pandas DataFrame as model.
10161038 """
10171039 def __init__ (self , parent = None , dataframe = None , font = 'Arial' ,
1018- fontsize = 12 , columnwidth = 80 , align = None , ** kwargs ):
1040+ fontsize = 12 , columnwidth = 80 , timeformat = '%m-%d-%Y' , ** kwargs ):
10191041
10201042 QTableView .__init__ (self )
10211043 self .parent = parent
10221044 self .font = font
10231045 self .fontsize = fontsize
1024- self .columnwidth = columnwidth
1046+ self .columnwidth = columnwidth
1047+ self .timeformat = timeformat
10251048 self .clicked .connect (self .showSelection )
10261049 #self.doubleClicked.connect(self.handleDoubleClick)
10271050 #self.setSelectionBehavior(QTableView.SelectRows)
@@ -1126,7 +1149,7 @@ def getMemory(self):
11261149
11271150 m = self .model .df .memory_usage (deep = True ).sum ()
11281151 if m > 1e5 :
1129- m = int (m / 1048576 )
1152+ m = round (m / 1048576 , 2 )
11301153 units = 'MB'
11311154 else :
11321155 units = 'Bytes'
@@ -1507,9 +1530,12 @@ def data(self, index, role=QtCore.Qt.DisplayRole):
15071530 i = index .row ()
15081531 j = index .column ()
15091532 coltype = self .df .dtypes [j ]
1533+ isdate = is_datetime (coltype )
15101534 if role == QtCore .Qt .DisplayRole :
15111535 value = self .df .iloc [i , j ]
1512- if type (value ) != str :
1536+ if isdate :
1537+ return value .strftime (TIMEFORMAT )
1538+ elif type (value ) != str :
15131539 if type (value ) in [float ,np .float64 ] and np .isnan (value ):
15141540 return ''
15151541 elif type (value ) == np .float :
0 commit comments