def accept(self): super(AddAttributesDialog, self).accept() newColumn = self.columnNameLineEdit.text() dtype = SupportedDtypes.dtype(self.dataTypeComboBox.currentText()) defaultValue = self.defaultValueLineEdit.text() try: if dtype in (SupportedDtypes.intTypes() + SupportedDtypes.uintTypes()): defaultValue = int(defaultValue) elif dtype in SupportedDtypes.floatTypes(): defaultValue = float(defaultValue) elif dtype in SupportedDtypes.boolTypes(): defaultValue = defaultValue.lower() in ['t', '1'] elif dtype in SupportedDtypes.datetimeTypes(): defaultValue = Timestamp(defaultValue) if isinstance(defaultValue, NaTType): defaultValue = Timestamp('') else: defaultValue = dtype.type() except ValueError: defaultValue = dtype.type() self.accepted.emit(newColumn, dtype, defaultValue)
def initUi(self): self.setModal(True) self.resize(303, 168) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) self.setSizePolicy(sizePolicy) self.verticalLayout = QtGui.QVBoxLayout(self) self.dialogHeading = QtGui.QLabel( self.tr('Add a new attribute column'), self) self.gridLayout = QtGui.QGridLayout() self.columnNameLineEdit = QtGui.QLineEdit(self) self.columnNameLabel = QtGui.QLabel(self.tr('Name'), self) self.dataTypeComboBox = QtGui.QComboBox(self) self.dataTypeComboBox.addItems(SupportedDtypes.names()) self.columnTypeLabel = QtGui.QLabel(self.tr('Type'), self) self.defaultValueLineEdit = QtGui.QLineEdit(self) self.lineEditValidator = DefaultValueValidator(self) self.defaultValueLineEdit.setValidator(self.lineEditValidator) self.defaultValueLabel = QtGui.QLabel(self.tr('Inital Value(s)'), self) self.gridLayout.addWidget(self.columnNameLabel, 0, 0, 1, 1) self.gridLayout.addWidget(self.columnNameLineEdit, 0, 1, 1, 1) self.gridLayout.addWidget(self.columnTypeLabel, 1, 0, 1, 1) self.gridLayout.addWidget(self.dataTypeComboBox, 1, 1, 1, 1) self.gridLayout.addWidget(self.defaultValueLabel, 2, 0, 1, 1) self.gridLayout.addWidget(self.defaultValueLineEdit, 2, 1, 1, 1) self.buttonBox = QtGui.QDialogButtonBox(self) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok) self.verticalLayout.addWidget(self.dialogHeading) self.verticalLayout.addLayout(self.gridLayout) self.verticalLayout.addWidget(self.buttonBox) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.dataTypeComboBox.currentIndexChanged.connect( self.updateValidatorDtype) self.updateValidatorDtype(self.dataTypeComboBox.currentIndex())
def data(self, index, role=Qt.DisplayRole): """Retrieve the data stored in the model at the given `index`. Args: index (QtCore.QModelIndex): The model index, which points at a data object. role (Qt.ItemDataRole, optional): Defaults to `Qt.DisplayRole`. You have to use different roles to retrieve different data for an `index`. Accepted roles are `Qt.DisplayRole`, `Qt.EditRole` and `DTYPE_ROLE`. Returns: None if an invalid index is given, the role is not accepted by the model or the column is greater than `1`. The column name will be returned if the given column number equals `0` and the role is either `Qt.DisplayRole` or `Qt.EditRole`. The datatype will be returned, if the column number equals `1`. The `Qt.DisplayRole` or `Qt.EditRole` return a human readable, translated string, whereas the `DTYPE_ROLE` returns the raw data type. """ # an index is invalid, if a row or column does not exist or extends # the bounds of self.columnCount() or self.rowCount() # therefor a check for col>1 is unnecessary. if not index.isValid(): return None col = index.column() #row = self._dataFrame.columns[index.column()] columnName = self._dataFrame.columns[index.row()] columnDtype = self._dataFrame[columnName].dtype if role == Qt.DisplayRole or role == Qt.EditRole: if col == 0: if columnName == index.row(): return index.row() return columnName elif col == 1: return SupportedDtypes.description(columnDtype) elif role == DTYPE_ROLE: if col == 1: return columnDtype else: return None
class PandasCellPayload(MimeDataPayload): _allowedDtypes = SupportedDtypes.allTypes() def __init__(self, dfindex, column, value, dtype, parentId): """store dataframe information in a pickable object Args: dfindex (pandas.index): index of the dragged data. column (str): name of column to be dragged. value (object): value on according position. dtype (pandas dtype): data type of column. parentId (str): hex(id(...)) of according DataFrameModel. """ super(PandasCellPayload, self).__init__() self.dfindex = dfindex self.column = column self.value = value self.dtype = dtype self.parentId = parentId def setAllowedDtypes(self, dtypes): """set the allowed dtypes used by the dropped widget to determin if we accept or decline the data. Defaults to allTypes. Args: dtypes(SupportedDtypes type): combination of SupportedDtypes types. e.x. SupportedDtypes.intTypes() + SupportedDtypes.floatTypes() """ self._allowedDtypes = dtypes def allowedDtypes(self): """return allowedDtypes""" return self._allowedDtypes def isValid(self): """check if the dtype is in allowedDtypes. Used to accept or decline a drop in the view.""" if self.dtype in self._allowedDtypes: return True else: return False
def addDataFrameColumn(self, columnName, dtype, defaultValue): if not self.editable or dtype not in SupportedDtypes.allTypes(): return False elements = self.rowCount() columnPosition = self.columnCount() newColumn = pandas.Series([defaultValue] * elements, index=self._dataFrame.index, dtype=dtype) self.beginInsertColumns(QtCore.QModelIndex(), columnPosition - 1, columnPosition - 1) try: self._dataFrame.insert(columnPosition, columnName, newColumn, allow_duplicates=False) except ValueError, e: # columnName does already exist return False
def test_data(self, dataframe): model = ColumnDtypeModel(dataFrame=dataframe) index = model.index(0, 0) # get data for display role ret = index.data() assert ret == 'Foo' # edit role does the same as display role ret = index.data(Qt.EditRole) assert ret == 'Foo' # datatype only defined for column 1 ret = index.data(DTYPE_ROLE) assert ret == None # datatype column index = index.sibling(0, 1) ret = index.data(DTYPE_ROLE).toPyObject() assert ret == numpy.dtype(numpy.int64) # check translation / display text assert (index.data().toPyObject() == 'integer (64 bit)' == SupportedDtypes.description(ret)) # column not defined index = index.sibling(0, 2) assert index.data(DTYPE_ROLE) == None # invalid index index = QtCore.QModelIndex() assert model.data(index) == None index = model.index(2, 0) # get data for display role ret = index.data() assert ret == 'Spam'
def createEditor(self, parent, option, index): """Creates an Editor Widget for the given index. Enables the user to manipulate the displayed data in place. An editor is created, which performs the change. The widget used will be a `QComboBox` with all available datatypes in the `pandas` project. Args: parent (QtCore.QWidget): Defines the parent for the created editor. option (QtGui.QStyleOptionViewItem): contains all the information that QStyle functions need to draw the items. index (QtCore.QModelIndex): The item/index which shall be edited. Returns: QtGui.QWidget: he widget used to edit the item specified by index for editing. """ combo = QtGui.QComboBox(parent) combo.addItems(SupportedDtypes.names()) combo.currentIndexChanged.connect(self.currentIndexChanged) return combo
def setData(self, index, value, role=DTYPE_CHANGE_ROLE): """Updates the datatype of a column. The model must be initated with a dataframe already, since valid indexes are necessary. The `value` is a translated description of the data type. The translations can be found at `dtocean_qt.translation.DTypeTranslator`. If a datatype can not be converted, e.g. datetime to integer, a `NotImplementedError` will be raised. Args: index (QtCore.QModelIndex): The index of the column to be changed. value (str): The description of the new datatype, e.g. `positive kleine ganze Zahl (16 Bit)`. role (Qt.ItemDataRole, optional): The role, which accesses and changes data. Defaults to `DTYPE_CHANGE_ROLE`. Raises: NotImplementedError: If an error during conversion occured. Returns: bool: `True` if the datatype could be changed, `False` if not or if the new datatype equals the old one. """ if role != DTYPE_CHANGE_ROLE or not index.isValid(): return False if not self.editable(): return False self.layoutAboutToBeChanged.emit() dtype = SupportedDtypes.dtype(value) currentDtype = np.dtype(index.data(role=DTYPE_ROLE).toPyObject()) if dtype is not None: if dtype != currentDtype: col = index.column() #row = self._dataFrame.columns[index.column()] columnName = self._dataFrame.columns[index.row()] try: if dtype == np.dtype('<M8[ns]'): if currentDtype in SupportedDtypes.boolTypes(): raise Exception, u"Can't convert a boolean value into a datetime value." self._dataFrame[columnName] = self._dataFrame[ columnName].apply(pandas.to_datetime) else: self._dataFrame[columnName] = self._dataFrame[ columnName].astype(dtype) self.dtypeChanged.emit(index.row(), dtype) self.layoutChanged.emit() return True except Exception, e: message = 'Could not change datatype %s of column %s to datatype %s' % ( currentDtype, columnName, dtype) self.changeFailed.emit(message, index, dtype) raise
class DataFrameModel(QtCore.QAbstractTableModel): """data model for use in QTableView, QListView, QComboBox, etc. Attributes: timestampFormat (unicode): formatting string for conversion of timestamps to QtCore.QDateTime. Used in data method. sortingAboutToStart (QtCore.pyqtSignal): emitted directly before sorting starts. sortingFinished (QtCore.pyqtSignal): emitted, when sorting finished. dtypeChanged (Signal(columnName)): passed from related ColumnDtypeModel if a columns dtype has changed. changingDtypeFailed (Signal(columnName, index, dtype)): passed from related ColumnDtypeModel. emitted after a column has changed it's data type. dataChanged (Signal): Emitted, if data has changed, e.x. finished loading, new columns added or removed. It's not the same as layoutChanged. Usefull to reset delegates in the view. """ _float_precisions = { "float16": numpy.finfo(numpy.float16).precision - 2, "float32": numpy.finfo(numpy.float32).precision - 1, "float64": numpy.finfo(numpy.float64).precision - 1 } """list of int datatypes for easy checking in data() and setData()""" _intDtypes = SupportedDtypes.intTypes() + SupportedDtypes.uintTypes() """list of float datatypes for easy checking in data() and setData()""" _floatDtypes = SupportedDtypes.floatTypes() """list of bool datatypes for easy checking in data() and setData()""" _boolDtypes = SupportedDtypes.boolTypes() """list of datetime datatypes for easy checking in data() and setData()""" _dateDtypes = SupportedDtypes.datetimeTypes() _timestampFormat = Qt.ISODate # Number of rows to display per fetch _row_batch_count = 100 sortingAboutToStart = Signal() sortingFinished = Signal() dtypeChanged = Signal(int, object) changingDtypeFailed = Signal(object, QtCore.QModelIndex, object) dataChanged = Signal() dataFrameChanged = Signal() def __init__(self, dataFrame=None, copyDataFrame=False): """the __init__ method. Args: dataFrame (pandas.core.frame.DataFrame, optional): initializes the model with given DataFrame. If none is given an empty DataFrame will be set. defaults to None. copyDataFrame (bool, optional): create a copy of dataFrame or use it as is. defaults to False. If you use it as is, you can change it from outside otherwise you have to reset the dataFrame after external changes. Attributes: freeze_first (bool, optional): Do not allow the first column to be modified after initialisation. """ super(DataFrameModel, self).__init__() self._dataFrame = pandas.DataFrame() if dataFrame is not None: self.setDataFrame(dataFrame, copyDataFrame=copyDataFrame) self.dataChanged.emit() self._dataFrameOriginal = None self._search = DataSearch("nothing", "") self.editable = False self.freeze_first = False self.rowsLoaded = DataFrameModel._row_batch_count return def dataFrame(self): """getter function to _dataFrame. Holds all data. Note: It's not implemented with python properties to keep Qt conventions. """ return self._dataFrame def setDataFrame(self, dataFrame, copyDataFrame=False): """setter function to _dataFrame. Holds all data. Note: It's not implemented with python properties to keep Qt conventions. Raises: TypeError: if dataFrame is not of type pandas.core.frame.DataFrame. Args: dataFrame (pandas.core.frame.DataFrame): assign dataFrame to _dataFrame. Holds all the data displayed. copyDataFrame (bool, optional): create a copy of dataFrame or use it as is. defaults to False. If you use it as is, you can change it from outside otherwise you have to reset the dataFrame after external changes. """ if not isinstance(dataFrame, pandas.core.frame.DataFrame): raise TypeError("not of type pandas.core.frame.DataFrame") self.layoutAboutToBeChanged.emit() if copyDataFrame: self._dataFrame = dataFrame.copy() else: self._dataFrame = dataFrame self._columnDtypeModel = ColumnDtypeModel(dataFrame) self._columnDtypeModel.dtypeChanged.connect(self.propagateDtypeChanges) self._columnDtypeModel.changeFailed.connect( lambda columnName, index, dtype: self.changingDtypeFailed.emit( columnName, index, dtype)) self.layoutChanged.emit() self.dataChanged.emit() self.dataFrameChanged.emit() @Slot(int, object) def propagateDtypeChanges(self, column, dtype): self.dtypeChanged.emit(column, dtype) @property def timestampFormat(self): """getter to _timestampFormat""" return self._timestampFormat @timestampFormat.setter def timestampFormat(self, timestampFormat): """setter to _timestampFormat. Formatting string for conversion of timestamps to QtCore.QDateTime Raises: AssertionError: if timestampFormat is not of type unicode. Args: timestampFormat (unicode): assign timestampFormat to _timestampFormat. Formatting string for conversion of timestamps to QtCore.QDateTime. Used in data method. """ if not isinstance(timestampFormat, (unicode, )): raise TypeError('not of type unicode') #assert isinstance(timestampFormat, unicode) or timestampFormat.__class__.__name__ == "DateFormat", "not of type unicode" self._timestampFormat = timestampFormat def headerData(self, section, orientation, role=Qt.DisplayRole): """return the header depending on section, orientation and Qt::ItemDataRole Args: section (int): For horizontal headers, the section number corresponds to the column number. Similarly, for vertical headers, the section number corresponds to the row number. orientation (Qt::Orientations): role (Qt::ItemDataRole): Returns: None if not Qt.DisplayRole _dataFrame.columns.tolist()[section] if orientation == Qt.Horizontal section if orientation == Qt.Vertical None if horizontal orientation and section raises IndexError """ if role != Qt.DisplayRole: return None if orientation == Qt.Horizontal: try: label = self._dataFrame.columns.tolist()[section] if label == section: label = section return label except (IndexError, ): return None elif orientation == Qt.Vertical: return section def data(self, index, role=Qt.DisplayRole): """return data depending on index, Qt::ItemDataRole and data type of the column. Args: index (QtCore.QModelIndex): Index to define column and row you want to return role (Qt::ItemDataRole): Define which data you want to return. Returns: None if index is invalid None if role is none of: DisplayRole, EditRole, CheckStateRole, DATAFRAME_ROLE if role DisplayRole: unmodified _dataFrame value if column dtype is object (string or unicode). _dataFrame value as int or long if column dtype is in _intDtypes. _dataFrame value as float if column dtype is in _floatDtypes. Rounds to defined precision (look at: _float16_precision, _float32_precision). None if column dtype is in _boolDtypes. QDateTime if column dtype is numpy.timestamp64[ns]. Uses timestampFormat as conversion template. if role EditRole: unmodified _dataFrame value if column dtype is object (string or unicode). _dataFrame value as int or long if column dtype is in _intDtypes. _dataFrame value as float if column dtype is in _floatDtypes. Rounds to defined precision (look at: _float16_precision, _float32_precision). _dataFrame value as bool if column dtype is in _boolDtypes. QDateTime if column dtype is numpy.timestamp64[ns]. Uses timestampFormat as conversion template. if role CheckStateRole: Qt.Checked or Qt.Unchecked if dtype is numpy.bool_ otherwise None for all other dtypes. if role DATAFRAME_ROLE: unmodified _dataFrame value. raises TypeError if an unhandled dtype is found in column. """ if not index.isValid(): return None def convertValue(row, col, columnDtype): value = None if columnDtype == object: value = self._dataFrame.iloc[row, col] elif columnDtype in self._floatDtypes: value = round(float(self._dataFrame.iloc[row, col]), self._float_precisions[str(columnDtype)]) elif columnDtype in self._intDtypes: value = int(self._dataFrame.iloc[row, col]) elif columnDtype in self._boolDtypes: # TODO this will most likely always be true # See: http://stackoverflow.com/a/715455 # well no: I am mistaken here, the data is already in the dataframe # so its already converted to a bool value = bool(self._dataFrame.iloc[row, col]) elif columnDtype in self._dateDtypes: #print numpy.datetime64(self._dataFrame.ix[row, col]) value = pandas.Timestamp(self._dataFrame.iloc[row, col]) value = QtCore.QDateTime.fromString(str(value), self.timestampFormat) #print value # else: # raise TypeError, "returning unhandled data type" return value rowi = index.row() coli = index.column() columnDtype = self._dataFrame.dtypes[coli] if role == Qt.DisplayRole: # return the value if you wanne show True/False as text if columnDtype == numpy.bool: result = self._dataFrame.iloc[rowi, coli] else: result = convertValue(rowi, coli, columnDtype) elif role == Qt.EditRole: result = convertValue(rowi, coli, columnDtype) elif role == Qt.CheckStateRole: if columnDtype == numpy.bool_: if convertValue(rowi, coli, columnDtype): result = Qt.Checked else: result = Qt.Unchecked else: result = None elif role == DATAFRAME_ROLE: result = self._dataFrame.iloc[rowi, coli] elif role == Qt.BackgroundRole: if self.freeze_first and coli == 0: return QtGui.QBrush(Qt.lightGray) else: return QtGui.QBrush(Qt.white) elif role == Qt.FontRole: if self.freeze_first and coli == 0: font = QtGui.QFont() font.setBold(True) return font else: return QtGui.QFont elif role == Qt.TextAlignmentRole: if self.freeze_first and coli == 0: return Qt.AlignCenter else: return Qt.AlignLeft | QtCore.Qt.AlignVCenter else: result = None return result def flags(self, index): """Returns the item flags for the given index as ored value, e.x.: Qt.ItemIsUserCheckable | Qt.ItemIsEditable If a combobox for bool values should pop up ItemIsEditable have to set for bool columns too. Args: index (QtCore.QModelIndex): Index to define column and row Returns: if column dtype is not boolean Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable if column dtype is boolean Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable """ flags = super(DataFrameModel, self).flags(index) if not self.editable or (self.freeze_first and index.column() == 0): return flags columnDtype = self._dataFrame.dtypes[index.column()] if columnDtype == numpy.bool: flags |= Qt.ItemIsUserCheckable else: # if you want to have a combobox for bool columns set this flags |= Qt.ItemIsEditable return flags def setData(self, index, value, role=Qt.DisplayRole): """Set the value to the index position depending on Qt::ItemDataRole and data type of the column Args: index (QtCore.QModelIndex): Index to define column and row. value (object): new value. role (Qt::ItemDataRole): Use this role to specify what you want to do. Raises: TypeError: If the value could not be converted to a known datatype. Returns: True if value is changed. Calls layoutChanged after update. False if value is not different from original value. """ if not index.isValid() or not self.editable: return False if value != index.data(role): self.layoutAboutToBeChanged.emit() row = self._dataFrame.index[index.row()] col = self._dataFrame.columns[index.column()] #print 'before change: ', index.data().toUTC(), self._dataFrame.iloc[row][col] columnDtype = self._dataFrame.dtypes[index.column()] if columnDtype == object: if isinstance(value, QtCore.QString): value = str(value) elif columnDtype in self._intDtypes: dtypeInfo = numpy.iinfo(columnDtype) if value < dtypeInfo.min: value = dtypeInfo.min elif value > dtypeInfo.max: value = dtypeInfo.max elif columnDtype in self._floatDtypes: value = numpy.float64(value).astype(columnDtype) elif columnDtype in self._boolDtypes: if isinstance(value, QtCore.QVariant): value = value.toInt()[0] value = numpy.bool_(value) elif columnDtype in self._dateDtypes: # convert the given value to a compatible datetime object. # if the conversation could not be done, keep the original # value. if isinstance(value, QtCore.QDateTime): value = value.toString(self.timestampFormat) elif isinstance(value, QtCore.QVariant): value = value.toString() try: value = pandas.to_datetime(str(value)) except Exception: raise Exception, u"Can't convert '{0}' into a datetime".format( value) return False else: raise TypeError, "try to set unhandled data type" self._dataFrame.set_value(row, col, value) #print 'after change: ', value, self._dataFrame.iloc[row][col] self.layoutChanged.emit() return True else: return False def rowCount(self, index=QtCore.QModelIndex()): """returns number of rows Args: index (QtCore.QModelIndex, optional): Index to define column and row. defaults to empty QModelIndex Returns: number of rows """ # len(df.index) is faster, so use it: # In [12]: %timeit df.shape[0] # 1000000 loops, best of 3: 437 ns per loop # In [13]: %timeit len(df.index) # 10000000 loops, best of 3: 110 ns per loop # In [14]: %timeit df.__len__() # 1000000 loops, best of 3: 215 ns per loop n_rows = len(self._dataFrame.index) if n_rows <= self.rowsLoaded: return n_rows else: return self.rowsLoaded def canFetchMore(self, index=QtCore.QModelIndex()): n_rows = len(self._dataFrame.index) if n_rows > self.rowsLoaded: return True else: return False def fetchMore(self, index=QtCore.QModelIndex()): n_rows = len(self._dataFrame.index) remainder = n_rows - self.rowsLoaded itemsToFetch = min(remainder, DataFrameModel._row_batch_count) self.beginInsertRows(QtCore.QModelIndex(), self.rowsLoaded, self.rowsLoaded + itemsToFetch - 1) self.rowsLoaded += itemsToFetch self.endInsertRows() return def columnCount(self, index=QtCore.QModelIndex()): """returns number of columns Args: index (QtCore.QModelIndex, optional): Index to define column and row. defaults to empty QModelIndex Returns: number of columns """ # speed comparison: # In [23]: %timeit len(df.columns) # 10000000 loops, best of 3: 108 ns per loop # In [24]: %timeit df.shape[1] # 1000000 loops, best of 3: 440 ns per loop return len(self._dataFrame.columns) def sort(self, columnId, order=Qt.AscendingOrder): """sort the model column After sorting the data in ascending or descending order, a signal `layoutChanged` is emitted. Args: columnId (int): columnIndex order (Qt::SortOrder, optional): descending(1) or ascending(0). defaults to Qt.AscendingOrder """ self.layoutAboutToBeChanged.emit() self.sortingAboutToStart.emit() column = self._dataFrame.columns[columnId] self._dataFrame.sort_values(column, ascending=not bool(order), inplace=True) self._dataFrame.reset_index(drop=True, inplace=True) self.layoutChanged.emit() self.sortingFinished.emit() def setFilter(self, search): """apply a filter and hide rows. The filter must be a `DataSearch` object, which evaluates a python expression. If there was an error while parsing the expression, the data will remain unfiltered. Args: search(dtocean_qt.DataSearch): data search object to use. Raises: TypeError: An error is raised, if the given parameter is not a `DataSearch` object. """ if not isinstance(search, DataSearch): raise TypeError( 'The given parameter must an `dtocean_qt.DataSearch` object') self._search = search self.layoutAboutToBeChanged.emit() if self._dataFrameOriginal is not None: self._dataFrame = self._dataFrameOriginal self._dataFrameOriginal = self._dataFrame.copy() self._search.setDataFrame(self._dataFrame) searchIndex, valid = self._search.search() if valid: self._dataFrame = self._dataFrame[searchIndex] self.layoutChanged.emit() else: self.clearFilter() self.layoutChanged.emit() self.dataFrameChanged.emit() def clearFilter(self): """clear all filters. """ if self._dataFrameOriginal is not None: self.layoutAboutToBeChanged.emit() self._dataFrame = self._dataFrameOriginal self._dataFrameOriginal = None self.layoutChanged.emit() def columnDtypeModel(self): """Getter for a ColumnDtypeModel. Returns: ColumnDtypeModel """ return self._columnDtypeModel def enableEditing(self, editable): self.editable = editable self._columnDtypeModel.setEditable(self.editable) def dataFrameColumns(self): return self._dataFrame.columns.tolist() def addDataFrameColumn(self, columnName, dtype, defaultValue): if not self.editable or dtype not in SupportedDtypes.allTypes(): return False elements = self.rowCount() columnPosition = self.columnCount() newColumn = pandas.Series([defaultValue] * elements, index=self._dataFrame.index, dtype=dtype) self.beginInsertColumns(QtCore.QModelIndex(), columnPosition - 1, columnPosition - 1) try: self._dataFrame.insert(columnPosition, columnName, newColumn, allow_duplicates=False) except ValueError, e: # columnName does already exist return False self.endInsertColumns() self.propagateDtypeChanges(columnPosition, newColumn.dtype) return True
def validate(self, s, pos): if not s: # s is emtpy return (QtGui.QValidator.Acceptable, pos) if self.dtype in SupportedDtypes.strTypes(): return (QtGui.QValidator.Acceptable, pos) elif self.dtype in SupportedDtypes.boolTypes(): match = re.match(self.boolPattern, s) if match: return (QtGui.QValidator.Acceptable, pos) else: return (QtGui.QValidator.Invalid, pos) elif self.dtype in SupportedDtypes.datetimeTypes(): try: Timestamp(s) except ValueError: return (QtGui.QValidator.Intermediate, pos) return (QtGui.QValidator.Acceptable, pos) else: dtypeInfo = None if self.dtype in SupportedDtypes.intTypes(): match = re.search(self.intPattern, s) if match: try: value = int(match.string) except ValueError: return (QtGui.QValidator.Invalid, pos) dtypeInfo = numpy.iinfo(self.dtype) elif self.dtype in SupportedDtypes.uintTypes(): match = re.search(self.uintPattern, s) if match: try: value = int(match.string) except ValueError: return (QtGui.QValidator.Invalid, pos) dtypeInfo = numpy.iinfo(self.dtype) elif self.dtype in SupportedDtypes.floatTypes(): match = re.search(self.floatPattern, s) if match: try: value = float(match.string) except ValueError: return (QtGui.QValidator.Invalid, pos) dtypeInfo = numpy.finfo(self.dtype) if dtypeInfo is not None: if value >= dtypeInfo.min and value <= dtypeInfo.max: return (QtGui.QValidator.Acceptable, pos) else: return (QtGui.QValidator.Invalid, pos) else: return (QtGui.QValidator.Invalid, pos) return (QtGui.QValidator.Invalid, pos)
def updateValidatorDtype(self, index): (dtype, name) = SupportedDtypes.tupleAt(index) self.defaultValueLineEdit.clear() self.lineEditValidator.validateType(dtype)