/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/table.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/table.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1019 by jan, Fri May 23 12:56:34 2003 UTC revision 1599 by bh, Mon Aug 18 12:45:28 2003 UTC
# Line 2  Line 2 
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  # Jan-Oliver Wagner <[email protected]>  # Jan-Oliver Wagner <[email protected]>
5    # Frank Koormann <[email protected]>
6  #  #
7  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
8  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
# Line 131  class DBFTable(TitledObject, OldTableInt Line 132  class DBFTable(TitledObject, OldTableInt
132      # work because a DBF file object buffers some data      # work because a DBF file object buffers some data
133    
134      def __init__(self, filename):      def __init__(self, filename):
135          self.filename = filename          self.filename = os.path.abspath(filename)
136          title = os.path.basename(self.filename)  
137            # Omit the extension in the title as it's not really needed and
138            # it can be confusing because dbflib removes extensions and
139            # appends some variations of '.dbf' before it tries to open the
140            # file. So the title could be e.g. myshapefile.shp when the real
141            # filename is myshapefile.dbf
142            title = os.path.splitext(os.path.basename(self.filename))[0]
143          TitledObject.__init__(self, title)          TitledObject.__init__(self, title)
144    
145          self.dbf = dbflib.DBFFile(filename)          self.dbf = dbflib.DBFFile(filename)
146    
147          # If true, self.dbf is open for writing.          # If true, self.dbf is open for writing.
# Line 229  class DBFTable(TitledObject, OldTableInt Line 237  class DBFTable(TitledObject, OldTableInt
237    
238      # DBF specific interface parts.      # DBF specific interface parts.
239    
240        def Width(self, col):
241            """Return column width"""
242            return self.column_map[col].width
243    
244      def Destroy(self):      def Destroy(self):
245          self.dbf.close()          self.dbf.close()
246          self.dbf = None          self.dbf = None
# Line 346  class MemoryTable(TitledObject, OldTable Line 358  class MemoryTable(TitledObject, OldTable
358          return min(values), max(values)          return min(values), max(values)
359    
360      def UniqueValues(self, col):      def UniqueValues(self, col):
361          """Return a sorted list of all unique values in the column col"""          """Return a sorted list of all unique values in the column col
362    
363            col can be either column index or name.
364            """
365          dict = {}          dict = {}
366    
367          for i in range(self.NumRows()):          for i in range(self.NumRows()):
# Line 357  class MemoryTable(TitledObject, OldTable Line 372  class MemoryTable(TitledObject, OldTable
372          values.sort()          values.sort()
373          return values          return values
374    
375        def Width(self, col):
376            """Return the maximum width of values in the column
377    
378            The return value is the the maximum length of string
379            representation of the values in the column (represented by index
380            or name).
381            """
382            max = 0
383    
384            type  = self.column_map[col].type
385            index = self.column_map[col].index
386            values = [row[index] for row in self.data]
387            if not values:
388                return None
389    
390            if type == FIELDTYPE_DOUBLE:
391                format = "%.12f"
392            elif type == FIELDTYPE_INT:
393                format = "%d"
394            else:
395                format = "%s"
396            for value in values:
397                l = len(format % value)
398                if l > max:
399                    max = l
400    
401            return max
402    
403      def Dependencies(self):      def Dependencies(self):
404          """Return an empty sequence. The MemoryTable doesn't depend on anything          """Return an empty sequence. The MemoryTable doesn't depend on anything
405          """          """
# Line 368  class MemoryTable(TitledObject, OldTable Line 411  class MemoryTable(TitledObject, OldTable
411          # TODO: Allow values to be a dictionary and write the single          # TODO: Allow values to be a dictionary and write the single
412          # fields that are specified.          # fields that are specified.
413          self.data[record] = values          self.data[record] = values
414    
415    
416    
417    def _find_dbf_column_names(names):
418        """Determine the column names to use in a DBF file
419    
420        DBF files have a length limit of 10 characters on the column names
421        so when writing an arbitrary Thuban table to a DBF file we may have
422        we may have to rename some of the columns making sure that they're
423        unique in the DBF file too.
424    
425        Names that are already short enough will stay the same. Longer names
426        will be truncated to 10 characters or if that isn't unique it will
427        be truncated more and filled up with digits.
428    
429        The parameter names should be a list of the column names. The return
430        value will be a dictionary mapping the names in the input list to
431        the names to use in the DBF file.
432        """
433        # mapping from the original names in table to the names in the DBF
434        # file
435        name_map = {}
436    
437        # First, we keep all names that are already short enough
438        for i in range(len(names) - 1, -1, -1):
439            if len(names[i]) <= 10:
440                name_map[names[i]] = names[i]
441                del names[i]
442    
443        # dict used as a set of all names already used as DBF column names
444        used = name_map.copy()
445    
446        # Go through all longer names. If the name truncated to 10
447        # characters is not used already, we use that. Otherwise we truncate
448        # it more and append numbers until we get an unused name
449        for name in names:
450            truncated = name[:10]
451            num = 0; numstr = ""
452            #print "truncated", truncated, num
453            while truncated in used and len(numstr) < 10:
454                num += 1
455                numstr = str(num)
456                truncated = name[:10 - len(numstr)] + numstr
457                #print "truncated", truncated, num
458            if len(numstr) >= 10:
459                # This case should never happen in practice as tables with
460                # 10^10 columns seem very unlikely :)
461                raise ValueError("Can't find unique dbf column name")
462    
463            name_map[name] = truncated
464            used[truncated] = 1
465    
466        return name_map
467    
468    def table_to_dbf(table, filename, rows = None):
469        """Create the dbf file filename from the table.
470        
471        If rows is not None (the default) then it must be a list of row
472        indices to be saved to the file, otherwise all rows are saved.
473        """
474    
475        dbf = dbflib.create(filename)
476    
477        dbflib_fieldtypes = {FIELDTYPE_STRING: dbflib.FTString,
478                             FIELDTYPE_INT: dbflib.FTInteger,
479                             FIELDTYPE_DOUBLE: dbflib.FTDouble}
480    
481    
482        name_map = _find_dbf_column_names([col.name for col in table.Columns()])
483    
484        # Initialise the header. Distinguish between DBFTable and others.
485        for col in table.Columns():
486            width = table.Width(col.name)
487            if col.type == FIELDTYPE_DOUBLE:
488                prec = getattr(col, "prec", 12)
489            else:
490                prec = 0
491            dbf.add_field(name_map[col.name], dbflib_fieldtypes[col.type],
492                          width, prec)
493    
494        if rows is None:
495            rows = range(table.NumRows())
496    
497        recNum = 0
498        for i in rows:
499            record = {}
500            for key, value in table.ReadRowAsDict(i).items():
501                record[name_map[key]] = value
502            dbf.write_record(recNum, record)
503            recNum += 1
504        dbf.close()
505    
506    def table_to_csv(table, filename, rows = None):
507        """Export table to csv file.
508        
509        If rows is not None (the default) then it must be a list of row
510        indices to be saved to the file, otherwise all rows are saved.
511        """
512    
513        file = open(filename,"w")
514        columns = table.Columns()
515        if columns:
516            header = "#%s" % columns[0].name
517            for col in columns[1:]:
518                header = header + ",%s" % col.name
519            header = header + "\n"
520            file.write(header)
521    
522            if rows is None:
523                rows = range(table.NumRows())
524    
525            for i in rows:
526                record = table.ReadRowAsDict(i)
527                if len(record):
528                    line = "%s" % record[columns[0].name]
529                    for col in columns[1:]:
530                        line = line + ",%s" % record[col.name]
531                line = line + "\n"
532                file.write(line)
533        file.close()
534    

Legend:
Removed from v.1019  
changed lines
  Added in v.1599

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26