Skip to main content
replaced http://gis.stackexchange.com/ with https://gis.stackexchange.com/
Source Link

You can do this using the Calculate Value (Data Management) tool and some Python magic. See also this related question: Add arbitrary code to Arcgis model builder?Add arbitrary code to Arcgis model builder?

You can do this using the Calculate Value (Data Management) tool and some Python magic. See also this related question: Add arbitrary code to Arcgis model builder?

You can do this using the Calculate Value (Data Management) tool and some Python magic. See also this related question: Add arbitrary code to Arcgis model builder?

edited body
Source Link
blah238
  • 35.9k
  • 8
  • 96
  • 200
  1. Create a new model -- this will be our "outer" model.

  2. Add a variable of type Folder to allow you to specify where to create the output CSV file.

  3. Add a variable of type String to allow you to specify the name of the output CSV file.

  4. Add the Inner Model to the new model (drag and drop from ArcToolbox or right-click and Add Data or Tool, browse to the inner model and click Add)

  5. Create variables for any parameters of the inner model you want to be able to set from the outer model, such as the Input Workspace (right-click the inner model and and choose Make Variable-From Parameter).

  6. Add the Calculate Value tool to the new model

  7. Paste the following into the appropriate boxes of the Calculate Value tool:

    Expression:

    multivaluesToCsv(r"%Output CSV File Location%", "%Output CSV File Name%", "%Feature Class Names%", "%Minimum Distance Values%", "%Average Distance Values%", "%Maximum Distance Values%")
    
    • This uses in-line variable substitution to pass the model variables into the function. Adjust to match your model variable names.
    • The r before "%Output CSV File Location%" is significant: this indicates that this is a raw string; because Windows file system paths usually contain backslashes (an escape character in Python), we have to use this to prevent Python from misinterpreting the backslashes and subsequent characters as special character sequences.
    • Be sure to put quotes around the in-line variables because without them Python will think they are identifiers instead of strings.
  8. (Optional) Expose the input and output variables as model parameters if you want to be able to run them from the model's tool dialog or chain it together with other models/scripts. The sole output of the outer model is the CSV file.

  9. (Optional) Connect the input variables and inner model outputs to the Calculate Value tool as preconditions. I do not think this actually has any effect, it just makes it more clear visually as to what's going on.

    Code Block:

    import os, csv
    
    def multivaluesToCsv(csvfilepath, csvfilename, fcnames, minvalues, avgvalues, maxvalues):
        ext = 'csv' # Define output file extension (e.g. csv or txt)
        header = ['FC', 'MIN', 'AVG', 'MAX'] # Define header row (column names)
    
        # Join CSV file path and name, adding extension if necessary
        csvfile = os.path.join(csvfilepath, os.extsep.join((csvfilename, ext)) if not os.path.splitext(csvfilename)[1].lower().endswith(ext) else csvfilename)
    
        # Open text file for writing
        with open(csvfile, 'wb') as f:
            w = csv.writer(f)
            w.writerow(header) # Write header row
            rows = zip(*map(lambda x: x.split(';'), [fcnames, minvalues, avgvalues, maxvalues])) # Transpose the semicolon-delimited values into rows
            w.writerows(rows)
        return csvfile
    
  10. (Optional) Expose the input and output variables as model parameters if you want to be able to run them from the model's tool dialog or chain it together with other models/scripts. The sole output of the outer model is the CSV file.

  11. (Optional) Connect the input variables and inner model outputs to the Calculate Value tool as preconditions. I do not think this actually has any effect, it just makes it more clear visually as to what's going on.

  1. Create a new model -- this will be our "outer" model.

  2. Add a variable of type Folder to allow you to specify where to create the output CSV file.

  3. Add a variable of type String to allow you to specify the name of the output CSV file.

  4. Add the Inner Model to the new model (drag and drop from ArcToolbox or right-click and Add Data or Tool, browse to the inner model and click Add)

  5. Create variables for any parameters of the inner model you want to be able to set from the outer model, such as the Input Workspace (right-click the inner model and and choose Make Variable-From Parameter).

  6. Add the Calculate Value tool to the new model

  7. Paste the following into the appropriate boxes of the Calculate Value tool:

    Expression:

    multivaluesToCsv(r"%Output CSV File Location%", "%Output CSV File Name%", "%Feature Class Names%", "%Minimum Distance Values%", "%Average Distance Values%", "%Maximum Distance Values%")
    
    • This uses in-line variable substitution to pass the model variables into the function. Adjust to match your model variable names.
    • The r before "%Output CSV File Location%" is significant: this indicates that this is a raw string; because Windows file system paths usually contain backslashes (an escape character in Python), we have to use this to prevent Python from misinterpreting the backslashes and subsequent characters as special character sequences.
    • Be sure to put quotes around the in-line variables because without them Python will think they are identifiers instead of strings.
  8. (Optional) Expose the input and output variables as model parameters if you want to be able to run them from the model's tool dialog or chain it together with other models/scripts. The sole output of the outer model is the CSV file.

  9. (Optional) Connect the input variables and inner model outputs to the Calculate Value tool as preconditions. I do not think this actually has any effect, it just makes it more clear visually as to what's going on.

    Code Block:

    import os, csv
    
    def multivaluesToCsv(csvfilepath, csvfilename, fcnames, minvalues, avgvalues, maxvalues):
        ext = 'csv' # Define output file extension (e.g. csv or txt)
        header = ['FC', 'MIN', 'AVG', 'MAX'] # Define header row (column names)
    
        # Join CSV file path and name, adding extension if necessary
        csvfile = os.path.join(csvfilepath, os.extsep.join((csvfilename, ext)) if not os.path.splitext(csvfilename)[1].lower().endswith(ext) else csvfilename)
    
        # Open text file for writing
        with open(csvfile, 'wb') as f:
            w = csv.writer(f)
            w.writerow(header) # Write header row
            rows = zip(*map(lambda x: x.split(';'), [fcnames, minvalues, avgvalues, maxvalues])) # Transpose the semicolon-delimited values into rows
            w.writerows(rows)
        return csvfile
    
  1. Create a new model -- this will be our "outer" model.

  2. Add a variable of type Folder to allow you to specify where to create the output CSV file.

  3. Add a variable of type String to allow you to specify the name of the output CSV file.

  4. Add the Inner Model to the new model (drag and drop from ArcToolbox or right-click and Add Data or Tool, browse to the inner model and click Add)

  5. Create variables for any parameters of the inner model you want to be able to set from the outer model, such as the Input Workspace (right-click the inner model and and choose Make Variable-From Parameter).

  6. Add the Calculate Value tool to the new model

  7. Paste the following into the appropriate boxes of the Calculate Value tool:

    Expression:

    multivaluesToCsv(r"%Output CSV File Location%", "%Output CSV File Name%", "%Feature Class Names%", "%Minimum Distance Values%", "%Average Distance Values%", "%Maximum Distance Values%")
    
    • This uses in-line variable substitution to pass the model variables into the function. Adjust to match your model variable names.
    • The r before "%Output CSV File Location%" is significant: this indicates that this is a raw string; because Windows file system paths usually contain backslashes (an escape character in Python), we have to use this to prevent Python from misinterpreting the backslashes and subsequent characters as special character sequences.
    • Be sure to put quotes around the in-line variables because without them Python will think they are identifiers instead of strings.

    Code Block:

    import os, csv
    
    def multivaluesToCsv(csvfilepath, csvfilename, fcnames, minvalues, avgvalues, maxvalues):
        ext = 'csv' # Define output file extension (e.g. csv or txt)
        header = ['FC', 'MIN', 'AVG', 'MAX'] # Define header row (column names)
    
        # Join CSV file path and name, adding extension if necessary
        csvfile = os.path.join(csvfilepath, os.extsep.join((csvfilename, ext)) if not os.path.splitext(csvfilename)[1].lower().endswith(ext) else csvfilename)
    
        # Open text file for writing
        with open(csvfile, 'wb') as f:
            w = csv.writer(f)
            w.writerow(header) # Write header row
            rows = zip(*map(lambda x: x.split(';'), [fcnames, minvalues, avgvalues, maxvalues])) # Transpose the semicolon-delimited values into rows
            w.writerows(rows)
        return csvfile
    
  8. (Optional) Expose the input and output variables as model parameters if you want to be able to run them from the model's tool dialog or chain it together with other models/scripts. The sole output of the outer model is the CSV file.

  9. (Optional) Connect the input variables and inner model outputs to the Calculate Value tool as preconditions. I do not think this actually has any effect, it just makes it more clear visually as to what's going on.

