Thursday, May 17, 2012

Sorting a List of Lists

In 10.1, the new arcpy.da (new cursor functions) returns essentially a list of lists.  A way to sort these list of lists is to use sorted() which is a built in function of python.  More can be found here.

Here is a simple example, but I think it will get what you need.


>>> myresults = [
[1,"A",2],
[2,"Z",1],
[3,"J",0]
]
>>> print sorted(myresults, key=lambda x:x[0])
[[1, 'A', 2], [2, 'Z', 1], [3, 'J', 0]]
>>> print sorted(myresults, key=lambda x:x[1])
[[1, 'A', 2], [3, 'J', 0], [2, 'Z', 1]]
>>> print sorted(myresults, key=lambda x:x[2])
[[3, 'J', 0], [2, 'Z', 1], [1, 'A', 2]]

Here we have our list with 3 entries in each sub-list item. The lambda function tells the sorted() what to sort on. The numeric value is the position in the sub-list item inside the parent list.

Wednesday, May 16, 2012

Quicksort() using python

One method of sorting lists is to use the quicksort.  The elements in the list must have a strict weak order and the index of the array can be of any discrete type.


Follow these steps to implement:
  1. Choose any element of the list to be the pivot.
  2. Divide all other elements (except the pivot) into two partitions.
    • All elements less than the pivot must be in the first partition (lower half list).
    • All elements greater than the pivot must be in the second partition (upper half list).
  3. Use recursion to sort both partitions.
  4. Join the first sorted partition, the pivot, and the second sorted partition
The run time of quicksort ranges from O(n log n) with the best pivots, to O(n2) with the worst pivots, where n is the number of elements in the list.  (O is complexity)



def qsort(list):
    if not list:
        return []
    else:
        pivot = list[0]
        less = [x for x in list     if x <  pivot]
        more = [x for x in list[1:] if x >= pivot]
        return qsort(less) + [pivot] + qsort(more)

Example:
someList = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3]
print qsort( someList )
[1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 7, 8, 9, 9, 9]


Enjoy the sort.

Friday, May 11, 2012

In the Esri's ArcGIS for SharePoint SDK, you can create buttons in the SharePoint ribbon.  In this example, I will talk about the OnHidden event.  This event fires when the Hide() is called on the floating window after it is displayed.  This can be used to signal a process that the event is finished, and now you can do some other process or show another form etc...

