faqts : Computers : Programming : Languages : Python : Snippets

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

2 of 4 people (50%) answered Yes
Recently 1 of 3 people (33%) answered Yes

Entry

Pivot class

Jul 5th, 2000 10:00
Nathan Wallace, Hans Nowak, Snippet 127, David Stegbauer


"""
Packages: maths;miscellaneous;oop
"""
"""
below is code of my Pivot class. It is inspired by Excel "Pivot Tables" or
database "cross tables". Pivot act as very simple matrix with generalized
indexes - index can be any type with defined ordering (i.e. __cmp__ function in
class) and hash value (i.e. __hash__ function in class).
Pivot only allow setting and getting items and incrementing values. Note, that
if Pivot doesn't contain data for given indexes, it automatically append
required row/column and initially set new values to 0 (zero).
I'm using this class daily about two months in conjunction with my PivotWriter
class (still need to be improved). So Pivot seems to be functional, but it isn't
perfect.
"""
import string
#rows are continuous blocks
#r0c0, r0c1, r0c2, r1c0, r1c1, r1c2, etc...
class Pivot:
    """Pivot: matrix with any type of index and value (numeric prefered)
       1999 David Stegbauer, david.stegbauer@cz.opel.com
       freeware"""
    def __init__(self):
        self.rows = {}  #map row labels to row numbers
        self.rowcnt = 0 #row count
        self.cols = {}  #map column labels to numbers
        self.colcnt = 0 #column count
        self.data = []  #continuous block of own data
    def __del__(self):
        pass
    #---
    def _indexof(self, col, row):
        """calculate index to self.data from row and colum labels
        if such row or column is not present, it is added"""
        if self.rowcnt == 0:     #colcnt has to be also zero...
            self.cols[col] = 0
            self.rows[row] = 0
            self.data.append(0)
            self.rowcnt = 1
            self.colcnt = 1
            return 0
        if not self.cols.has_key(col):  #then append new column
            self.cols[col] = self.colcnt
            for i in xrange(self.rowcnt*self.colcnt, self.colcnt-1,-self.colcnt):
                self.data.insert(i, 0)
            self.colcnt = self.colcnt + 1
        if not self.rows.has_key(row):  #then append new row
            self.rows[row] = self.rowcnt
            self.data = self.data + (self.colcnt) * [0]
            self.rowcnt = self.rowcnt + 1
        return self.rows[row] * self.colcnt + self.cols[col]    #calc index
    def setitem(self, col, row, value):
        """directly set value in Pivot"""
        i = self._indexof(col, row)
        self.data[i] = value
    def getitem(self, col, row):
        """get value from Pivot"""
        i = self._indexof(col, row)
        return self.data[i]
    def increment(self, col, row, val=1):
        """increment value in Pivot, default by one"""
        i = self._indexof(col, row)
        self.data[i] = self.data[i] + val
    def rownames(self):
        """get sorted row labels"""
        rn = self.rows.keys()
        rn.sort()
        return rn
    def colnames(self):
        """get sorted colum labels"""
        cn = self.cols.keys()
        cn.sort()
        return cn
    def coltotals(self):
        """get column totals (sums), bad ordered"""
        tot = (self.colcnt) * [0]
        for j in xrange(len(self.data)):
            i = j % self.colcnt
            tot[i] = tot[i] + self.data[j]
        # TO DO:  sort same as colnames() is
        return tot
    def formatrow(self, row, fmt, sep):
        if not self.rows.has_key(row):
            return ""
        cn = self.cols.keys()
        cn.sort()                   #column indexes
        i = self.rows[row] * self.colcnt   #index base
        r = ""                      #return value
        if type(fmt) != type("") or fmt == "":
            do_fmt = 0
        else:
            do_fmt = 1          #should apply format
        for e in cn:
            if do_fmt:          #apply format
                r = r + fmt % self.data[i + self.cols[e]] + sep
            else:
                r = r + `self.data[i + self.cols[e]]` + sep  #backticks - repr
        return r
    def format(self, itemformat = '', rowsep = '\n', colsep = '\t'):
        cn = self.cols.keys(); cn.sort()
        r =  reduce(lambda x,y,s=colsep: x+str(y)+s, cn, colsep)  #column labels
        cn = map(lambda i, dic=self.cols: dic[i], cn)             #column indexes
        rnames = self.rows.keys(); rnames.sort()                  #row labels
        rn = map(lambda i, dic=self.rows: dic[i], rnames)         #row indexes
        r = r + rowsep
        if type(itemformat) != type("") or itemformat == "":
            do_itemformat = 0
        else:
            do_itemformat = 1          #should apply format
        i = 0
        for row in rn:
            r = r + str(rnames[i]) + colsep; i = i + 1
            for col in cn:
                if do_itemformat:          #apply format
                    r = r + itemformat % self.data[row*self.colcnt + col] + colsep
                else:
                    r = r + str(self.data[row*self.colcnt + col]) + colsep
            r = r + rowsep
        return r