~ubuntu-branches/debian/experimental/spyder/experimental

« back to all changes in this revision

Viewing changes to spyderlib/widgets/dataframeeditor.py

  • Committer: Package Import Robot
  • Author(s): Picca Frédéric-Emmanuel, Ghislain Antony Vaillant, Picca Frédéric-Emmanuel
  • Date: 2015-02-26 13:31:59 UTC
  • mfrom: (1.1.23)
  • Revision ID: package-import@ubuntu.com-20150226133159-zvom6ax6mah3irhv
Tags: 2.3.3+dfsg-1~exp1
[Ghislain Antony Vaillant]
* New upstream release.

[Picca Frédéric-Emmanuel]
* Upstream moved to github (watch, control and copyright file updated)

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
from spyderlib.qt.QtGui import (QDialog, QTableView, QColor, QGridLayout,
19
19
                                QDialogButtonBox, QHBoxLayout, QPushButton,
20
20
                                QCheckBox, QMessageBox, QInputDialog,
21
 
                                QLineEdit, QApplication, QMenu)
 
21
                                QLineEdit, QApplication, QMenu, QKeySequence)
22
22
from spyderlib.qt.compat import to_qvariant, from_qvariant
23
23
from spyderlib.utils.qthelpers import (qapplication, get_icon, create_action,
24
24
                                       add_actions, keybinding)
25
25
 
26
26
from spyderlib.baseconfig import _
27
 
from spyderlib.guiconfig import get_font
 
27
from spyderlib.guiconfig import get_font, new_shortcut
28
28
from spyderlib.py3compat import io, is_text_string, to_text_string
29
29
from spyderlib.utils import encoding
30
30
from spyderlib.widgets.arrayeditor import get_idx_rect
39
39
_bool_false = ['false', '0']
40
40
 
41
41
 
 
42
LARGE_SIZE = 5e5
42
43
LARGE_NROWS = 1e5
 
44
LARGE_COLS = 60
43
45
 
44
46
 
45
47
def bool_false_check(value):
62
64
    """ DataFrame Table Model"""
63
65
    
64
66
    ROWS_TO_LOAD = 500
 
67
    COLS_TO_LOAD = 40
65
68
    
66
69
    def __init__(self, dataFrame, format="%.3g", parent=None):
67
70
        QAbstractTableModel.__init__(self)
68
71
        self.dialog = parent
69
72
        self.df = dataFrame
70
73
        self.df_index = dataFrame.index.tolist()
 
74
        self.df_header = dataFrame.columns.tolist()
71
75
        self._format = format
72
 
        self.bgcolor_enabled = True
73
76
        self.complex_intran = None
 
77
        
 
78
        self.total_rows = self.df.shape[0]
 
79
        self.total_cols = self.df.shape[1]
 
80
        size = self.total_rows * self.total_cols
74
81
 
75
82
        huerange = [.66, .99]  # Hue
76
83
        self.sat = .7  # Saturation
79
86
        self.hue0 = huerange[0]
80
87
        self.dhue = huerange[1]-huerange[0]
81
88
        self.max_min_col = None
82
 
        self.max_min_col_update()
83
 
        self.colum_avg_enabled = True
84
 
        self.colum_avg(1)
 
89
        if size < LARGE_SIZE:
 
90
            self.max_min_col_update()
 
91
            self.colum_avg_enabled = True
 
92
            self.bgcolor_enabled = True
 
93
            self.colum_avg(1)
 
94
        else:
 
95
            self.colum_avg_enabled = False
 
96
            self.bgcolor_enabled = False
 
97
            self.colum_avg(0)
85
98
 
86
 
        # To define paging when the number of rows is large
87
 
        self.total_rows = self.df.shape[0]
88
 
        if self.total_rows > LARGE_NROWS:
 
99
        # Use paging when the total size, number of rows or number of
 
100
        # columns is too large
 
101
        if size > LARGE_SIZE:
89
102
            self.rows_loaded = self.ROWS_TO_LOAD
 
103
            self.cols_loaded = self.COLS_TO_LOAD
90
104
        else:
91
 
            self.rows_loaded = self.total_rows
 
105
            if self.total_rows > LARGE_NROWS:
 
106
                self.rows_loaded = self.ROWS_TO_LOAD
 
107
            else:
 
108
                self.rows_loaded = self.total_rows
 
109
            if self.total_cols > LARGE_COLS:
 
110
                self.cols_loaded = self.COLS_TO_LOAD
 
111
            else:
 
112
                self.cols_loaded = self.total_cols
92
113
 
93
114
    def max_min_col_update(self):
94
115
        """Determines the maximum and minimum number in each column"""
101
122
            self.complex_intran = self.df.applymap(lambda e:
102
123
                                                   isinstance(e, _sup_com))
103
124
            mask = float_intran & (~ self.complex_intran)
104
 
            df_abs = self.df[self.complex_intran].abs()
 
125
            try:
 
126
                df_abs = self.df[self.complex_intran].abs()
 
127
            except TypeError:
 
128
                df_abs = self.df[self.complex_intran]
105
129
            max_c = df_abs.max(skipna=True)
106
130
            min_c = df_abs.min(skipna=True)