Here I just implemented ICommand, and kept everything default.  I created a custom event EventHandler called OnHidden that will get call when the floating window is hidden or closed by a user.

    [Export(typeof(ICommand))]
    [DisplayNameAttribute("This is a Demo")]
    [DefaultIcon("/DemoFun;component/Images/Demo.png")]
    public class cmdGenerateExcelTemplate : ICommand
    {
        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;
        public event EventHandler OnHidden;
     
        public void Execute(object parameter)
        {
         
            MapApplication.Current.ShowWindow("This is my control",
                 <controlobject>,
                false,
                null,
                OnHidden,
                WindowType.Floating);
            this.OnHidden += new EventHandler(cmdGenerateExcelTemplate_OnHidden);

        }

        void cmdGenerateExcelTemplate_OnHidden(object sender, EventArgs e)
        {
            MessageBox.Show("I'm hidden now!");
        }
That's It.  It's very easy to do, and helpful in some instances.

Enjoy


Wednesday, May 9, 2012

Using Static Methods on a Class

Static Methods are functions that can be called from a class without creating that object.  From python.org - "A static method does not receive an implicit first argument"
This means basically that it is not dependent on the class from within it resides, but it is an associated function to the overall class. 

Take the example below:
import arcpy
import os
class StaticExample(object):

    def __init__(self,*argv):
        '''
        Constructor
        '''
        pass
    @staticmethod
    def createSDEFromConnectionInfo(folderName,
                           fileName,
                           serverName,
                           serviceName,
                           databaseName,
                           username,
                           password,
                           versionName,
                           saveUserInfo,
                           saveVersionInfo,
                           authType,
                           overwriteExisting=True):
        """
            Static Method To Create an SDE Connection File
            Inputs:
                folderName - The folder path where the .sde file will be stored.
                fileName -  The name of the ArcSDE Connection file. Use the .sde file extension.
                serverName - The ArcSDE Server machine name.
                serviceName - The ArcSDE Service name or TCP port number.
                databaseName - For non-Oracle databases only. The DBMS database to connect to.
                username - Database username to connect with using Database Authentication.
                password - The database user password when using Database Authentication.
                versionName -  The Geodatabase version to connect to.
                saveUserInfo - SAVE_USERNAME —Save the username and password in the connection file.
                               DO_NOT_SAVE_USERNAME —Do not save the username and password in the file.
                               Every time you attempt to connect using the file you will be prompted for
                               the username and password.
                saveVersionInfo - SAVE_VERSION —Save the version name in the connection file.
                                  DO_NOT_SAVE_VERSION —Do not save the version name in the connection file.
                                  Without the version name being saved with the file you will be prompted
                                  for the version to connect to each time you access the connection file.
                authType - Either DATABASE_AUTH or OPERATING_SYSTEM_ATUH - forms of authentication
                overwriteExisting - Tells the function if it can overwrite the .sde file.
        """
        if overwriteExisting == True and \
           os.path.isfile(folderName + os.sep + fileName) == True:
            os.remove(folderName + os.sep + fileName)
        arcpy.CreateArcSDEConnectionFile_management (folderName, fileName,
                                                     serverName, serviceName,
                                                     databaseName, authType,
                                                     username, password,
                                                     saveUserInfo, versionName,
                                                     saveVersionInfo)


To declare your static method, use the descriptor tag @staticmethod.  This tells the class that this function does not need to know about itself.  Using the function is easy:

print StaticExample.createSDEFromConnectionInfo(parm1,param2,....)
>>> c:\temp\mysde.sde


It sometimes is helpful to have functions that are associated with a class be accessible without creating the class object. Some would say just put the function in the .py file outside the class, but then you lose the ability of inheritance on that function.

Happy Coding

Tuesday, May 8, 2012

Finding Duplicates (3 Ways)

In this post I will show some methods of finding duplicate values in an enterprise SDE database.
The general query is quite simple.  We will perform a SELECT on the table and return the values and the number of times it repeats within that table
First I will use cx_Oracle module to query a table and return both the count and field value that has duplicates:
import cx_Oracle
#.... connection 
information
#.... create cursor
columnName = "ClientName" 
table = "clients" 
sql = "SELECT %s, count(*) from %s GROUP BY %s HAVING count(*) > 1" % (columnName, table, columnName) 
print cursor.execute(sql).fetchall()
That will return a 2 column list of tuples where as a developer you can then parse that information as needed.

Let's assume you want to do it a more ArcPy way.  ArcSDESQLExecute class can be used to perform the same SQL statement.  The ArcSDESQLExecute class provides a means of executing SQL statements via an ArcSDE connection (source: webhelp.esri.com).

# Two ways to create the object, which also creates the connection to ArcSDE. 
# Using the first method, pass a set of strings containing the connection properties: 
# sdeConn = arcpy.ArcSDESQLExecute("gpserver3","5151","#","toolbox","toolbox") 
# Using the second method pass the path to a valid ArcSDE connection file 
# sdeConn = arcpy.ArcSDESQLExecute("data\Connection to GPSERVER3.sde")
sdeConn = arcpy.ArcSDESQLExecute(r"c:\temp\connectionFile.sde"

columnName = "ClientName" 
table = "clients" 
sql = "SELECT %s, count(*) from %s GROUP BY %s HAVING count(*) > 1" % (columnName, table, columnName) 

results = sdeConn.execute(sql)
for result in results:
   print result # List with [column value, # of duplicates]


You can always turns to ArcToolbox for help if you do not like using SQL. Using Summary Statistics you can get the count of the values in a specific field. It most likely will be slower for large data sets compared to the other two method mentioned above, but it can be used for any supported data set in ArcGIS.

Happy Duplicate Finding

Monday, May 7, 2012

ArcPy - List Columns for Table

In my previous post, I showed you how to use pure SQL in oracle to list the fields of a table.  This can be done using ArcPy as well.
ArcPy has a function called: ListFields (dataset, {wild_card}, {field_type}) where all you are required to pass is the dataset. The wild card and field type are limiters that can help slim down the results.
sdeFile = r"c:\temp\connectionFile.sde" 
fc = sdeFile + os.sep + "myFeatClass" 
fields = arcpy.ListFields(fc) 
for field in fields:
   print field.name

The code returns a field object from which you can access a whole set of properties. This method is preferred when examining spatial data because it provides the data in a format that the Arc system can read and understand.
Enjoy

Tuesday, May 1, 2012

Listing Oracle Columns Using Python

I've started coding a set of helpful functions for oracle and python using the cx_oracle library for python.  Just download the library and install the one associated with your python install.

In this example, I will list a set of columns in a table using python. First we need to connect to the oracle database
import cx_Oracle
username = "user" 
password = "*****" 
ip = "111.11.11.11" 
port = 1521 
SID = 'ORCL' 
table = 'mytablename' 
dsn_tns = cx_Oracle.makedsn(ip, port, SID) 
db = cx_Oracle.connect(user,passwword, dsn_tns)

All I did was create the entry like it would appear in the tnsname.ora file then pass that information along with the username and password to the database.
Great, now we are connected to the oracle database.  Now the database can be queried.

cursor = db.cursor()
results = cursor.execute("select * from %s where 1=0" % table)
print results.description


[('OBJECTID', <type 'cx_oracle.number'="">, 39, 22, 38, 0, 0), ('NEWNAME', <type 'cx_oracle.unicode'="">, 50, 100, 0, 0, 1)]

Now you do not have to use arcpy to list the fields in a table.  Some other ideas you could do with your enterprise database is: rename fields, create views, etc...

Enjoy