|
POST
|
You should set a visible scale range limit on the label properties so that if you zoom out too far the labels will not be displayed. Also I zoomed out to see what would happen without a visible scale range after adding the del statements. Here is the result at 2 different scale ranges to generate a large set of labels. It took a long time to draw, especially for the second example, but it did not crash. The error was my fault for not editing this line: whereClause = "%s = %s" % tuple(whereArgs) it should be: whereClause = "%s = %s AND %s = %s" % tuple(whereArgs)
... View more
09-11-2013
04:54 PM
|
0
|
0
|
8424
|
|
POST
|
Ah, interesting, zooming in did take prevent the crash. Didn't think that would matter since the labels would have to be created anyway. I am still a little hesitant that it might crash the system anytime but it does work. For the sql statement, I just wanted a data filter, which I worked around by putting it in the code with an if statement instead of using a sql clause
for row in rows:
if row[1] == "CHROMIUM": # data filter
finalString = (str(row[1]) + ": " + str(row[2]) + ": " + str(row[3])) # combining the label fields
labelList.append(finalString)
You are wrong. It only processes labels on features in the visible extent, so the list is reduced by zooming in. Also you want that filter in the SQL, since the number of rows returned affects the resources used. But I think the real resource issue is that I did not include the del statements. So add those and then zoom out. import arcpy
# variables that need to be customized for your specific data
def FindLabel ( [SampleName] ): # input the field name of the parent table's relate field
inputValue = [SampleName] # repeat the parent table's relate field
# define the data source path and fields of the related table
featureClass = r'Chromium_Data'
relatedFieldName = "sampleid" # the relate field name in the related table that corresponds to the input field
valueFieldName = "param" # desired label value field name in the related table
valueFieldName2 = "depth" # second field to label
valueFieldName3 = "result" # third field to label
# As long as you want a simple single field stacked label you should not need to change this code
whereArgs = [arcpy.AddFieldDelimiters(featureClass, relatedFieldName), "'" + inputValue + "'", arcpy.AddFieldDelimiters(featureClass, valueFieldName), "'CHROMIUM'"]
whereClause = "%s = %s AND %s = %s" % tuple(whereArgs)
labelList = []
rows = arcpy.da.SearchCursor(featureClass, (relatedFieldName, valueFieldName, valueFieldName2, valueFieldName3), whereClause)
for row in rows:
finalString = (str(row[1]) + " - " + str(row[2]) + " - " + str(row[3])) # combining the label fields
del row
labelList.append(finalString)
del rows
labelList.sort() # uses correct sort order for numbers, dates or strings
labelList.insert(0, inputValue) # insert input value as a heading
return "\n".join(str(labelvalue) for labelvalue in labelList)
... View more
09-11-2013
04:38 PM
|
0
|
0
|
8424
|
|
POST
|
Finally got it to work to look more like what I want, although running into a resource problem which is causing ArcMap to crash. This code works, and does what I need it to do to display two fields instead of just the one
import arcpy
# variables that need to be customized for your specific data
def FindLabel ( [SampleName] ): # input the field name of the parent table's relate field
inputValue = [SampleName] # repeat the parent table's relate field
# define the data source path and fields of the related table
featureClass = r'Chromium_Data'
relatedFieldName = "sampleid" # the relate field name in the related table that corresponds to the input field
valueFieldName = "depth" # desired label value field name in the related table
valueFieldName2 = "result" # second field to label
# As long as you want a simple single field stacked label you should not need to change this code
whereArgs = [arcpy.AddFieldDelimiters(featureClass, relatedFieldName), "'" + inputValue + "'"]
whereClause = "%s = %s" % tuple(whereArgs)
labelList = []
rows = arcpy.da.SearchCursor(featureClass, (relatedFieldName, valueFieldName, valueFieldName2), whereClause)
for row in rows:
finalString = (str(row[1]) + ": " + str(row[2])) # combining the label fields
labelList.append(finalString)
labelList.sort() # uses correct sort order for numbers, dates or strings
labelList.insert(0, inputValue) # insert input value as a heading
return "\n".join(str(labelvalue) for labelvalue in labelList)
This code theoretically works using 3 label fields, the code verification process displays the correct result, but the processing is too much and causes ArcMap to crash.
import arcpy
# variables that need to be customized for your specific data
def FindLabel ( [SampleName] ): # input the field name of the parent table's relate field
inputValue = [SampleName] # repeat the parent table's relate field
# define the data source path and fields of the related table
featureClass = r'Chromium_Data'
relatedFieldName = "sampleid" # the relate field name in the related table that corresponds to the input field
valueFieldName = "param" # desired label value field name in the related table
valueFieldName2 = "depth" # second field to label
valueFieldName3 = "result" # third field to label
# As long as you want a simple single field stacked label you should not need to change this code
whereArgs = [arcpy.AddFieldDelimiters(featureClass, relatedFieldName), "'" + inputValue + "'"]
whereClause = "%s = %s" % tuple(whereArgs)
labelList = []
rows = arcpy.da.SearchCursor(featureClass, (relatedFieldName, valueFieldName, valueFieldName2, valueFieldName3), whereClause)
for row in rows:
finalString = (str(row[1]) + " - " + str(row[2]) + " - " + str(row[3])) # combining the label fields
labelList.append(finalString)
labelList.sort() # uses correct sort order for numbers, dates or strings
labelList.insert(0, inputValue) # insert input value as a heading
return "\n".join(str(labelvalue) for labelvalue in labelList)
It would be nice if ArcMap could handle this by itself, but I could work around it by pre-concatnating my 3 fields into one within the database. Of course editing the database is not an ideal solution, but at least we got a working solution. Side question, do you know if there is a way to run a SQL statement within the code to filter the results, such as only displaying results where "valueFieldName3 = "desiredValue""? I am curious. Did you try limiting the visible scale of the labels to see if that has any influence on ArcMap crashing or not? I am not clear on what you mean in your last paragraph. If there are two criteria field values in the parent table that give the desired value for field 3 then that would be a modification to the def to include 2 fields separated by commas and constructing a whereclause with an AND condition. So it that what you want? Or is the desired value hard coded, i.e. all values > 0? Something like: def FindLabel ( [SampleName], [SampleName3] 😞 ... whereArgs = [arcpy.AddFieldDelimiters(featureClass, relatedFieldName), "'" + inputValue + "'", arcpy.AddFieldDelimiters(featureClass, valueFieldName3), "'" + [SampleName3] + "'"] whereClause = "%s = %s AND %s = %s" % tuple(whereArgs) Also probably you need to include del statements. I.e.: del row del rows # delete cursor after building the list to free resources labelList.sort() # uses correct sort order for numbers, dates or strings labelList.insert(0, inputValue) # insert input value as a heading return "\n".join(str(labelvalue) for labelvalue in labelList)
... View more
09-11-2013
04:16 PM
|
0
|
0
|
8424
|
|
POST
|
Here is a screen shot of the output where the street name is labeled with all of the House Numbers that occurred on that street in numeric sorted order. The labels are not optimized for prettiness or presentation. They just demonstrate that the code above created labels that used the road name values from the displayed lines and matched them to the house numbers from a related table to generate a label. Obviously there are better ways to present house numbers, such a min, max, count and average rather than labeling with the entire house number list, but that is formatting and not really relavant to the question about whether there is an alternative way to generate one-to-many relationship labels.
... View more
09-11-2013
12:02 PM
|
0
|
0
|
8424
|
|
POST
|
Richard, The result is the same. The script works, the selected annotation is copied from pa to oa. But, when the script is run the second time, the first copy is nullified, and the annotation(s) revert back from oa to pa. It works like editing and not saving edits. The tricky part seems to be copying & pasting into an existing Feature Class and having the Annotations saved into the Feature Class. I have also tried the Copy_management(input, output), but the statement does not like the existing oa Feature Class. Any further suggestions on how to get the copy & paste to "save"? Mark, Your suggestion of copying & pasting to a new Feature Class works. But, I want to use the two existing Annotation Feature Classes within ArcMap. It sounds to me like you are expecting Copy Features to do something it won't do. It won't append features to an existing feature class, it creates a new feature class. To append to an existing feature class and keep any previously existing features you have to use Append. If you actually do want to overwrite an existing feature class with a new feature class that uses the same name you cannot use the environment overwrite setting in a Python script to do that. That setting does not work in a Python script, it only works in Model Builder. You have to explicitly use the Delete tool to delete an existing feature class and then you can write to the same name the second time. This is how it always works. I have to run a script once without the Delete tool to just generate the outputs during the first run. Then before I can run it any more times I first have to add the Delete tool to the code and then I can run it again.
... View more
09-11-2013
11:37 AM
|
0
|
0
|
2656
|
|
POST
|
I know this is something we have been asking for forever, but I do not know if there is a real solution for this yet? Did anyone ever manage to recreate the "One to Many Label" script from VB6? Did ESRI finally give us a real solution to do the labeling? I saw one option of doing it using pivot tables that would require ArcInfo license, but that is a very roundabout solution using a license most people don't have. If anyone knows of a working solution please let me know. If you don't know what I am talking about, basically I am looking to make "callout box" type of labels such as: MW01 DEPTH BENZENE XYLENE 12 34 0.78 18 102 9 I have not updated the VB6 script, but have created a Python script that can be used in an Advanced Label expression using the Python parser. As written, thin code is designed for version 10.1 or later, since it used the data access module. It could be adapted to work with 10.0 cursors, but I do not think Python labels are supported prior to 10.0. At this point I have not attempting to develop a label anywhere near the complexity of the one you want. That will come later. But for now I have developed the core fundamental script that will build a simpler one-to-many relationship stacked label. The code below will create a label that lists the input value of the relate field from the parent table and then stacks underneath it the values of another field in a related table from all of the records that matched the input value in the related table's relate field. import arcpy # variables that need to be customized for your specific data def FindLabel ( [FULL_NAME] ): # input the field name of the parent table's relate field inputValue = [FULL_NAME] # repeat the parent table's relate field queryValue = "'" + inputValue + "'" # add query value delimiters for strings or dates here # define the data source path and fields of the related table featureClass = r'\\agency\agencydfs\Trans\rfairhur\Layers\PARCEL_LINES.gdb\ADDRESS_POINT_Locate_JURUP' relatedFieldName = "FULL_NAME" # the relate field name in the related table that corresponds to the input field valueFieldName = "HOUSE_NUMBER" # desired label value field name in the related table # As long as you want a simple single field stacked label you should not need to change this code whereArgs = [arcpy.AddFieldDelimiters(featureClass, relatedFieldName), queryValue] whereClause = "%s = %s" % tuple(whereArgs) labelList = [] rows = arcpy.da.SearchCursor(featureClass, (relatedFieldName, valueFieldName), whereClause) for row in rows: labelList.append(row[1]) labelList.sort() # uses correct sort order for numbers, dates or strings labelList.insert(0, inputValue) # insert input value as a heading return "\n".join(str(labelvalue) for labelvalue in labelList) Just as with the VB6 program, the labels take longer to build than labels based on fields from a single table. Python has several advantages over VB6 or any other form of VB. It can easily sort lists with correct sort orders for the value type contained in the list (numeric, date or string). And the Python data access cursors are faster than the cursors used with VB6. So this fundamental script can now be adapted to develop more sophisticated labels and multi-field labels. There are several challenges to doing a label as complex as the one you want, so I first wanted to develop a proof of concept script before trying to tackle those challenges.
... View more
09-11-2013
07:36 AM
|
0
|
0
|
8424
|
|
POST
|
Richard, I have tested each of the suggestions multiple times and my results were unsuccessful. arcpy.CopyFeatures_management(pa, oa) approach returns the Error 840: The value is not a Feature Class. arcpy.CopyFeatures_management(pa.name, oa.name approach runs but does not work. But, arcpy.env.workspace = "C:\Working\MyData\Python.gdb" arcpy.CopyFeatures_management("PropertyAnno", "OwnerAnno") works. An annotation is selected and using the Select Features tool, the script runs, and copies and pastes the annotation from PropertyAnno into OwnerAnno. The issue is with: pa = arcpy.mapping.ListLayers(mxd, "PropertyAnno", df)[0] oa = arcpy.mapping.ListLayers(mxd, "OwnerAnno", df)[0] They are defined as Layers, but the output requires a Feature Class. Commenting those out, the script works outside of an edit session. But, when the script is run multiple times, the previous copy does not save. How can the copy be saved? Mark, I am currently testing your suggestion. Try: arcpy.CopyFeatures_management(pa, oa.dataSource) pa should be the layer, because it has a selection, but dataSource should get the feature class and path for the output.
... View more
09-10-2013
04:18 PM
|
0
|
0
|
2656
|
|
POST
|
I am confused as to why the script does not work. I believe something is wrong my CopyFeatures_management statement. import arcpy
arcpy.env.workSpace = "C:\Working\MyData\Python.gdb"
arcpy.env.overwriteOutput = 'True'
mxd = arcpy.mapping.MapDocument ("CURRENT")
df = arcpy.mapping.ListDataFrames (mxd)[0]
pa = arcpy.mapping.ListLayers(mxd, "PropertyAnno", df)[0]
oa = arcpy.mapping.ListLayers(mxd, "OwnerAnno", df)[0]
arcpy.AddMessage(pa.name)
arcpy.AddMessage(oa.name)
arcpy.CopyFeatures_management("pa", "oa") Yet, if I write a basic script the CopyFeatures_management works. I only want to copy selected features & paste into an existing Feature Class, not create a new Feature Class. import arcpy try: arcpy.env.workspace = "C:\Working\MyData\Python.gdb" arcpy.CopyFeatures_management("HomeValue", "Test") except: print arcpy.GetMessages() It doesn't work because you are telling the CopyFeatures_management to use the literal strings "pa" and "oa", which are not the names of any layers. Unquote those variables and possibly use the .name property as you did in the messages. So try either: arcpy.CopyFeatures_management(pa, oa) or try arcpy.CopyFeatures_management(pa.name, oa.name)
... View more
09-10-2013
06:15 AM
|
0
|
0
|
2656
|
|
POST
|
Mark, How is oa not a Feature Class? ArcCatalog and ArcMap list the Data Type as a File Geodatabase Feature Class. The feature layer at its core is a feature class, but the layer itself is on top of that and is a Desktop display wrapper that defines its output location as a layer designed for placement in a map dataframe, not as a feature class file in a directory. This geoprocessing tool cannot use the layer wrapper that hides the feature class information from the tool. That is why when you interactively complete the tool you cannot drag a layer into the output text box of the CopyFeatures tool or type a layer name into the output of the tool. You have to navigate directories to fill in that part of the tool dialog with a full feature class path or you must only connect raw feature class variables or tool outputs that store direct pointers to a feature class path. Layers are only an indirect pointer to a feature class, not a direct pointer. Although many people use the term layer indiscriminately to refer to both what you see in the TOC of a Desktop map and the underlying data in ArcCatalog, technically the term is actually only correctly used to refer to what you see in a Desktop map TOC. The data stored on disk seen in ArcCatalog is only a feature class that has its own independent existence even if it was never used to create a layer in a Desktop map TOC. Likewise, layers can exist without a feature class (when a layer has a red exclamation mark due to a lost data connection it is still a layer even though it has no feature class and virtually no real functionality).
... View more
09-09-2013
09:14 AM
|
0
|
0
|
2732
|
|
POST
|
You made three errors. Xander pointed out one, which is that you put the result on the same line as the else clause rather than on a new line. The second it that at 10.0 you should not use Dim statements. VBA is gone and in VB script all variables are Variant and can no longer be defined, so don't bother with them or just put Dim codigo and nothing else. The third is that you closed the If block with EndIf (one word) and not End If (two words). Assuming there are no null values in your data and your field is long enough to handle the largest value stored in the CAMPO field this code will work (with codigo being put in the field text box as you indicated): If [CAMPO] = "Captura" OR [CAMPO] = "Replanteo" OR [CAMPO] = "GPS" Then
codigo = "1"
ElseIf [CAMPO] = "Plano" OR [CAMPO] = "Ortofoto" Then
codigo = "2"
ElseIf [CAMPO] = "Catastro" OR [CAMPO] = "Ajuste parcelario" Then
codigo = "3"
Else
codigo = [CAMPO]
End If
... View more
09-09-2013
07:09 AM
|
0
|
0
|
878
|
|
POST
|
Do you still have the unclipped feature in your mxd? If so did you try and remove it before exporting? That won't work. He is using a data frame clip, not the Clip tool. Data frame clips don't alter the original data. You could try to create a selection of the features within the clip boundary and then create a Selection layer for the labeling. That way you could turn off the full layer and with the Selection layer no labels will be created outside the dataframe and you won't have to create a new fc. (Of course you have to manually configure the selection layer to match the full layer for labeling and symbology, because it won't match by default).
... View more
09-05-2013
11:30 AM
|
0
|
0
|
2743
|
|
POST
|
Only add ArcLength when it is greater than '0'. Otherwise, the script should return shapeLength values and add those together. Then just use the code as written in my post before that. Here is how to make the message only report the totals if they are above 0. for lyr in arcpy.mapping.ListLayers(mxd):
dsc = arcpy.Describe(lyr)
sel_set = dsc.fidSet.replace(";",",")
if dsc.shapeType == "Polyline" and dsc.fidSet != "":
cursor = arcpy.da.SearchCursor(lyr, ["OID@", "ARCLENGTH", "Shape_Length"], "OBJECTID IN (" + sel_set + ")")
arcLengthTot = 0
shapeLengthTot = 0
for row in cursor:
arcLength = row[1]
shapeLength = row[2]
if arcLength > '0':
arcLengthTot += float(arcLength)
arcpy.AddMessage("ArcLength = " + arcLength)
else:
shapeLengthTot += shapeLength
arcpy.AddMessage("ShapeLength = " + str(shapeLength))
if arcLengthTot > 0:
arcpy.AddMessage("ArcLengthTot = " + str(arcLengthTot))
if shapeLengthTot > 0:
arcpy.AddMessage("ShapeLengthTot = " + str(shapeLengthTot))
del row
del cursor Both totals messages could print for a given selection is you selected a mix of the two kinds of arcs/shapes as a group. You could now optionally comment out the individual reported lengths if you want just the totals or leave both individual segment and totals messages. For a single feature the messages would print two times and repeat the same number unless some more logic is added about the sel_set count.
... View more
09-04-2013
11:47 AM
|
0
|
0
|
1057
|
|
POST
|
Rereading my last post, I realize my statement maybe clear as mud. I need to add arcLength + arcLength and shapeLength + shapeLength, as two separate expressions. Reread my post. After you posted this I made some edits that should be clearer. In the case of ShapeLength, did you want it to add even when ArcLength is greater than '0' or just when arcLength is less than or equal to '0'? I wrote it to do the latter. If you wanted it to do the former the code within the cursor rotuine would be if arcLength > '0':
arcLengthTot += float(arcLength)
shapeLengthTot += shapeLength
arcpy.AddMessage("ArcLength = " + arcLength)
else:
shapeLengthTot += shapeLength
arcpy.AddMessage("ShapeLength = " + str(shapeLength)) Edit: Fixed another indent issue.
... View more
09-04-2013
11:34 AM
|
0
|
0
|
1057
|
|
POST
|
This is quickly becoming the script that would not go away. I have read through the help on arithmetic operators. I need to add the selected ArcLength values together and the selected Shape_Length values together. What is the syntax difference in using + for an arithmetic operator and using the + to concatenate fields? The difference is if the expressions on each side are both strings or both numbers. A mix should trigger an error. So once you have established that you are dealing with an ArcLength that is greater than '0' cast it to a float and then do the addition and then cast back to a string if it has to overwrite the ArcLength field. So to do all of that it should be: for lyr in arcpy.mapping.ListLayers(mxd):
dsc = arcpy.Describe(lyr)
sel_set = dsc.fidSet.replace(";",",")
if dsc.shapeType == "Polyline" and dsc.fidSet != "":
cursor = arcpy.da.SearchCursor(lyr, ["OID@", "ARCLENGTH", "Shape_Length"], "OBJECTID IN (" + sel_set + ")")
arcLengthTot = 0
shapeLengthTot = 0
for row in cursor:
arcLength = row[1]
shapeLength = row[2]
if arcLength > '0':
arcLengthTot += float(arcLength)
arcpy.AddMessage("ArcLength = " + arcLength)
else:
shapeLengthTot += shapeLength
arcpy.AddMessage("ShapeLength = " + str(shapeLength))
arcpy.AddMessage("ArcLengthTot = " + str(arcLengthTot))
arcpy.AddMessage("ShapeLengthTot = " + str(shapeLengthTot))
del row
del cursor
... View more
09-04-2013
11:20 AM
|
0
|
0
|
2377
|
|
POST
|
Why does changing the number 0 to a string '0', change the selection from arcLength to shapeLength? For instance, if len(arcLength) > 0: returns arcLength and if len(arcLength) > '0': returns shapeLength? The ARCLENGTH field is a string and the Shape_Length field is a double. I didn't write if len(arcLength) > '0':. That is a meaningless piece of code and should return an error, since a it is comparing a number with a string. The alternative you wrote is also wrong. if len(arcLength) > 0: should return arclength even if it is ' ', which you don't want. The version James wrote was if len(arcLength) > 1: and it will not return ' ' through '9', which is also wrong. I wrote if arcLength > '0':, which compares the string with a string and will return arcLength in all cases except where it is equal to ' ' or '0'. It will return '1' - '9'. Use the code I wrote and you will get the most correct results. (It still could fail if you had values like ' 0' or '00', but I considered that to be too unlikely to add more tests to evaluate.)
... View more
09-04-2013
06:20 AM
|
0
|
0
|
5162
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 03-24-2026 11:37 PM | |
| 1 | 03-24-2026 08:01 PM | |
| 7 | 02-23-2026 08:34 AM | |
| 1 | 03-31-2025 03:25 PM | |
| 1 | 03-28-2025 06:54 PM |
| Online Status |
Offline
|
| Date Last Visited |
07-09-2026
12:59 AM
|