Data in CSV file overwritten

15819
9
Jump to solution
02-05-2015 11:11 AM
LauraBlackburn
New Contributor III

I am exporting my data from multiple Network Anayst VRPs to a CSV file.  I am able to get the data exported to the csv file, but it keeps putting all the data in one row and overwriting it.  I need to be able to advance down to the next row, but I am new to python and not sure how to do this.  any help is greatly appreciated.  Here's the code that writes to the CSV file.

# create table - fields: From script [Block (shortBlockName), Scale (scale)], From Routes layer [stops (OrderCount), dTime (TotalTravelTime), dDistance (TotalDistance)]
        CSVFile = 'F:\\Workspace\\Sandy\\GM_costAnalysis\\analysis2\\allRoutes.csv'
        f = open (CSVFile, "wb")
        w = csv.writer(f)
        fieldNames = ['OrderCount', 'TotalTravelTime', 'TotalDistance', 'Block', 'Scale']
        w.writerow(fieldNames)
        recordList = []
        # print "Data type: " + desc.dataElement.dataType # dataType = layer

        # examine children and print their name and datatype - no children
        lyrFile = arcpy.mapping.Layer(outLayerFile)
        for lyr in arcpy.mapping.ListLayers(lyrFile):
            if lyr.name == "Routes":
                #print "Routes location: " + lyr.datasetName # returns 'Routes'
                #print "Routes long Name: " + lyr.longName   # returns 'TrapRoute_IA1_1K\Routes'
                desc = arcpy.Describe(lyr)
                # indexFields = 0
                # for field in desc.fields:
                #    print "%-22s %s %s" % (field.name, ":", field.type) # this returns all of the fields in the routes table
                cntCursor = arcpy.da.SearchCursor(lyr, "OrderCount")
                for row in cntCursor:
                    cnt = row[0]
                    recordList.append(str(cnt))
                    print ("OrderCount: {}".format(cnt))
                timeCursor = arcpy.da.SearchCursor(lyr, "TotalTravelTime")
                for row in timeCursor:
                    t = row[0]
                    recordList.append(str(t))
                    print ("TravelTime: {}".format(t))
                distCursor = arcpy.da.SearchCursor(lyr,"TotalDistance")
                for row in distCursor:
                    dist = row[0]
                    recordList.append(str(dist))
                    print ("TravelDist: {}".format(dist))
                recordList.append(str(shortBlockName))
                recordList.append(str(scale))
                print ("Records: {}".format(recordList))    # returns:  [102, 144.19780824705958, 61.627489665697794, 'IA1', '1000']
                print ("Block: {}".format(shortBlockName))  # returns: IA1
                print ("Scale: {}".format(scale))           # returns: 1000
        w.writerow(recordList)
        w.next() # returns error - I need a way to move to the next row
    f.close()