107
131
            df_real = self.df[mask]
147
171
            if section == 0:
148
172
                return 'Index'
149
173
            else:
150
 
                return to_qvariant(to_text_string(self.df.columns.tolist()
151
 
                                                  [section-1]))
 
174
                return to_qvariant(to_text_string(self.df_header[section-1]))
152
175
        else:
153
176
            return to_qvariant()
154
177
 
293
316
            return self.total_rows
294
317
        else:
295
318
            return self.rows_loaded
296
 
    
297
 
    def canFetchMore(self, index=QModelIndex()):
298
 
        if self.total_rows > self.rows_loaded:
299
 
            return True
300
 
        else:
301
 
            return False
302
 
 
303
 
    def fetchMore(self, index=QModelIndex()):
304
 
        reminder = self.total_rows - self.rows_loaded
305
 
        items_to_fetch = min(reminder, self.ROWS_TO_LOAD)
306
 
        self.beginInsertRows(QModelIndex(), self.rows_loaded,
307
 
                             self.rows_loaded + items_to_fetch - 1)
308
 
        self.rows_loaded += items_to_fetch
309
 
        self.endInsertRows()
 
319
 
 
320
    def can_fetch_more(self, rows=False, columns=False):
 
321
        if rows:
 
322
            if self.total_rows > self.rows_loaded:
 
323
                return True
 
324
            else:
 
325
                return False
 
326
        if columns:
 
327
            if self.total_cols > self.cols_loaded:
 
328
                return True
 
329
            else:
 
330
                return False
 
331
 
 
332
    def fetch_more(self, rows=False, columns=False):
 
333
        if self.can_fetch_more(rows=rows):
 
334
            reminder = self.total_rows - self.rows_loaded
 
335
            items_to_fetch = min(reminder, self.ROWS_TO_LOAD)
 
336
            self.beginInsertRows(QModelIndex(), self.rows_loaded,
 
337
                                 self.rows_loaded + items_to_fetch - 1)
 
338
            self.rows_loaded += items_to_fetch
 
339
            self.endInsertRows()
 
340
        if self.can_fetch_more(columns=columns):
 
341
            reminder = self.total_cols - self.cols_loaded
 
342
            items_to_fetch = min(reminder, self.COLS_TO_LOAD)
 
343
            self.beginInsertColumns(QModelIndex(), self.cols_loaded,
 
344
                                    self.cols_loaded + items_to_fetch - 1)
 
345
            self.cols_loaded += items_to_fetch
 
346
            self.endInsertColumns()
310
347
 
311
348
    def columnCount(self, index=QModelIndex()):
312
349
        """DataFrame column number"""
313
 
        shape = self.df.shape
314
350
        # This is done to implement timeseries
315
 
        if len(shape) == 1:
 
351
        if len(self.df.shape) == 1:
316
352
            return 2
 
353
        elif self.total_cols <= self.cols_loaded:
 
354
            return self.total_cols + 1
317
355
        else:
318
 
            return shape[1]+1
 
356
            return self.cols_loaded + 1
319
357
 
320
358
 
321
359
class DataFrameView(QTableView):
329
367
        self.connect(self.header_class,
330
368
                     SIGNAL("sectionClicked(int)"), self.sortByColumn)
331
369
        self.menu = self.setup_menu()
 
370
        new_shortcut(QKeySequence.Copy, self, self.copy)
 
371
        self.connect(self.horizontalScrollBar(), SIGNAL("valueChanged(int)"),
 
372
                     lambda val: self.load_more_data(val, columns=True))
 
373
        self.connect(self.verticalScrollBar(), SIGNAL("valueChanged(int)"),
 
374
                     lambda val: self.load_more_data(val, rows=True))
 
375
    
 
376
    def load_more_data(self, value, rows=False, columns=False):
 
377
        if rows and value == self.verticalScrollBar().maximum():
 
378
            self.model().fetch_more(rows=rows)
 
379
        if columns and value == self.horizontalScrollBar().maximum():
 
380
            self.model().fetch_more(columns=columns)
332
381
 
333
382
    def sortByColumn(self, index):
334
383
        """ Implement a Column sort """
375
424
        index_list = self.selectedIndexes()
376
425
        [model.setData(i, '', change_type=func) for i in index_list]
377
426
 
378
 
    def copy(self, index=False, header=False):
 
427
    def copy(self):
379
428
        """Copy text to clipboard"""
380
429
        (row_min, row_max,
381
430
         col_min, col_max) = get_idx_rect(self.selectedIndexes())
 
431
        index = header = False
382
432
        if col_min == 0:
383
433
            col_min = 1
384
434
            index = True
387
437
            contents = '\n'.join(map(str, df.index.tolist()[slice(row_min,
388
438
                                                            row_max+1)]))
389
439
        else:  # To copy DataFrame
390
 
            if df.shape[0] == row_max+1 and row_min == 0:
 
440
            if (col_min == 0 or col_min == 1) and (df.shape[1] == col_max):
391
441
                header = True
392
442
            obj = df.iloc[slice(row_min, row_max+1), slice(col_min-1, col_max)]
393
443
            output = io.StringIO()