Advanced Labeling In ArcMap With VBScript FindLabel Functions
1. exists Have you ever needed to do just a little bit or perhaps much
more to label a featureclass in ArcMap than the standard
1
2
Function FindLabel ([TOTNETAC], [NETNP], [NETPR], [NETHBP], [NETHBO], _
[TOTNETFED], [NETFEDNP], [NETFEDPR], [NETFEDHBP], [NETFEDHBO]) The Problem ESRI or even Maplex labeling engine would allow? Me too. The Problem
3
4 Dim iMaxValSz, h, i, j, k, space, intIndex, fedIntIndex, netArray, strLabel, strCarReturns, _ Lucky for us, with the release of ArcGIS 8.1, ESRI
5 strFedLabel, mathNP, mathHBP, mathPR
You have a dataset with multiple attributes Here we have a point dataset (gas wells, to be more precise) where multiple
6
7
iMaxValSz = 0 ' set max value size initial value to zero
' Set our field values into variables
introduced quot;advancedquot; labeling to all licensing levels using points in the same location are stacked and each one has a different label. Each
8 totnetac = [TOTNETAC] you want to label with, but when values are
9 netnp = [NETNP] absent (zero or null), you want to skip that the FindLabel function and your choice of two scripting record for one well (some have only one point, some have 4+) represents a
10 netpr = [NETPR]
11 nethbp = [NETHBP] attribute. Also, it’s a polygon featureclass, languages: VBScript and JScript. Advanced labeling along producing zone. The well names are almost identical except for codes that denote
12 nethbo = [NETHBO]
so absolutely positioning the labels can be what zone the well is producing from. We need to get rid of the multiple labels, yet
13
14
fednp = [NETFEDNP]
fedpr = [NETFEDPR] with the FindLabel function provides a way to still show all of the points.
15 fedhbp = [NETFEDHBP] difficult.
16
17
' SECTIONS WITH FEDERAL LEASES
If FormatNumber([TOTNETFED]) > 0 Then BEFORE programmatically define the text that displays when labeling
18
19
20
' Do some math, compare fed to non‐fed NP/HBP/PR, if arent equal, get the difference
' between the two, the non‐federal portion. If equal, set var to zero. Var goes into
' array, if zero, ignore it, if non‐zero, display as non‐federal acreage
features. Through the use of code examples, we will focus BEFORE
21 ' Compare NP/FNP on using VBScript and FindLabel functions to do advanced
22 If [NETNP] = [NETFEDNP] Then
23
24 Else
mathNP = quot;0quot; labeling of features by incorporating scripting functionality
25
26
If ([NETNP] ‐ [NETFEDNP]) <= 0.5 Then
mathNP = FormatNumber(([NETNP] ‐ [NETFEDNP]),2) such as conditional logic, arrays, and regular expressions.
27 ElseIf Right((FormatNumber(([NETNP] ‐ [NETFEDNP]),2)),2) = quot;00quot; Then
28
29
mathNP = FormatNumber(([NETNP] ‐ [NETFEDNP]),0)
ElseIf Right((FormatNumber(([NETNP] ‐ [NETFEDNP]),2)),2) <> quot;00quot; Then
With a little (or sometimes a lot) of code, users can either
30
31 End If
mathNP = FormatNumber(([NETNP] ‐ [NETFEDNP]),2)
simplify or add complexity to their feature labels without
32 End If
33 ' Compare HBP/FHBP having to modify the underlying data, create temporary
34 If [NETHBP] = [NETFEDHBP] Then
35
36 Else
mathHBP = quot;0quot; datasets for the sole purpose of labeling, or convert labels
37
38
If ([NETHBP] ‐ [NETFEDHBP]) <= 0.5 Then
mathHBP = FormatNumber(([NETHBP] ‐ [NETFEDHBP]),2) to annotation and - oh, the horror - manually arrange labels
39 ElseIf Right((FormatNumber(([NETHBP] ‐ [NETFEDHBP]),2)),2) = quot;00quot; Then
40
41
mathHBP = FormatNumber(([NETHBP] ‐ [NETFEDHBP]),0)
ElseIf Right((FormatNumber(([NETHBP] ‐ [NETFEDHBP]),2)),2) <> quot;00quot; Then
by hand.
42 mathHBP = FormatNumber(([NETHBP] ‐ [NETFEDHBP]),2)
43 End If
44 End If
45 ' Compare PR/FPR Inspirations/other resources
46 If [NETPR] = [NETFEDPR] Then
47 mathPR = quot;0quot;
48 Else
49
50
If ([NETPR] ‐ [NETFEDPR]) <= 0.5 Then
mathPR = FormatNumber(([NETPR] ‐ [NETFEDPR]),2) Hankley, Chip. Using VBScript to Build Complex Labels in
51 ElseIf Right((FormatNumber(([NETPR] ‐ [NETFEDPR]),2)),2) = quot;00quot; Then
52
53
mathPR = FormatNumber(([NETPR] ‐ [NETFEDPR]),0)
ElseIf Right((FormatNumber(([NETPR] ‐ [NETFEDPR]),2)),2) <> quot;00quot; Then
ArcGIS. ArcUser. October-December 2004: 50-53. Online
54
55 End If
mathPR = FormatNumber(([NETPR] ‐ [NETFEDPR]),2)
at http://www.esri.com/news/arcuser/1104/files/
56 End If
57 ' Build array for FED values, if mathNP/mathHBP/mathPR are zero, theyre ignored below when vbscript_label.pdf
58 ' tested, otherwise, they are included in the array explosion as non‐fed acreage
59 fedArray = Array(Array(totnetac, quot;<clr red='255'>quot;, quot; CNT</clr>quot;), _
60 Array(mathNP, quot;<clr red='0' green='0' blue='0'>quot;, quot; NP</clr>quot;), _
Partial Solution
61
62
Array(mathHBP, quot;<clr red='0' green='0' blue='0'>quot;, quot; HBP</clr>quot;), _
Array(mathPR, quot;<clr red='0' green='0' blue='0'>quot;, quot; PR</clr>quot;), _ Hoque, Mohammed A. Labeling Features Using Attributes
63 Array(fednp, quot;<clr red='132' green='0' blue='168'>quot;, quot; FNP</clr>quot;), _
64
65
Array(fedpr, quot;<clr red='132' green='0' blue='168'>quot;, quot; FPR</clr>quot;), _
Array(fedhbp, quot;<clr red='132' green='0' blue='168'>quot;, quot; FHBP</clr>quot;))
Sure, we can stack the labels with a simple from an External Database. ArcUser July-September 2005:
66 ' Determine length of longest acreage string in array FindLabel function, but the results aren’t pretty at all. 52-53. Online at http://www.esri.com/news/arcuser/0705/
67 ' Use it later to center longer strings in section
68 For i = 0 To UBound(fedArray)
69 j = fedArray(i) 1 Function FindLabel ([TOTNETAC],[NETPR],[NETNP],[NETHBP],
[NETHBO],[NETFEDPR],[NETFEDNP],[NETFEDHBP])
files/externaldb.pdf
70 If (Len(j(1)) > iMaxValSz) Then
71 iMaxValSz = Len(j(1)) 2 FindLabel = [TOTNETAC] & vbNewLine & [NETPR] & vbNewLine & _
72 End If 3 [NETNP] & vbNewLine & [NETHBP] & vbNewLine & _
4 [NETHBO] & vbNewLine & [NETFEDPR] & vbNewLine & _
73 Next
Write the FindLabel
74
75
' START MAKING LABEL
strFedLabel = quot;<bol>quot;
1 function
5
6 End Function
[NETFEDNP] & vbNewLine & [NETFEDHBP]
76 ' Explode array values, if they are > 0
77 k = fedArray(0) Place it in the
78
79
fedIntIndex = 0
For h = 0 To UBound(fedArray) Better Solution 2 label expression The Solution
80 k = fedArray(h)
81
82 If iMaxValSz > 2 Then ' push longer acreage strings over to
83 space = quot; quot; ' the left a little, center in section Arrays to the rescue! Using a nested array, Let’s put a regular expression to work for us. Regular expressions
84
85
Else
space = quot;quot; we can test values and only use valid ones in provide us with a way of identifying characters, words, or patterns
86
87
End If
our label. We can also color the fonts of of characters in strings of text. They are similar to wildcards,
88 If k(0) > 0 Then specific attributes, perform calculations using except much more powerful. For our label to work, you must have
89 strFedLabel = strFedLabel & space & k(1) & k(0) & k(2) & vbNewLine
attribute values and place the results into our access to the Maplex labeling engine, since we are going to use Place it in the
90
91 End If
fedIntIndex = fedIntIndex + 1 ' count lines for non‐zero hits from array
the “Remove duplicate labels” function of the Maplex engine.
2 label expression
92 Next label array. By using a point featureclass
' Determine how many carriage returns are needed to top align
93
94 ' acreage list in the section polygon, based on line hits above (converted from the polygon featureclass) to Here’s how this works:
95 Select Case fedIntIndex
label with, we have control over the absolute
96
97
98
Case 2
Case 3
strCarReturns = vbNewLine & vbNewLine position of the labels around the points. a) Look at the attribute table for this dataset (upper right). Notice AFTER
99 strCarReturns = vbNewLine that well names are all based off of the lease name and have the
100
101
Case Else
strCarReturns = quot;quot; AFTER zone information appended to that. If we can make the well names
102
103
End Select
' FINAL BUILD OF LABEL
all the same, then the Maplex “Remove duplicates” function will
104
105
FindLabel = strFedLabel & quot;</bol>quot; & strCarReturns remove all but one of those labels – with no modification of our
106 Else underlying dataset!
107 ' SECTIONS WITHOUT FEDERAL LEASES
108 ' Build nested array of field values for non‐federal acreage b) Our regular expression looks for the common combinations that
109 netArray = Array(Array(quot; CNT</clr>quot;, totnetac, quot;<clr red='255'>quot;), _
110 Array(quot; NP</clr>quot;, netnp, quot;<clr red='0' green='0' blue='0'>quot;), _ occur in the zone names at the end of the well names (“CM”, “UT”,
Array(quot; PR</clr>quot;, netpr, quot;<clr red='0' green='0' blue='0'>quot;), _
111
112 Array(quot; HBP</clr>quot;, nethbp, quot;<clr red='0' green='0' blue='0'>quot;), _
“Not Active”, etc.) and simply replaces those occurrences with “” -
113
114
Array(quot; HBO</clr>quot;, hbo, quot;<clr red='0' green='0' blue='0'>quot;))
' Determine length of longest acreage string in array
nothing.
115 ' Use it later to center longer strings in section c) Now that our labels are all the same for any one well with
116 For i = 0 To UBound(netArray)
117 j = netArray(i) multiple zones, Maplex drops the duplicates and leaves us just one
118 If (Len(j(1)) > iMaxValSz) Then
119 iMaxValSz = Len(j(1)) – exactly what we wanted. Remove duplicate
120 End If 3 labels
121 Next
122 ' START BUILDING THE LABEL
123
124
strLabel = quot;<bol>quot;
' Loop thru array, get our values, if not = 0
Values of zero 1 Function FindLabel ( [Well_Name] )
125 j = netArray(0) ' reset j to be first sub‐array in netArray get omitted 2
3 FindLabel = ParseWellName([Well_Name])
126 intIndex = 0 ' reset array counter
127 For i = 0 To UBound(netArray) from the array 4
128 j = netArray(i) 5 End Function
129 6
' push longer acreage strings over to 7 Function ParseWellname(well_name) Write the FindLabel
130
131
If iMaxValSz > 2 Then
space = quot; quot; ' the left a little, center in section 8 1 function
132 Else 9 Dim patt, reg_exp, repl
133 space = quot;quot; 10 Set reg_exp = New RegExp
134 End If 11 reg_exp.IgnoreCase = False
135 12 ' Regex to look for commingle, tubing, casing, inactive,
13 ' not active zones that we don't want labeled Set duplicate label
136
137
If j(1) > 0 Then ' test for zero values, skip em
strLabel = strLabel & space & j(2) & j(1) & j(0) & vbNewLine 14 patt = quot;(s)quot; & _ 4 search tolerance
138 intIndex = intIndex + 1 ' count how many returns we get 15 quot;(C*s*T*s*(?CM)?s*((Inactive)$|(Not Active))*$|quot; & _
139 End If ' from our array, only non‐zero hits 16 quot;Cs*((Inactive)$|(Not Active))*$|quot; & _
140 Next 17 quot;Ts*((Inactive)$|(Not Active))*$|quot; & _
141 ' Determine how many carriage returns are needed to top align 18 quot;UT (Inactive)$|quot; & _
142 ' acreage list in the section polygon, based on line hits above 19 quot;LT (Inactive)$|quot; & _
143 Select Case intIndex 20 quot;((Inactive)$|(Not Active))*$|quot; & _
144 Case 2 21 quot;C$|T$|UT$|LT$|quot; & _
145 strCarReturns = vbNewLine & vbNewLine 22 quot;((?CM)?$|T|C)* (?CM)?$|quot; & _
146 Case 3 23 quot;[C|CM|T|LT|UT]*s*STORAGE$)quot; DISCLAIMER: Not the
147 strCarReturns = vbNewLine 24 most efficient or elegant
148 Case Else 25 reg_exp.Pattern = patt regular expression, but
149 strCarReturns = quot;quot; 26 repl = quot;quot; it works
150 End Select 27
151 ' FINAL BUILD OF NON‐FEDERAL LABEL 28 result = reg_exp.Replace(well_name, repl)
152 FindLabel = strLabel & strFedLabel & quot;</bol>quot; & strCarReturns 29
153 End If 30 ParseWellname = result
154 End Function Absolutely position 31
3 label around point
32 End Function
For more information about using regular expressions with VBScript, see http://msdn.microsoft.com/en-us/library/ms974570.aspx or Google “regular expressions vbscript”.
I also find the book VBScript in a Nutshell (published by O’Reilly, ISBN# 0596004885) to be an indispensable resource for writing FindLabel functions in VBScript.
This poster available as a pdf at: http://www.super-cooper.com/okscaug