# create table - fields: From script [Block (shortBlockName), Scale (scale)], From Routes layer [(OrderCount), (TotalTravelTime), (TotalDistance)]        CSVFile = 'F:\\Workspace\\Sandy\\GM_costAnalysis\\analysis2\\allRoutes.csv'        f = open (CSVFile, "wb")        w = csv.writer(f)        fieldNames = ['OrderCount', 'TotalTravelTime', 'TotalDistance', 'Block', 'Scale']        w.writerow(fieldNames)        recordList = []        # print "Data type: " + desc.dataElement.dataType # dataType = layer        # examine children and print their name and datatype - no children        lyrFile = arcpy.mapping.Layer(outLayerFile)        for lyr in arcpy.mapping.ListLayers(lyrFile):            if lyr.name == "Routes":                #print "Routes location: " + lyr.datasetName # returns 'Routes'                #print "Routes long Name: " + lyr.longName  # returns 'TrapRoute_IA1_1K\Routes'                desc = arcpy.Describe(lyr)                # indexFields = 0                # for field in desc.fields:                #    print "%-22s %s %s" % (field.name, ":", field.type) # this returns all of the fields in the routes table                cntCursor = arcpy.da.SearchCursor(lyr, "OrderCount")                for row in cntCursor:                    cnt = row[0]                    recordList.append(str(cnt))                    print ("OrderCount: {}".format(cnt))                timeCursor = arcpy.da.SearchCursor(lyr, "TotalTravelTime")                for row in timeCursor:                    t = row[0]                    recordList.append(str(t))                    print ("TravelTime: {}".format(t))                distCursor = arcpy.da.SearchCursor(lyr,"TotalDistance")                for row in distCursor:                    dist = row[0]                    recordList.append(str(dist))                    print ("TravelDist: {}".format(dist))                recordList.append(str(shortBlockName))                recordList.append(str(scale))                print ("Records: {}".format(recordList))    # returns:  [102, 144.19780824705958, 61.627489665697794, 'IA1', '1000']                print ("Block: {}".format(shortBlockName))  # returns: IA1                print ("Scale: {}".format(scale))          # returns: 1000        w.writerow(recordList)        w.next() # returns error - I need a way to move to the next row    f.close() 
Tags (2)
1 Solution

Accepted Solutions
BlakeTerhune
MVP Regular Contributor

If you're writing one row at a time, use

w.writerow()

If you're writing all the data at once in some kind of iterable variable, use

w.writerows()

Also, I recommend using the csv writer in a with statement to ensure it is closed even if there is an error. Here is what I use for writing a geodatabase table to csv.

import arcpy
import os
import csv

# Environment variables
workingDir = r"C:\temp"
workingGDB = os.path.join(workingDir, "MyGeodatabase.gdb")
inputTable = os.path.join(workingGDB, "MyInputTable")
outputCSV = os.path.join(workingDir, "MyOutput.csv")

# Create CSV
with open(outputCSV, "w") as csvfile:
    csvwriter = csv.writer(csvfile, delimiter=',', lineterminator='\n')
    ## Write field name header line
    fields = ['FirstField','NextField','AndThirdExample']
    csvwriter.writerow(fields)
    ## Write data rows
    with arcpy.da.SearchCursor(inputTable, fields) as s_cursor:
        for row in s_cursor:
            csvwriter.writerow(row)

View solution in original post

9 Replies
DarrenWiens2
MVP Honored Contributor

The line containing writerow is not within a loop, so it only writes once, after the code exits the for loop. Indent further to include in the loop and write multiple rows.

LauraBlackburn
New Contributor III

When I try to indent my line: w.writerow(recordList), I get 5 blank lines and then 4 duplicate lines of code.  So there is something weird going on here.  I thought I might just be able to add a line return to my record list using recordList.append('\n') but that doesn't do it either.  I am sure this isn't the most elegant way to write code, but it is my first stab at it.

0 Kudos
DanPatterson_Retired
MVP Emeritus

\n is a line return in python but not for most text editors, you may as well just write to the file as you go along...in fact

look at Python's builtin csv module...explore the functionality of 'writer' and reader

>>> import csv
>>> dir(csv)
['Dialect', 'DictReader', 'DictWriter', 'Error', 'QUOTE_ALL', 'QUOTE_MINIMAL',
 'QUOTE_NONE', 'QUOTE_NONNUMERIC', 'Sniffer', 'StringIO', '_Dialect', '__all__',
 '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__version__',
 'excel', 'excel_tab', 'field_size_limit', 'get_dialect', 'list_dialects', 're',
 'reader', 'reduce', 'register_dialect', 'unregister_dialect', 'writer']
>>>
0 Kudos
BlakeTerhune
MVP Regular Contributor

If you're writing one row at a time, use

w.writerow()

If you're writing all the data at once in some kind of iterable variable, use

w.writerows()

Also, I recommend using the csv writer in a with statement to ensure it is closed even if there is an error. Here is what I use for writing a geodatabase table to csv.

