|
POST
|
There is a good description of programming Word in Python in "Python programming on Win32" by Mark Hammond (O'Reilly) and I found some specific hints in "Writing Excel Macros with VBA" by Roman (O'Reily). Quote from Mark Please note: Word is hard to work with. Here are some examples from his book: http://examples.oreilly.com/9781565926219
... View more
06-21-2011
09:21 PM
|
0
|
0
|
2164
|
|
POST
|
That is the problem, it does not use the same event queue to detect mouse actions. I don't see anything that you could not do using the tool interface. Have you looked at the validation tab? You can add in Python scripts there that can react to filling in the form before the script is run. You can interactively add in an input there and do some preprocessing depending on the input.
... View more
06-06-2011
05:36 PM
|
0
|
0
|
1489
|
|
POST
|
Its the KISS principle. If all the functions were added that could be done from ArcObjects, then it would be ArcObjects. So the official view would be to use ArcObjects. You may be able to approximate different class breaks by saving the range of breaks you anticipate to be needed, do some statistics and call in the required layer template. If only we had access to an ascii dump of layer objects (as an XML file) we could hack a symbol definition in a layer just like we could with Avenue. Meanwhile it is possible to call ArcObjects from Python using the ctypes module and a good manual on ArcObjects.
... View more
06-06-2011
05:30 PM
|
0
|
0
|
630
|
|
POST
|
You are not very explicity on what the selected feature is. I assume you mean the page in an index layer in a location map inset? In the index dataframe copy the layer that is being used for data driven pages. The first layer will be an outline say Index. The second layer (renamed say Sheet) will be the highlighted tile. Set this layer to be a filled colour. With data driven pages enabled, open the properties>definition and you will see two button options instead of one, Query Builder or Page Definition. Select the page definition button and choose your options. Set the pages field and set Features that Match. If it is not the index that you want highlighted, the process is the same with any other feature layer, add a field so that the feature(s) to be highlighted has the pagename that corresponds in the attributes.
... View more
06-06-2011
05:21 PM
|
0
|
0
|
1717
|
|
POST
|
Intellisense works just fine in PythonWin while coding if you first import arcpy in the Interactive Window. No need to go to some other IDE. import arcpy will check out a licence but it will make Pythonwin aware of the module. If you only have an arcview licence, then import arcview You can also then browse the arcpy module from Menu>Tools>Browser> arcpy instead of the default __builtins__ However I still find the commentary in the ArcGIS help more useful.
... View more
06-05-2011
11:50 PM
|
0
|
0
|
1109
|
|
POST
|
Deleting layers never worked for me, maybe it does now in 10. My solution is to set gp.overwriteoutput = True or arcpy.env.overwriteOutput = True Then you can always overwrite an in-memory layer definition.
... View more
06-05-2011
11:34 PM
|
0
|
0
|
1086
|
|
POST
|
If you want a more automated approach, you can use the dispatch com interface that we used to use for ArcGIS9. This works well to get direct access to a spreadsheet and each of the sheets. This is well explained in "Python Programming on Win 32" by Hammond and Robinson. o = win32com.client.Dispatch("Excel.Application")
o.Visible = 1
o.Workbooks.Add() # for office 97 �?? 95 a bit different!
o.Cells(1,1).Value = "Hello" To make accessing Excel a bit easier, Mark Hammond suggested a small module to get the data which I called exceldemos.py: # Excel module from Mark Hammond
# Python Programming on Win 32
import win32com.client
import win32com.client.dynamic
from pywintypes import UnicodeType, TimeType
import pprint
import os
import time
import string
class easyExcel:
"""A utility to make it easier to get at Excel. Remembering
to save the data is your problem, as is error handling.
Operates on one workbook at a time."""
def __init__(self, filename=None):
self.xlApp = win32com.client.dynamic.Dispatch('Excel.Application')
if filename:
self.filename = filename
self.xlBook = self.xlApp.Workbooks.Open(filename)
else:
self.xlBook = self.xlApp.Workbooks.Add()
self.filename = ''
def save(self, newfilename=None):
if newfilename:
self.filename = newfilename
self.xlBook.SaveAs(newfilename)
else:
self.xlBook.Save()
def close(self):
self.xlBook.Close(SaveChanges=0)
del self.xlApp
def show(self):
self.xlApp.Visible = 1
def hide(self):
self.xlApp.Visible = 0
def getBooks(self):
return self.xlApp.Worksheets
def getName(self,sheet):
return self.xlBook.Worksheets(sheet).Name
#
# now for the helper methods
#
def getCell(self, sheet, row, col):
"Get value of one cell"
sht = self.xlBook.Worksheets(sheet)
return sht.Cells(row, col).Value
def setCell(self, sheet, row, col, value):
"set value of one cell"
sht = self.xlBook.Worksheets(sheet)
sht.Cells(row, col).Value = value
def getRange(self, sheet, row1, col1, row2, col2):
"return a 2d array (i.e. tuple of tuples)"
sht = self.xlBook.Worksheets(sheet)
return sht.Range(sht.Cells(row1, col1), sht.Cells(row2, col2)).Value
def setRange(self, sheet, leftCol, topRow, data):
"""insert a 2d array starting at given location.
Works out the size needed for itself"""
bottomRow = topRow + len(data) - 1
rightCol = leftCol + len(data[0]) - 1
sht = self.xlBook.Worksheets(sheet)
sht.Range(
sht.Cells(topRow, leftCol),
sht.Cells(bottomRow, rightCol)
).Value = data
def getContiguousRange(self, sheet, row, col):
"""Tracks down and across from top left cell until it
encounters blank cells; returns the non-blank range.
Looks at first row and column; blanks at bottom or right
are OK and return None witin the array"""
sht = self.xlBook.Worksheets(sheet)
# find the bottom row
bottom = row
while sht.Cells(bottom + 1, col).Value not in [None, '']:
bottom = bottom + 1
# right column
right = col
while sht.Cells(row, right + 1).Value not in [None, '']:
right = right + 1
return sht.Range(sht.Cells(row, col), sht.Cells(bottom, right)).Value
def getHeaderRange(self, sheet, row, col):
"""Tracks across from left cell until it
encounters blank cells; returns the non-blank range.
Looks at first row and column; blanks at bottom or right
are OK and return None within the array"""
sht = self.xlBook.Worksheets(sheet)
# find the bottom row
# bottom = row
# while sht.Cells(bottom + 1, col).Value not in [None, '']:
# bottom = bottom + 1
# right column
right = col
while sht.Cells(row, right + 1).Value not in [None, '']:
right = right + 1
return sht.Range(sht.Cells(row, col), sht.Cells(row, right)).Value
def fixStringsAndDates(self, aMatrix):
# converts all unicode strings and times
newmatrix = []
for row in aMatrix:
newrow = []
for cell in row:
if type(cell) is UnicodeType:
newrow.append(str(cell))
elif type(cell) is TimeType:
newrow.append(int(cell))
else:
newrow.append(cell)
newmatrix.append(tuple(newrow))
return newmatrix
def test():
# puts things in a new sheet which it does not save
spr = easyExcel()
spr.show()
input = 'hello'
spr.setCell('Sheet1',1,4, input)
output = spr.getCell('Sheet1',1,4)
print output
assert input == output, 'setCell/getCell failed'
input = []
for i in range(10):
row = []
for j in range(4):
row.append(str('(%d,%d)'% (j, i)))
input.append(tuple(row))
spr.setRange('Sheet1',2,2,input)
output = spr.getRange('Sheet1',2,2,11,5)
# get rid of unicode strings
output = spr.fixStringsAndDates(output)
assert input == output, 'setRange/getRange test failed'
#get a contiguous range
output2 = spr.getContiguousRange('Sheet1',2,2)
dimensions = (len(output2), len(output2[0]))
assert dimensions == (10, 4), 'getContiguousRange failed'
print 'passed!'
# if __name__ == '__main__' :
# test()
Then to get each sheet you can create a Python loop something line this: The spreadsheet had data split into several tables, with headers. I needed to transpose the data and calculate some cross sections from a centreline. In my case I exported to CSV files and loaded them using another obsolete tool called CreateFeaturesFromText, but you could write the data directly into a table using a cursor. # load reachs and crosssections from a spreadsheet
# getwater3.py
# get channel centreline and number nodes uniquely
# dropping off duplicates
# calculate bearing of nodes in geographic degrees
# Kimo
# 6 October 2005
# upgrade to average angles for middle points of a reach
# 7 October 2005
# 10 October 2005
# offset one more row to allow for max water level calc
# does not get all the other water levels, just bottom and max
# better to load database of levels for each section for joining later
# so that we can create a surface for each time step from same cross sections
# ref first field for sorting and joining
# pad chainage
# removed max row again
# but too late, have to have it.
#
# import win32com.client
import win32com.client.dynamic
import os,sys
from math import *
# sys.path.append("d:\\project\\python")
import exceldemos
homedir = "e:/toolbox/scratch"
os.chdir(homedir)
xlApp = win32com.client.dynamic.Dispatch('Excel.Application')
filename = "e:/example/GISTransfer.xls"
spr = exceldemos.easyExcel(filename)
f1 = open("channel.txt","w") # polyline generate file
f2 = open("channel_att.txt","w") # polyline attributes
f3 = open("channel_node.txt","w")# xsection nodes, can load as XY events
f4 = open("channel_skip.txt","w")# rejects - duplicate nodes
f5 = open("channel_xsec.txt","w")# xsection ref,x,y,theta for joining to xsections
# there are multiple worksheets
# so loop over all to combine into single output
max = 0
lstRef = []
try :
for b in spr.getBooks() :
max += 1
print "workbook: ",b.Name
print "Workbooks found: ",max
row = 0
# output file headers
print >> f1,'Polyline' # for Toolbox loader
print >> f2,'rid,reach'
print >> f3,'ref,nodeid,x,y,z,w,theta,rid,reach,chain'
print >> f4,'rec,x,y,reach,chain,z,w'
# no header for f5 xsec
# print >> f5,'ref,x,y,theta,maxwater'
rec = 1
id = 0
rn = 0
# skip first sheet
for sheetindex in range(2,5) :
# get number of columns
header = spr.getHeaderRange(sheetindex,3,1)
columns = len(header[0])
print "Length of header",columns
print "Beginning :",spr.getName(sheetindex)
aHeader = spr.getRange(sheetindex,1,1,6,columns)
# transpose rows and columns
headerpivot = [[r[col] for r in aHeader] for col in range(len(aHeader[0]))]
# initialize counters
rname = ""
rx = 0
ry = 0
i = 0
rej = 0
colcount = len(headerpivot[1:])
print "Columns",colcount
for (a,b,c,d,e,w) in headerpivot[1:] :
# print rec,a,b,c,d,e,w
# a X coordinate
# b Y coordinate
# ..... snip to fit forum text limit .....
print >> f1,"END"
print "records :",rec,"nodes",id,"reaches",rn,"rejects",rej
f1.close()
f2.close()
f3.close()
f4.close()
f5.close()
spr.close()
del xlApp
except :
print "cleanup close"
f1.close()
f2.close()
f3.close()
f4.close()
f5.close()
spr.close()
del xlApp
The spreadsheet is a bit large to include, I hope this is enough of a clue to encourage you to buy the book, which is now available in digital format. http://oreilly.com/catalog/9781565926219
... View more
06-05-2011
04:48 PM
|
0
|
0
|
1230
|
|
POST
|
It is because the paths to Python26 are not set for Arcpy. Even if you reinstall Python26 you have to make sure there is a Desktop10.pth file in c:/Python26/Lib/site-packages containing the paths to the package C:\Program Files (x86)\ArcGIS\Desktop10.0\bin
C:\Program Files (x86)\ArcGIS\Desktop10.0\arcpy
C:\Program Files (x86)\ArcGIS\Desktop10.0\ArcToolbox\Scripts Also you might need to reinstall Numpy which resides in site-packages as a folder Note that if you use the ArcGIS installer it will install another copy of python in C:/Python26/Desktop10.0/Lib/.... so if you cleanup and reinstall Python yourself the configuration will be broken. But on the other hand if you use the Esri installer, the Python install will be broken, you will not be able to open the Python help and other tools will fail.
... View more
06-02-2011
08:24 PM
|
0
|
0
|
634
|
|
POST
|
The "Text loader", part of Microsoft libraries needs a Schema.ini to properly define the field names and types. ArcGIS uses it. If schema.ini does not exist it defaults to using the header fields which will then fail if they are not valid field names. With a schema.ini you can rename the fields on import and also define the field type. The schema.ini is a recent discovery for me, and has saved me hours of work creating custom scripts. It is mentioned in the ArcGIS help, but do a Google search for more details from Microsoft. http://msdn.microsoft.com/en-us/library/ms709353%28v=vs.85%29.aspx
... View more
06-02-2011
08:16 PM
|
1
|
0
|
1414
|
|
POST
|
Renaming a layer in the current MXD should be instantaneous. After all the MXD will be in memory. This took 312 milliseconds. I think that having things on a network will be the likely culprit. It could be a very slow licence manager lookup causing the delay. Try a ping and other network analysis tools. I am amazed at the lengths people go to to avoid a simple local machine running Windows with local disks. They surely are a commodity? This is the only way I run processes for GIS analysis. Anything else is asking for much delay, even network calls are not optimised in any system, they simulate a local disk call, but are very slow across a network. Nothing to do with the network drives, its the OS and the network disconnection. Here is a benchmark script. I ran this in the Python window. >>> # rename layer
... import arcpy
... import datetime
... start = datetime.datetime.now()
... mxd = arcpy.mapping.MapDocument("CURRENT")
... lstDF = arcpy.mapping.ListDataFrames(mxd)
... print len(lstDF),"frames"
... for df in lstDF:
... print df.name
... llay = arcpy.mapping.ListLayers(mxd,"",df)
... for lay in llay:
... print lay.name
... print mxd.title,df.name,lay.name
... lay.name = lay.name+"changed"
... arcpy.RefreshActiveView()
... arcpy.RefreshTOC()
... print datetime.datetime.now() - start
...
2 frames
Layers
pointerchanged
topo250 Layers pointerchanged
coastlinechanged
topo250 Layers coastlinechanged
lakechanged
topo250 Layers lakechanged
native_polychanged
topo250 Layers native_polychanged
island_polychanged
topo250 Layers island_polychanged
mainlandchanged
topo250 Layers mainlandchanged
index250changed
topo250 Layers index250changed
Index
coastlinechanged
topo250 Index coastlinechanged
sheetchanged
topo250 Index sheetchanged
index250changed
topo250 Index index250changed
0:00:00.312000
... View more
06-02-2011
07:41 PM
|
0
|
0
|
789
|
|
POST
|
I started a similar project to create a tool that split a parcel in half if there were two address points in the parcel, when the parcel was a corner property. It needed ET_Geotools I created a line for the split by bisecting the two points and used that to intersect the polygon. You can then write the split polygon back to the featureclass. # bisect2
# bisect a parcel into two
# between two points inside
# extend to multipoints later
# input parcel_id
# select parcel poly
# select address points
# if two points
# calculate perpendicular bisector
# cut polygon with the line
# save to be replaced
# 26 Nov 2010
#
import arcgisscripting,sys,os,math
gp = arcgisscripting.create(9.3)
def createknife(par_id):
"""create knife lines for bulk splitting
using address points with same parcel_id"""
gp.MakeFeatureLayer_management(fcAdd,"add_lay","parcel_id = "+str(par_id))
shapeField = gp.Describe(fcAdd).shapeFieldName
cur = gp.SearchCursor("add_lay","parcel_id = "+str(par_id),SR)
row = cur.next()
n = 0
pt = []
while row:
pt.append(row.getValue(shapeField).centroid)
n+=1
row = cur.next()
del row,cur
## print n, "points"
##for addpt in pt:
## print "address ",addpt.X,addpt.Y
# find mid point and angle, add 90 degrees
midpt = gp.CreateObject("Point")
midpt.X = (pt[0].X + pt[1].X)/2.0
midpt.Y = (pt[0].Y + pt[1].Y)/2.0
radAngle = math.atan2(pt[0].Y - pt[1].Y,pt[0].X - pt[1].X) + math.pi/2.0
# print "midpoint",midpt.X,midpt.Y,"Bearing",radAngle
# create a perpendicular line in a temp fc
ext = gp.Describe("in_memory/parcel").extent
size = max(ext.width,ext.height)*1.5
print par_id,size
pnt1 = gp.CreateObject("Point")
pnt2 = gp.CreateObject("Point")
pnt1.X = midpt.X - size * math.cos(radAngle)
pnt1.Y = midpt.Y - size * math.sin(radAngle)
pnt2.X = midpt.X + size * math.cos(radAngle)
pnt2.Y = midpt.Y + size * math.sin(radAngle)
pline = gp.CreateObject("Array")
pline.Add(pnt1)
pline.Add(pnt2)
##print "knife %8.1f %8.1f %8.1f %8.1f" % (pnt1.x,pnt1.y,pnt2.x,pnt2.y)
cur = gp.InsertCursor("in_memory/knife")
row = cur.newRow()
row.shape = pline
cur.insertRow(row)
row = cur.newRow()
pline.removeAll()
del cur,row
# temp debugging
outLine = gp.CreateScratchName("split_line","","FeatureClass")
gp.CopyFeatures_management("in_memory/knife",outLine)
##print "Knife extent",gp.Describe("in_memory/temp").extent
##print "Parcel extent",gp.Describe("in_memory/parcel").extent
##print "Address extent",gp.Describe("add_lay").extent
##outAdd = gp.CreateScratchName("split_add","","FeatureClass")
##gp.CopyFeatures_management("add_lay",outAdd)
gp.AddToolbox(r"C:\Program Files\ET SpatialTechniques\ET GeoWizards 10.0 for ArcGIS 9.2 and 9.3\ET GeoWizards.tbx")
outParcel = "in_memory/split" #gp.CreateScratchName("split_parcel","","FeatureClass")
gp.ET_GPPartitionPolygons("in_memory/parcel","in_memory/temp",outParcel)
# print gp.GetMessages()
return outParcel
# -------------------- main -----------------------
try:
fcPar = sys.argv[1]
except:
fcPar = "corner"
gp.overwriteOutput = True
ws = "d:/work/pcl/CourierRun.gdb"
gp.workspace = ws
fcAdd = "addrun"
SR = gp.CreateObject("SpatialReference")
SR.CreateFromFile("c:/arcgis/nztm.prj")
gp.CreateFeatureClass("in_memory","knife","Polyline","","","",SR)
rCursor = gp.SearchCursor(fcPar)
row = rCursor.next()
while row:
par_id = row.par_id
result = split(par_id)
row = rCursor.next()
... View more
06-02-2011
06:50 PM
|
0
|
0
|
1157
|
|
POST
|
1. Load the spreadsheet into a table. If you dump the spreadsheet to a .CSV file first and define a Schema.ini then it will load nicely as a formatted table using the CopyTable_management tool. Schema.ini is a default Windows function. Note that a spreadsheet is not a database and is not supported to be reliably loaded with a satisfactory schema because columns are not defined, only formatted. Default widths are 255 chars for example. 2. If you have to update multiple sheets from one table, create a dictionary using the key value and the attribute. 3. Run an updateCursor on each target table and push the new values in using the dictionary as a lookup. Using the join tools are a bit slow.
... View more
06-02-2011
06:29 PM
|
0
|
0
|
1230
|
|
POST
|
To debug a tool, try this: Run a tool interactively by filling in the dialog by hand. After it runs successfully, open the results and right-click to get "Copy as a Python Snippet" Paste this into an empty Python script and examine the syntax, particularly the SQL query. I find that provided you are not using a personal geodatabase (*.mdb) AND you are using valid field names (No spaces or silly chars, starts with a letter, less than max chars, not a reserved word) you can also dispense with the double quotes around the field names. In spite of the help saying otherwise. This makes assembling SQL queries much simpler. Also try printing out your expression to see if you really got the expected valid expression.
... View more
06-02-2011
06:22 PM
|
0
|
0
|
1109
|
|
POST
|
I used the standard module ElementTree to parse XML for a GPX file as hinted by a Python demo at the conference. This is much easier than some of the older parsers such as SAX or DOM.
... View more
05-19-2011
01:07 AM
|
0
|
0
|
600
|
|
POST
|
Ok, I didn't think I would get away with that brief specification. A sample script takes 3 seconds to iterate 100 times. I have shown one case creating a layer of the random selection. You could put this back into a table of contents. # randomselection.py
# 19 May 2011
# kimo@ollivier.co.nz
#
# Input: parcel polygon featureclass
# item to sum (area)
# threshold (check min, mean, max values for reasonable figure)
# Assumes values always less than threshold or you get a null list
# Output: Total sum and layer with selected parcels
# set up to allow iteration
# uses ArcGIS 10 but could use 9.3
import arcpy
import sys
import os
import random
import datetime
try:
fc = sys.argv[1]
item = sys.argv[2]
threshold = sys.argv[3]
except:
# debugging and standalone operation
fc = "c:/project/forum/mobile.gdb/parcel"
item = "area"
threshold = 100000.0 # square metres
def getdict(fc,item):
''' Make a dictionary
once for the sampler
'''
dParcel = {}
for row in arcpy.SearchCursor(fc,"featcode = 'parcel'"):
if item.lower() == 'area':
dParcel[row.objectid] = row.shape.area
else :
dParcel[row.objectid] = row.GetValue(item)
return dParcel
def getsample(dParcel,threshold):
'''Given a dict of values
return a random selection
less than the threshold.
Shuffles the list and pops off
the ids until threshold reached
ie sampling without replacement
'''
total = 0
lstObj = []
lstKey = dParcel.keys()
random.shuffle(lstKey)
while total < threshold:
nObj = lstKey.pop()
nVal = dParcel[nObj]
total = nVal
if total > threshold:
break # do not exceed threshold
else :
lstObj.append(nObj)
total += nVal
return (total,lstObj)
# --------------- main ---------------
print
start = datetime.datetime.now()
print start
#
# make a dictionary
dParcel = getdict(fc,item)
print "records",len(dParcel)
# sample the dictionary
total,lstObj = getsample(dParcel,threshold)
print "Total: ",total
print "No of parcels: ",len(lstObj)
print "objectid: value"
for ob in lstObj:
print ob,":",dParcel[ob],", ",
print
# make up an sql query to select the features
sqlQuery = "OBJECTID in (" + ",".join([str(id) for id in lstObj]) + ")"
print sqlQuery
arcpy.env.overwriteOutput = True
arcpy.MakeFeatureLayer_management(fc,"fc_lay",sqlQuery)
lyrName = arcpy.CreateUniqueName("xx.lyr",os.path.dirname(os.path.dirname(fc)))
print lyrName
arcpy.SaveToLayerFile_management("fc_lay",lyrName)
# Or sample the dictionary 100 times
for it in range(100):
total,lstObj = getsample(dParcel,threshold)
print total,len(lstObj)
# finished
elapsed = datetime.datetime.now() - start
print "\n\nElapsed",elapsed, "Well done!" # positive feedback
2011-05-19 20:40:43.640000
records 7170
Total: 145316.242757
No of parcels: 21
objectid: value
726 : 809.726863177 , 4530 : 809.419546424 , 4752 : 1012.70775115 , 6120 : 809.397052955 , 3022 : 809.418725814 , 253 : 986.240771943 , 4445 : 1132.16238039 , 7161 : 928.75695316 , 5747 : 964.13873029 , 2188 : 864.834770195 , 4164 : 20.9192428737 , 187 : 839.573627519 , 2745 : 811.268061104 , 2572 : 1002.32513709 , 1445 : 1381.14243957 , 2674 : 812.661986759 , 6925 : 25126.7099296 , 5479 : 1395.56544711 , 4791 : 810.812432473 , 5406 : 848.317697436 , 6543 : 72658.1213786 ,
OBJECTID in (726,4530,4752,6120,3022,253,4445,7161,5747,2188,4164,187,2745,2572,1445,2674,6925,5479,4791,5406,6543)
c:/project/forum\xx0.lyr
185921.392647 4
145871.629063 27
154201.63183 1
...
140524.256299 0
...
190822.946912 9
193668.483773 23
334292.358346 16
141967.626185 23
15109126.1898 56
...
413536.709991 2
157130.891363 6
Elapsed 0:00:02.917000 Well done!
... View more
05-19-2011
12:53 AM
|
0
|
0
|
2184
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 09-15-2024 10:32 PM | |
| 1 | 03-12-2026 01:10 AM | |
| 1 | 03-13-2026 08:30 PM | |
| 1 | 03-13-2026 05:17 PM | |
| 1 | 03-12-2026 05:14 PM |
| Online Status |
Offline
|
| Date Last Visited |
03-13-2026
05:04 PM
|