|
POST
|
Your tree class looks good, with one possible exception. The next to last line appears to need indentation. When sharing Python scripts, it is good to use the "syntax highlighter" when posting to GeoNet. There are some good instructions on using the highlighter here: Code Formatting... the basics++ Here is what your code looks like using the highlighter with the indentation corrected: class Tree:
def __init__(self, block, plot, species, dbh):
self.block = block
self.plot=plot
self.species=species
self.dbh=dbh
def dib(self):
dib = self.dbh * (1/1.09) # 1/1.09 = 0.917431193
return dib
Also in line 9, I added some parenthesis around the 1/1.09. I don't think it matters in this case, but it insures the division happens before the multiplication. You could also use the 0.91743 equivalent. For the next step, you will need some code to read your text file. Here's a basic approach. It assumes the text file does not have a header. filename = r"C:\Path\to\trees.txt" # enter full path and filename
tf = open(filename, 'r')
treeData = tf.readlines()
for row in treeData:
td = row.strip().split() # strip any line feeds, then split on spaces
print td
tf.close() I created a simple tree data file, and the script prints out: ['1', '1', 'cedar', '4.5']
['1', '2', 'spruce', '3.75']
['2', '1', 'hemlock', '2.5'] Note that a list is produced and all the elements are text (in quotes). It is possible that the Block and Plot will be text, but they could be numbers. The DBH data is probably a floating point number, so you will need to change it from type text to float. The next steps are to include the tree class and print the results. This should be similar to your parcels example. You may need to deal with a header row when reading your text file. If you were wanting to number each tree by row in the file, you will need a counter. Let me know how this part goes.
... View more
03-21-2020
04:55 PM
|
1
|
1
|
3059
|
|
POST
|
I assume this is related to your question about Exercise 12. The parcel class script used in that exercise can be used as a pattern to create a tree class. Once the class is created, then you would come up with a way to read the lines in the text file. Here is the parcel class example: class Parcel:
def __init__(self, landuse, value):
self.landuse = landuse
self.value = value
def assessment(self):
if self.landuse == "SFR":
rate = 0.05
elif self.landuse == "MFR":
rate = 0.04
else:
rate = 0.02
assessment = self.value * rate
return assessment In line 1 change Parcel to Tree. In lines 2, 3 and 4, replace landuse and value with block, plot, species and dbh. (You'll be adding a couple of new lines in this section.) In lines 6, 13 and 14, replace assessment with dib. In line 13, replace value with dbh, and replace rate with your numeric value. Delete lines 7 thru 12 in above script (landuse and rate section). Share the script you come up with. The next steps would be to read the text file, split each line where there are spaces, use the data to create a tree class, and print the results.
... View more
03-21-2020
11:51 AM
|
1
|
3
|
3059
|
|
POST
|
For Challenge 2 you have a parcel class module. The code needs no modification; it just needs to be included in the final project: class Parcel:
def __init__(self, landuse, value):
self.landuse = landuse
self.value = value
def assessment(self):
if self.landuse == "SFR":
rate = 0.05
elif self.landuse == "MFR":
rate = 0.04
else:
rate = 0.02
assessment = self.value * rate
return assessment The parcel tax script illustrates how to use the parcel class: import parcelclass
myparcel = parcelclass.Parcel("SFR", 125000)
print "Land use: ", myparcel.landuse
mytax = myparcel.assessment()
print "Tax assessment: ", mytax What is being asked is to loop through a feature and calculate the tax for each parcel based on the FID, Landuse and Value of the property. To do this, you will use a search cursor. The author has given an example of how to use a search cursor in exercise 7. Review this section if needed. import arcpy
from arcpy import env
env.workspace = r"C:/EsriPress/Python/Data/Exercise07"
fc = "airports.shp"
cursor = arcpy.da.SearchCursor(fc, ["NAME"])
for row in cursor:
print "Airport name = {0}".format(row[0]) Since this last script is closest to the goal, modify it to read the desired data. Replace the path given in line 3 to the path for Exercise 12. In line 3, correct the name of the shape file where the data is located. Replace "NAME" in line 5 with the three fields needed. Then change line 7 to print the data; this is for testing and will be replaced later. # line 7 will become (note indentation)
print "FID: {0} Landuse: {1} Value: {2}".format(row[0], row[1], row[2]) Once you have this script reading your shape file correctly, the parcel class and tax scripts will be added into the mix by Import the parcel class by placing line 1 of the tax script at the top of your working script. Copy lines 2 and 4 from your tax script and insert them between the "for row in cursor" and "print ..." rows of your working script. You will need to change "SFR", 125000 of the copied line 2 of the tax script to use row[1] and row[2]. Modify the print statement to: print "{0}: {1}".format(row[0], mytax) Then test your script and let us know how it is working. If you have problems, post your script, and comments will be provided. Hope this helps.
... View more
03-21-2020
11:29 AM
|
2
|
2
|
4148
|
|
POST
|
The solution the author intended was to print a list of FIDs and the corresponding tax assessment; and not to create a "Python list" containing this data. The author's solution is near the end of the PDF exercise document available on the book's webpage. The basic solution is to create a SearchCursor to read the data from a shape file, use the Parcel class to create a parcel object from each row of data, use the assessment method to calculate the tax, and then print the FID and tax amount.
... View more
03-20-2020
06:51 PM
|
1
|
2
|
4148
|
|
POST
|
You may need to use Make Feature Layer to convert your shape file into a "layer".
... View more
03-20-2020
12:30 PM
|
2
|
1
|
1572
|
|
POST
|
Perhaps something like: countFC = 'polygons' # feature containing outer polygons
countFld = ['ParcelCount', 'SHAPE@'] # ParcelCount is for count results, SHAPE@ is geometry of polygon
parcels = 'parcels' # parcels to be counted
with arcpy.da.UpdateCursor(countFC, countFld) as cursor: # cycle through outer polygon layer
for row in cursor:
arcpy.management.SelectLayerByLocation(parcels, "HAVE_THEIR_CENTER_IN", row[1], "", "NEW_SELECTION") # row[1] is SHAPE@
row[0] = int(arcpy.GetCount_management(parcels)[0]) # row[0] to be updated with count
cursor.updateRow(row) # update row
... View more
03-19-2020
03:25 PM
|
2
|
1
|
4723
|
|
POST
|
One approach would be to read the XY file line by line and use the data in an InsertCursor. Perhaps something like: # =========== CHANGE AS NEEDED ==========
xy_file = r'C:\Path\to\xy_test.csv'
feature = r'C:\Path\to\Test.gdb\XY_test'
# dictionary to match feature field name to csv column name
# { featureField : csvColumn, ... }
# first 2 fields are x and y coordinates
fld = { 'SHAPE@X' : 'X', # SHAPE@X is special token for x coordinate
'SHAPE@Y' : 'Y', # SHAPE@Y is special token for y coordinate
'Field1' : 'Field1',
'Field2' : 'Field2',
'Field3' : 'AnotherFld' # add field pairs as needed
}
inSR = 4326 # WGS 1984 (lon, lat)
outSR = 3857 # Web Mercator
# ==================================
import arcpy
import csv
fields = fld.keys()
cursor = arcpy.da.InsertCursor(feature,fields)
with open(xy_file, 'rb') as ff:
reader = csv.DictReader(ff) # (f, delimiter='\t', quoting=csv.QUOTE_NONE)
for r in reader:
values = { f:r[fld[f]] for f in fields } # pair csv file values with feature field names
# project x y coordinates as required
ptXY = arcpy.PointGeometry(arcpy.Point(values['SHAPE@X'],values['SHAPE@Y']),
arcpy.SpatialReference(inSR)).projectAs(arcpy.SpatialReference(outSR))
values['SHAPE@X'], values['SHAPE@Y'] = ptXY.firstPoint.X, ptXY.firstPoint.Y
# print values # print for debugging
cursor.insertRow([values[f] for f in fields])
del reader
del cursor
ff.close() Of course, you will probably need to make tweaks for your particular case.
... View more
03-14-2020
07:54 PM
|
1
|
0
|
3615
|
|
POST
|
I haven't fully tested it, but you might try this for the tool validator: import arcpy
class ToolValidator(object):
def __init__(self):
self.params = arcpy.GetParameterInfo()
def initializeParameters(self):
self.params[0].filter.list = ["Taucher", "Ganse", "Kormoran"]
self.params[0].value = self.params[0].filter.list[0] # default: Taucher
self.params[1].filter.list = ["Haubentaucher", "Zwergtaucher", "Prachttaucher"]
self.params[1].value = self.params[1].filter.list[0] # default: Haubentaucher
return
def updateParameters(self):
if self.params[0].value not in self.params[0].filter.list: # set defaults
self.params[0].value = self.params[0].filter.list[0] # default: Taucher
self.params[1].filter.list = ["Haubentaucher", "Zwergtaucher", "Prachttaucher"]
self.params[1].value = self.params[1].filter.list[0] # default: Haubentaucher
elif self.params[0].value == "Taucher": # Taucher selected
self.params[1].filter.list = ["Haubentaucher", "Zwergtaucher", "Prachttaucher"] # update list
if self.params[1].value not in self.params[1].filter.list: # if selection not in list
self.params[1].value = self.params[1].filter.list[0] # first option becomes default
elif self.params[0].value == "Ganse": # Ganse selected
self.params[1].filter.list = ["Brandente", "Nonnegans","Saatgans"]
if self.params[1].value not in self.params[1].filter.list:
self.params[1].value = self.params[1].filter.list[0]
elif self.params[0].value == "Kormoran": # Kormoran selected
self.params[1].filter.list = ["Kormoran"]
if self.params[1].value not in self.params[1].filter.list:
self.params[1].value = self.params[1].filter.list[0]
return
def updateMessages(self):
return
Hope it helps.
... View more
03-13-2020
12:53 PM
|
2
|
1
|
1830
|
|
POST
|
Puzzling. What if you try writing to a file instead of printing? This would create a tab delimited file with an xls extension Excel may give a "file format" error, but it should open it. import pyodbc
# MS Access DB connection
pyodbc.lowercase = False
conn = pyodbc.connect(r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};' +
r'DBQ=DBQ=C:\Desktop\PACP.MDB;')
# Open cursor and execute SQL
cursor = conn.cursor()
cursor.execute('select P_UpNumber, P_DownNumber FROM T_PIPES');
# open a file for writing
fw = open(r"C:\Desktop\PACP.xls","w") # edit path as needed
fw.write("{}\t{}\n".format('Upstream Manhole', 'Downstream Manhole')) # write a header row
for row in cursor.fetchall(): # loop through Access
fw.write("{}\t{}\n".format(row[0],row[1]))
fw.close() # close file You may wish to verify Access as being 64 or 32 bit. You should also be using a matching 64/32 bit version of Python.
... View more
03-12-2020
06:14 PM
|
0
|
1
|
6610
|
|
POST
|
One option would be to use the xlwt module, something like: import pyodbc
import xlwt
# MS Access DB connection
pyodbc.lowercase = False
conn = pyodbc.connect(r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};' +
r'DBQ=DBQ=C:\Desktop\PACP.MDB;')
# Open cursor and execute SQL
cursor = conn.cursor()
cursor.execute('select P_UpNumber, P_DownNumber FROM T_PIPES');
wb = xlwt.Workbook()
ws = wb.add_sheet("T_PIPES") # use table name for worksheet name
cols = ['Upstream Manhole', 'Downstream Manhole'] # renamed colum headings
wbRow = 0 # counter for workbook row
ws.write(wbRow, 0, cols[0]) # write column heading to first row
ws.write(wbRow, 1, cols[1])
for row in cursor.fetchall():
wbRow += 1 # increment workbook row counter
ws.write(wbRow, 0, row[0])
ws.write(wbRow, 1, row[1])
wb.save(r"C:\Path\to\PACP.xls") Was your script connecting to the database and printing results?
... View more
03-11-2020
08:49 PM
|
1
|
1
|
6610
|
|
POST
|
Thanks Joshua Bixby for the comment about using "SHAPE@". The SelectLayerByAttribute step is not necessary. oFields = ['OBJECTID', 'zoning_ove', 'SHAPE@']
with arcpy.da.SearchCursor(overlay,oFields) as cursor:
for row in cursor:
print "Processing feature {}".format(row[0])
arcpy.management.SelectLayerByLocation(parcels, "HAVE_THEIR_CENTER_IN", row[2], "", "NEW_SELECTION") # row[2] is SHAPE@
arcpy.management.CalculateField(parcels, pField, "'{}'".format(row[1]), "PYTHON_9.3")
... View more
03-06-2020
06:58 PM
|
1
|
0
|
4743
|
|
POST
|
Updated expression used in my previous code: import re
recs = [
"New SFR w/Attached Garage, covered parch and patio B24501000 0", # B24501000 0
"B34567000 0 30 X 48 Pole Barn", # B34567000 0
"NEW 22,778 SQ FT B33561000 0 Addition to existing hop building", # B33561000 0
"Residential B143560000 Storage", # B14356000
"Single Family Res B34561000A0", # B34561000A0
"New SFR w/Attached Garage, covered parch and patio B24501000 0" # B2450100000
]
pattern = re.compile(r"([\d]+[A-Z][\d]*|[\d]+[\s][\d]*)"
for rec in recs:
print(pattern.findall(rec)[0].strip())
'''
Results:
B24501000 0
B34567000 0
B33561000 0
B143560000
B34561000A0
B24501000 0
''' Then replace the space in the results with a zero or whatever. To experiment with regular expressions, see: Regular Expressions 101. This is the explanation given by the website of the expression used in line 12. "[\d]+[A-Z][\d]*|[\d]+[\s][\d]*"
gm
1st Alternative [\d]+[A-Z][\d]*
Match a single character present in the list below
B matches the character B literally (case sensitive)
Match a single character present in the list below [\d]+
+ Quantifier — Matches between one and unlimited times, as many times as possible, giving back as needed (greedy)
\d matches a digit (equal to [0-9])
Match a single character present in the list below [A-Z]
A-Z a single character in the range between A (index 65) and Z (index 90) (case sensitive)
Match a single character present in the list below [\d]*
* Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed (greedy)
\d matches a digit (equal to [0-9])
2nd Alternative [\d]+[\s][\d]*
Match a single character present in the list below
B matches the character B literally (case sensitive)
Match a single character present in the list below [\d]+
+ Quantifier — Matches between one and unlimited times, as many times as possible, giving back as needed (greedy)
\d matches a digit (equal to [0-9])
Match a single character present in the list below [\s]
\s matches any whitespace character (equal to [\r\n\t\f\v ])
Match a single character present in the list below [\d]*
* Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed (greedy)
\d matches a digit (equal to [0-9])
Global pattern flags
g modifier: global. All matches (don't return after first match)
m modifier: multi line. Causes ^ and $ to match the begin/end of each line (not only begin/end of string) EDIT: The following simpler expression also works for the examples in the code above: pattern = re.compile(r"([\d][\d A-Z]{7,9})")
# Letter B followed by a number, followed by 7 to 9 numbers, spaces, and/or capital letters
... View more
03-06-2020
04:53 PM
|
2
|
5
|
2402
|
|
POST
|
Perhaps the following. import re
recs = [
"New SFR w/Attached Garage, covered parch and patio B24501000 0", # B24501000 0
"B34567000 0 30 X 48 Pole Barn", # B34567000 0
"NEW 22,778 SQ FT B33561000 0 Addition to existing hop building", # B33561000 0
"Residential B143560000 Storage" # B14356000
]
pattern = re.compile(r"([\d ?]{8,10})") # B followed by 8-10 digits, may include space
for rec in recs:
print(pattern.findall(rec)[0].strip()) # strip trims a trailing space
''' Results:
B24501000 0
B34567000 0
B33561000 0
B143560000
'''
... View more
03-06-2020
02:12 PM
|
1
|
0
|
2402
|
|
POST
|
I took another look at your code and was wondering if you intended to create a new field in your parcels layer for each feature in the Merged_Overlays_Layer? This could be a lot of fields to add. Or did you intend to create a field and populate it with the name/ID of the overlay feature the parcel was located in? For the CalculateField, I believe the single quotes should be inside the double quotes for the third parameter. '"Overlay_{}".format(row[1])'
# try instead:
"'Overlay_{}'".format(row[1]) I was experimenting in Desktop and needed to add a 4th parameter "PYTHON_9.3" which is supposed to be optional, but without it I was getting an error. For my testing I was using the following code in ArcMap's Python window. Changes are probably required, but it may give you some ideas. parcels = 'austin_parcels_layer'
pField = 'Overlay' # new field for overlay feature name/ID
overlay = 'Merged_Overlays_layer'
oFields = ['OBJECTID', 'zoning_ove']
arcpy.management.AddField(parcels, pField, 'TEXT', None, 100) # add text field with length of 100
with arcpy.da.SearchCursor(overlay,oFields) as cursor:
for row in cursor:
select = "OBJECTID = {}".format(row[0])
arcpy.management.SelectLayerByAttribute(overlay, "NEW_SELECTION",select)
arcpy.management.SelectLayerByLocation(parcels, "HAVE_THEIR_CENTER_IN", overlay, "", "NEW_SELECTION")
arcpy.management.CalculateField(parcels, pField, "'{}'".format(row[1]), "PYTHON_9.3")
arcpy.management.SelectLayerByAttribute(overlay,"CLEAR_SELECTION") # clear any selections
arcpy.management.SelectLayerByAttribute(parcels,"CLEAR_SELECTION")
... View more
03-05-2020
07:55 PM
|
2
|
0
|
4743
|
|
POST
|
I don't think arcpy.env.workspace can take "two geoprocessing environments". Perhaps the comma in the workspace variable is causing the "something unexpected" error. # Set two geoprocessing environments
arcpy.env.workspace = r"D:\APRX, MXDS\Geo_Engine_Zoning_Project\Austin_Geo_Engine.gdb"
arcpy.env.overwriteOutput = True
... View more
03-05-2020
04:52 PM
|
1
|
1
|
4743
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 10-27-2016 02:23 PM | |
| 1 | 09-09-2017 08:27 PM | |
| 2 | 08-20-2020 06:15 PM | |
| 1 | 10-21-2021 09:15 PM | |
| 1 | 07-19-2018 12:33 PM |
| Online Status |
Offline
|
| Date Last Visited |
02-12-2026
07:13 PM
|