import arcpy
import os
import csv

# Environment variables
workingDir = r"C:\temp"
workingGDB = os.path.join(workingDir, "MyGeodatabase.gdb")
inputTable = os.path.join(workingGDB, "MyInputTable")
outputCSV = os.path.join(workingDir, "MyOutput.csv")

# Create CSV
with open(outputCSV, "w") as csvfile:
    csvwriter = csv.writer(csvfile, delimiter=',', lineterminator='\n')
    ## Write field name header line
    fields = ['FirstField','NextField','AndThirdExample']
    csvwriter.writerow(fields)
    ## Write data rows
    with arcpy.da.SearchCursor(inputTable, fields) as s_cursor:
        for row in s_cursor:
            csvwriter.writerow(row)
LauraBlackburn
New Contributor III

I very much appreciate you all taking the time to help!

When I use w.writerows() it breaks up all of my string variables into one character width fields and spits out something like this:

OrderCount,TotalTravelTime,TotalDistance,Block,Scale

1,6

6,7,.,7,7,6,9,4,8,9,7,9,1

2,9,.,2,9,1,2,5,7,6,3,1

I,A,1

3,0,0,0

if I use w.writerow() it keeps writing on the same line, but the format is correct and looks like this:

OrderCount,TotalTravelTime,TotalDistance,Block,Scale

16, 67.7769489791, 29.291257631, IA1, 3000

I know I am close to getting this right, I just need to tell it to write the next list of variables on the following line instead of overwriting.

0 Kudos
BlakeTerhune
MVP Regular Contributor

I don't know what outLayerFile is so this is the best I can do for you. See if you can make this work.

import arcpy
import os
import csv

lyrFile = arcpy.mapping.Layer(outLayerFile)

for lyr in arcpy.mapping.ListLayers(lyrFile):
    if lyr.name == "Routes":
        # Create CSV
        CSVFile = r'F:\Workspace\Sandy\GM_costAnalysis\analysis2\allRoutes.csv'
        with open(outputCSV, "w") as csvfile:
            csvwriter = csv.writer(csvfile, delimiter=',', lineterminator='\n')
            ## Write field name header line
            fields = ['OrderCount', 'TotalTravelTime', 'TotalDistance', 'Block', 'Scale']
            csvwriter.writerow(fields)
            ## Write data rows
            with arcpy.da.SearchCursor(lyr.dataSource, fields) as s_cursor:
                for row in s_cursor:
                    csvwriter.writerow(row)
LauraBlackburn
New Contributor III

Hi Blake,

One quick question for you...if I use the "with open(outputCSV, "w") as csvfile:" do I also need a line to close this file?  If I do, would that be at the same indent level as that "with open" statement?

I did find that my file was being overwritten because the open CSV command was inside of a larger loop, so my code was just doing what I told it.  Now that I have moved the statements to open the CSV and write the headers outside of my main loop for solving the VRP (not shown in the snippets above) I am no longer overwriting my data output.

0 Kudos
BlakeTerhune
MVP Regular Contributor

There is nothing special you have to write to the file to close it, but you do need to close the CSV open object in the code. If you have it in a with statement (like in my code) it will always close automatically. In the code you posted, you do not have it in a with statement so you need the f.close() at the end.

Glad you got it working. Keep in mind that when you open the CSV file for writing, you have different modes to open it as. Use 'r' when the file will only be read, 'w' for only writing (an existing file with the same name will be erased), and 'a' opens the file for appending. Any data written to the file is automatically added to the end. The mode argument is optional; 'r' will be assumed if it’s omitted. If you try using the append mode, make sure you don't write the field name header row again!

LauraBlackburn
New Contributor III

Thanks for all of your help Blake!  Also thanks for the link to the modes, I must have spent over an hour yesterday trying to find exactly what the various CSV format paramaters were w/o any luck.

0 Kudos