Another wonderful predicament. I am trying to use an instance of ICalculator to update a field based on another field. Textbook stuff. Unfortunately, the example in the SDK for C# is a bit lacking.

Here is what I have puzzled out so far from the C# GeoDatabaseUI 10.x and VB.NET ICalculator 9.3 examples/documentation (NOTE: I am doing this in C#, in case I was not clear).

  1. If you want to use a string in the Expression property, do not use triple quotes (must be legacy information), but escaped quotes for normal string-within-string notation.
  2. You can use VB.NET code in the pre-expression when working in VB.NET (this confuses me).

With these assumptions in mind, I have been attempting to use python or C# in the pre-expression property, but I am having no luck.


Has anyone tried this yet? If so, what is the proper way to use a python function and/or a C# method when working with the ICalculcator?

UPDATE: Okay, trying the method kenbuja suggests below, I changed it to an IGeoProcessor method with the following code:

public void GPCalculate(ITable table)
        IGeoProcessor gp = new GeoProcessorClass();
        IVariantArray varray = new VarArrayClass();
        string input = workspacepath+"\\"+targetfile;

        string codeblock = "states = {'2':'AK', '1':'AL', '5':'AR', '60':'AS', '4':'AZ', '6':'CA', '8':'CO', '9':'CT', '11':'DC', '10':'DE', '12':'FL',"+
            "'13':'GA', '66':'GU', '15':'HI', '19':'IA', '16':'ID', '17':'IL', '18':'IN', '20':'KS', '21':'KY', '22':'LA', '25':'MA', '24':'MD', '23':'ME',"+
            "'26':'MI', '27':'MN', '29':'MO', '28':'MS', '30':'MT', '37':'NC', '38':'ND', '31':'NE', '33':'NH', '34':'NJ', '35':'NM', '32':'NV', '36':'NY',"+
            "'39':'OH', '40':'OK', '41':'OR', '42':'PA', '72':'PR', '44':'RI', '45':'SC', '46':'SD', '47':'TN', '48':'TX', '49':'UT', '51':'VA', '78':'VI',"+
            "'50':'VT', '53':'WA', '55':'WI', '54':'WV', '56':'WY'}\n" +
            "def getstate(id):\n" +
            "  id = str(id)\n"+
            "  if (len(id) == 14):\n" +
            "    id = id[0]\n" +
            "  if (len(id) == 15):\n" +
            "    tid = id[0:2]\n" +
            "  return states[id]";
        // First Parameter in_table
        // Second Parameter calculate field
        // Third Parameter expression
        // Fourth Parameter expression_type (optional)
        // Fifth Parameter Codeblock (optional)

        IGeoProcessorResult result = new GeoProcessorResultClass();
        settesttext("Starting Calculation");
        result = gp.Execute("CalculateField_management", varray, null);

The above code works perfectly now (thanks to an edit @blah238).

  • I am pretty sure that only VBScript and Python are supported, just like the normal Field Calculator dialog and Calculate Field GP tool. I don't see where you specify which language it is though, unless it figures it out on its own somehow. I will say that this seems an awkward way to do it though, why not just use an update cursor?
    – blah238
    Nov 18 '11 at 4:18
  • I already built an update cursor for it, but I would think that the builtin calculator function might be faster. A cursor was running maybe 10k records a minute, and this table in question has 44 million and some change.
    – Nathanus
    Nov 18 '11 at 15:59
  • You might try using the subfields property and creating an index for the attribute, should speed it up, also use a recycling cursor if you weren't already. As for the new code in your question try varray.Add("getstate(!ID!)");
    – blah238
    Nov 18 '11 at 18:07
  • Ah, yes, that did it, @blah238. Thank you so much, you've been a life saver.
    – Nathanus
    Nov 18 '11 at 19:53
  • Cool! Would be interested in seeing the performance stats vs an update cursor.
    – blah238
    Nov 18 '11 at 20:08

Currently in ArcGIS 10, ICalculator has no property that allows you to set the parcer to use Python, so it always defaults to VBScript (bug NIM061356). The workaround would be to use something like the following VBA example to use the Geoprocessor and CalculateField_management tool.

    'Create the Geoprocessor
Dim pGp As IGeoProcessor
Set pGp = New GeoProcessor

'Set Overwriteoutput to True
'pGp.OverwriteOutput = True

'Add the custom toolbox containing the model tool
'pGp.AddToolbox "C:\CustomTools\custom.tbx"

'Create the Parameter array
Dim pParamArray As IVariantArray
Set pParamArray = New VarArray

'Populate array of parameters
'First Parameter:  in_table (e.g. File GDB feature class)
pParamArray.Add "C:\Incidents\845875\Converted_GDB931\downgradedFGDB.gdb\Main_931"

'Second Parameter:  field on which to calculate
pParamArray.Add "LastField"

'Third Parameter:  expression
pParamArray.Add "math.log1p(!SumOfConcentrations!)"

'Fourth Parameter:  expression_type (Optional)  !!!  !!!  !!!  !!!  !!!
pParamArray.Add "PYTHON_9.3"
Dim pResult As IGeoProcessorResult

'Execute the Model tool
Set pResult = pGp.Execute("CalculateField_management", pParamArray, Nothing)

'Get the returned tool messages
ReturnMessages pResult

Public Sub ReturnMessages(ByVal messages As IGeoProcessorResult)

  Dim i As Long
  Dim message As String

  For i = 0 To messages.MessageCount - 1
     message = messages.GetMessage(i)
     Debug.Print message

End Sub
  • I was interested in using the GP tool but I was uncomfortable with working with all the string properties. This looks very doable. I will give it a shot. Thanks.
    – Nathanus
    Nov 18 '11 at 16:00
  • Updated my question with new confusion!
    – Nathanus
    Nov 18 '11 at 17:01
  • Success is mine. Thank you for the leg up. I ended up converting it to C#, and the working code is above.
    – Nathanus
    Nov 18 '11 at 19:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.