Use nested inner and outer models to avoid Calculate Value running multiple times; function now takes output location and output filename arguments; function returns output text file path
Source Link
blah238
  • 35.9k
  • 8
  • 96
  • 200

To getModel iterators run ALL the processes in the model once per iteration -- this workingis undesirable for our Calculate Value tool, which we just want to run once at the end. The way you willaccomplish this is by creating another, outer model to wrap the original, inner model. This is discussed in the help topic Integrating a model within a model.

So here's what you need to do to get this working:

Inner Model - Iterates feature classes, processes them, collects values:

  1. In your original model, which will be our "inner" model, add another Collect Values tool to collect the Name variable's values so that we can map the distance statistic values to their corresponding feature class names.
  2. Expose the input and output variables as model parameters (right-click an oval and check Model Parameter). Do this for each of the outputs of the Collect Value tools as well as whatever input parameters you need such as the Input Workspace.
  3. Save and close the inner model.

Outer Model - Runs inner model, runs Calculate Value tool just once when inner model completes:

  1. Create a new model -- this will be our "outer" model.

  2. Add another Collect Values tool to collect thea variable of type NameFolder variable's values so that we can map the distance statistic values to their corresponding feature class namesallow you to specify where to create the output CSV file.

  3. Add a variable of type "Text file"String to allow you to specify where to createthe name of the output CSV file.

  4. Add the Inner Model to the new model (drag and drop from ArcToolbox or right-click and Add Data or Tool, browse to the inner model and click Add)

  5. Create variables for any parameters of the inner model you want to be able to set from the outer model, such as the Input Workspace (right-click the inner model and and choose Make Variable-From Parameter).

  6. Add the Calculate Value tool to the new model

  7. Paste the following into the appropriate boxes of the Calculate Value tool:

    Expression:

    multivaluesToCsv(r"%CSVr"%Output File%"CSV File Location%", "%FC"%Output NameCSV Values%"File Name%", "%Feature Class Names%", "%Minimum Distance Values%", "%Average Distance Values%", "%Maximum Distance Values%")
    
    • This uses in-line variable substitution to pass the model variables into the function. Adjust to match your model variable names.
    • The r before "%CSV"%Output File%"CSV File Location%" is significant: this indicates that this is a raw string; because Windows file system paths usually contain backslashes (an escape character in Python), we have to use this to prevent Python from misinterpreting the backslashes and subsequent characters as special character sequences.
    • Be sure to put quotes around the in-line variables because without them Python will think they are identifiers instead of strings.
  8. (Optional) Expose the input and output variables as model parameters if you want to be able to run them from the model's tool dialog or chain it together with other models/scripts. The sole output of the outer model is the CSV file.

  9. (Optional) Connect the input variables and inner model outputs to the Calculate Value tool as preconditions. I do not think this actually has any effect, it just makes it more clear visually as to what's going on.

    Code Block:

    import os, csv
    
    def multivaluesToCsv(csvfilecsvfilepath, csvfilename, fcnames, minvalues, avgvalues, maxvalues):
        ext = 'csv' # Define output file extension (e.g. csv or txt)
        header = ['FC', 'MIN', 'AVG', 'MAX'] # Define header row (column names)
    
        # Join CSV file path and name, adding extension if necessary
        csvfile = os.path.join(csvfilepath, os.extsep.join((csvfilename, ext)) if not os.path.splitext(csvfilename)[1].lower().endswith(ext) else csvfilename)
    
        # Open text file for writing
        with open(csvfile, 'wb') as f:
            w = csv.writer(f)
         columnNames = ["FC", "MIN",w.writerow(header) "AVG",# "MAX"]
    Write header row
       w.writerow(columnNames)
         rows = zip(*map(lambda x: x.split(';'), [fcnames, minvalues, avgvalues, maxvalues])) # Transpose the semicolon-delimited values into rows
            w.writerows(rows)
        return csvfile
    

I have tested this with ModelBuilder and got it working (see screenshotscreenshots).

ModelBuilder screenshot http://img443.imageshack.us/img443/4804/5aaec5643b634b098f57de3.pngInner Model: Inner Model

However there is a quirk with iterators in that allOuter Model: Outer Model

The inner model runs all of theits processes in the model are run once for each iterationper feature class, soand then the Calculate Value tool runs once for each feature class, writing and overwriting the same CSV file several times until it's complete. Inat the end though the output is correct.

I think the "correct" way to avoid that is to embedoutput the iterated part in a sub-model, but I didn't try thatCSV file once and only once.

To get this working you will need to:

  1. Add another Collect Values tool to collect the Name variable's values so that we can map the distance statistic values to their corresponding feature class names.

  2. Add a variable of type "Text file" to allow you to specify where to create the output CSV file.

  3. Paste the following into the appropriate boxes of the Calculate Value tool:

    Expression:

    multivaluesToCsv(r"%CSV File%", "%FC Name Values%", "%Minimum Values%", "%Average Values%", "%Maximum Values%")
    
    • This uses in-line variable substitution to pass the model variables into the function. Adjust to match your model variable names.
    • The r before "%CSV File%" is significant: this indicates that this is a raw string; because Windows file system paths usually contain backslashes (an escape character in Python), we have to use this to prevent Python from misinterpreting the backslashes and subsequent characters as special character sequences.
    • Be sure to put quotes around the in-line variables because without them Python will think they are identifiers instead of strings.

    Code Block:

    import csv
    
    def multivaluesToCsv(csvfile, fcnames, minvalues, avgvalues, maxvalues):
        with open(csvfile, 'wb') as f:
         w = csv.writer(f)
         columnNames = ["FC", "MIN", "AVG", "MAX"]
         w.writerow(columnNames)
         rows = zip(*map(lambda x: x.split(';'), [fcnames, minvalues, avgvalues, maxvalues]))
         w.writerows(rows)
    

I have tested this with ModelBuilder and got it working (see screenshot).

ModelBuilder screenshot http://img443.imageshack.us/img443/4804/5aaec5643b634b098f57de3.png

However there is a quirk with iterators in that all of the processes in the model are run once for each iteration, so the Calculate Value tool runs once for each feature class, writing and overwriting the same CSV file several times until it's complete. In the end though the output is correct.

I think the "correct" way to avoid that is to embed the iterated part in a sub-model, but I didn't try that.

Model iterators run ALL the processes in the model once per iteration -- this is undesirable for our Calculate Value tool, which we just want to run once at the end. The way you accomplish this is by creating another, outer model to wrap the original, inner model. This is discussed in the help topic Integrating a model within a model.

So here's what you need to do to get this working:

Inner Model - Iterates feature classes, processes them, collects values:

  1. In your original model, which will be our "inner" model, add another Collect Values tool to collect the Name variable's values so that we can map the distance statistic values to their corresponding feature class names.
  2. Expose the input and output variables as model parameters (right-click an oval and check Model Parameter). Do this for each of the outputs of the Collect Value tools as well as whatever input parameters you need such as the Input Workspace.
  3. Save and close the inner model.

Outer Model - Runs inner model, runs Calculate Value tool just once when inner model completes:

  1. Create a new model -- this will be our "outer" model.

  2. Add a variable of type Folder to allow you to specify where to create the output CSV file.

  3. Add a variable of type String to allow you to specify the name of the output CSV file.

  4. Add the Inner Model to the new model (drag and drop from ArcToolbox or right-click and Add Data or Tool, browse to the inner model and click Add)

  5. Create variables for any parameters of the inner model you want to be able to set from the outer model, such as the Input Workspace (right-click the inner model and and choose Make Variable-From Parameter).

  6. Add the Calculate Value tool to the new model

  7. Paste the following into the appropriate boxes of the Calculate Value tool:

    Expression:

    multivaluesToCsv(r"%Output CSV File Location%", "%Output CSV File Name%", "%Feature Class Names%", "%Minimum Distance Values%", "%Average Distance Values%", "%Maximum Distance Values%")
    
    • This uses in-line variable substitution to pass the model variables into the function. Adjust to match your model variable names.
    • The r before "%Output CSV File Location%" is significant: this indicates that this is a raw string; because Windows file system paths usually contain backslashes (an escape character in Python), we have to use this to prevent Python from misinterpreting the backslashes and subsequent characters as special character sequences.
    • Be sure to put quotes around the in-line variables because without them Python will think they are identifiers instead of strings.
  8. (Optional) Expose the input and output variables as model parameters if you want to be able to run them from the model's tool dialog or chain it together with other models/scripts. The sole output of the outer model is the CSV file.

  9. (Optional) Connect the input variables and inner model outputs to the Calculate Value tool as preconditions. I do not think this actually has any effect, it just makes it more clear visually as to what's going on.

    Code Block:

    import os, csv
    
    def multivaluesToCsv(csvfilepath, csvfilename, fcnames, minvalues, avgvalues, maxvalues):
        ext = 'csv' # Define output file extension (e.g. csv or txt)
        header = ['FC', 'MIN', 'AVG', 'MAX'] # Define header row (column names)
    
        # Join CSV file path and name, adding extension if necessary
        csvfile = os.path.join(csvfilepath, os.extsep.join((csvfilename, ext)) if not os.path.splitext(csvfilename)[1].lower().endswith(ext) else csvfilename)
    
        # Open text file for writing
        with open(csvfile, 'wb') as f:
            w = csv.writer(f)
            w.writerow(header) # Write header row
            rows = zip(*map(lambda x: x.split(';'), [fcnames, minvalues, avgvalues, maxvalues])) # Transpose the semicolon-delimited values into rows
            w.writerows(rows)
        return csvfile
    

I have tested this with ModelBuilder and got it working (see screenshots).

Inner Model: Inner Model

Outer Model: Outer Model

The inner model runs all of its processes once per feature class, and then the Calculate Value tool runs once at the end to output the CSV file once and only once.

added raw string link
Source Link
blah238
  • 35.9k
  • 8
  • 96
  • 200
Loading
added more information, related question link, ModelBuilder screenshot and improved formatting/structure
Source Link
blah238
  • 35.9k
  • 8
  • 96
  • 200
Loading
edited body
Source Link
blah238
  • 35.9k
  • 8
  • 96
  • 200
Loading
Source Link
blah238
  • 35.9k
  • 8
  • 96
  • 200
Loading