Hatch expression help

2112
15
Jump to solution
08-12-2013 01:32 PM
BrettMorse
New Contributor
This is driving me crazy and I'm sure its something really simple but I can't find examples to show me what to do so I'm hoping someone here can help me out.  I have a route with measures that I'm trying to format into 123+45

I ran this in PythonWin just to make sure I had this part right:

import arcpy
station = "37000"
rs = station[-2:]
ls = station[:-2]
print ls + "+" + rs

it gave me this:

370+00

just what I'm trying to do.  So then I go to the Hatch Text Expression dialogue and hit advanced.  First thing I probably need to know is what FindLabel is doing?  I looked around on the internet  trying to find it and still I'm not very sure.  Could be I just suck at the internet though.  I'm guessing the statement def FindLabel ( esri_measure) just lists the arguments you're going to use below it.  Does it make a string or is it a still a number?

So far in the advanced box I can get this much to work:

def FindLabel ( esri__measure 😞
  return str(int(esri__measure))

and it seems to return a value with no decimals just fine.

But when I start trying to add to that to get my 123+45 format it keeps giving me the error "No features found.  Could not verify expression."

This is going to have a lot to do with my inexperience using Python this way and my inexperience with Python in general I'm sure, but I haven't been able to find any good examples on the internet to help me puzzle this out or explain it to me.

If someone could show me how to enter this into the advanced expression box or point me to some good examples so I can figure it out myself that would be great.

Thanks in advance!
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
StacyRendall1
Occasional Contributor III

def FindLabel ( esri__measure ):   if len(str(int( esri__measure ))) == 0:     return "0+00"   elif len(str(int( esri__measure ))) == 2:     return "0+{0}{1}".format( *esri__measure )   elif len(str(int( esri__measure ))) == 3:     return "{0}+{1}{2}".format( *esri__measure )   elif len(str(int( esri__measure ))) == 4:     return "{0}{1}+{2}{3}".format( *esri__measure )   elif len(str(int( esri__measure))) == 5:     return "{0}{1}{2}+{3}{4}".format( *esri__measure )   elif len(str(int( esri__measure ))) == 6:     return "{0}{1}{2}{3}+{4}{5}".format( *esri__measure )

It verifies, but it returns nothing.  Just a blank.  I also tried it without the str(int part and got the same thing.  A blank when verified.


This fails because the asterisk (*) only works on certain iterables: strings, lists, tuples. A float (which esri__measure is) is not iterable. However, I am surprised it didn't throw a more useful error, like TypeError.

The other issues you discussed in the above-mentioned post appear to be related to having square brackets within the expression. I cannot get square brackets within the expression to work...

The code below is an adaptation of your code above, but includes the case where len == 1. My earlier answer didn't account for the fact that esri_measure is a floating point number, so will not work correctly. You should note that using int() on floats doesn't round as you might expect, so I use int(round(esri__measure)).

def FindLabel (esri__measure):   EM = str(int(round(esri__measure)))   if len(EM) == 0:     return "0+00"   elif len(EM) == 1:     return "0+0{0}".format(*EM)     elif len(EM) == 2:     return "0+{0}{1}".format(*EM)   elif len(EM) == 3:     return "{0}+{1}{2}".format(*EM)   elif len(EM) == 4:     return "{0}{1}+{2}{3}".format(*EM)   elif len(EM) == 5:     return "{0}{1}{2}+{3}{4}".format(*EM)   elif len(EM) == 6:     return "{0}{1}{2}{3}+{4}{5}".format(*EM)

View solution in original post

0 Kudos
15 Replies
StacyRendall1
Occasional Contributor III
I have never used this tool before, but it appears that you can't use square brackets within the expression, as square brackets also define the fields being passed to the tool...

So, when you are using something like [-2:] in the expression, it is looking for a field named -2:, which doesn't exist, and thus has no features.

Hopefully someone from ESRI has a workaround or some help?
0 Kudos
StacyRendall1
Occasional Contributor III
I think I found something that might help, using string formats. More info here.

It will only work as long as your field is always five characters long (the other method would have worked if shorter or longer too). Note that it is a one-liner, so you do not need to check the advanced box.

"{0}{1}{2}+{3}{4}".format( *[esri__measure])


The asterisk unpacks the string, so "37000" becomes like the tuple ('3', '7', '0', '0', '0'), and the numbers in the format string address elements of this tuple.

If the number of characters in the field changes you could use a conditional statement to check length (in which case you would have to check the advanced box):
def FindLabel ( [esri__measure] ):
    if len([esri__measure]) == 5:
        return "{0}{1}{2}+{3}{4}".format( *[esri__measure])
    elif len([esri__measure]) == 6:
        return "{0}{1}{2}{3}+{4}{5}".format( *[esri__measure])
    else:
        return "UNKNOWN FIELD LENGTH"
0 Kudos
Luke_Pinner
MVP Regular Contributor
Square brackets work fine in the label expression (tested on 10.1)

def FindLabel ( [FIELD_NAME] ):
    rs = [FIELD_NAME][-2:]
    ls = [FIELD_NAME][:-2]

    return  ls + "+" + rs
0 Kudos
StacyRendall1
Occasional Contributor III
Square brackets work fine in the label expression (tested on 10.1)

def FindLabel ( [FIELD_NAME] ):
    rs = [FIELD_NAME][-2:]
    ls = [FIELD_NAME][:-2]

    return  ls + "+" + rs


You are indeed correct!

I think I must have been just testing that on single line ones like:
[FIELD_NAME][0:-2]

which do not work!
0 Kudos
curtvprice
MVP Esteemed Contributor
Square brackets work fine in the label expression (tested on 10.1)

def FindLabel ( [FIELD_NAME] ):
    rs = [FIELD_NAME][-2:]
    ls = [FIELD_NAME][:-2]

    return  ls + "+" + rs


The code block, which is simply a python function that takes an input and returns an output, should use a Python variable -- not field names. (The insertion of the field value for [fieldname] only happens in the expression block.)

Expression: FindLabel(![FIELDNAME]!)

Code:
def FindLabel(fn):
  rs = fn[:3] # first three chars
  ls = fn[3:]  # characters four-> end
  return "{0}+{1}".format(rs, ls)  
 
0 Kudos
BrettMorse
New Contributor
Okay, so I've tried these suggestions.  I'm think the problem might be the esri__measure comes from the route and is assigned where ever the hatch mark falls or something because nothing is working here for me anyway.

I tried this one.

def FindLabel ( esri__measure ):
  if len(str(int( esri__measure ))) == 0:
    return "0+00"
  elif len(str(int( esri__measure ))) == 2:
    return "0+{0}{1}".format( *esri__measure )
  elif len(str(int( esri__measure ))) == 3:
    return "{0}+{1}{2}".format( *esri__measure )
  elif len(str(int( esri__measure ))) == 4:
    return "{0}{1}+{2}{3}".format( *esri__measure )
  elif len(str(int( esri__measure))) == 5:
    return "{0}{1}{2}+{3}{4}".format( *esri__measure )
  elif len(str(int( esri__measure ))) == 6:
    return "{0}{1}{2}{3}+{4}{5}".format( *esri__measure )


It verifies, but it returns nothing.  Just a blank.  I also tried it without the str(int part and got the same thing.  A blank when verified.

The brackets are to call a field name, problem is this isn't a field name.

I tried this next.

def FindLabel ( esri__measure ):
  m = esri__measure
  return m


And that works.  Returns my station just as if I hadn't changed anything.  I'm not worried about the integer anymore because my interval is set to 1000' so there is nothing on the end anyway.

So with that working I'm thinking I'm on to something so I try this next.

def FindLabel ( esri__measure ):
  m = esri__measure
  ls = m[:-2]
  rs = m[-2:]
  return ls "+" rs


When I verify this it throws up the error "No features found.  Could not verify expression."

This is the same bit I tried out in PythonWin making m an integer and a string and it worked both times.

Maybe someone sees something I'm not catching (don't know about) and can get this working for me please.

By the way I'm using 10.1

Thanks again for the help here!

I just tried that first code in PythonWin and changed return to print and added the else at the bottom in case it wouldn't print any of the if statements and I get nothing.  No errors or anything so I'll be trying to figure that out too.

Just tried this too:

def FindLabel ( esri__measure ):
  rs = esri__measure[-2:]
  ls = esri__measure[:-2]
  return ls + "+" + rs


Same error, "No features found.  Could not verify expression"
0 Kudos
StacyRendall1
Occasional Contributor III
OK, I finally found the Hatch Expression calculator. Previously I was testing on Label Expression/Display expression, assuming that they were the same thing. They are not. If it is any use to others: more information is shown below about locating the Hatch Expression tool and the testing that lead to finding the answer.

In Hatch Expression, this seems to work (note that it is not advanced, so that box must be un-checked):
"{0}{1}{2}+{3}{4}".format( *str(esri__measure))


As before, this will only work for inputs of length 5. If you want to condition test, this seems to work (is advanced, box must be checked):
def FindLabel ( esri__measure):
  EM = str(esri__measure)
  if len(EM) == 5:
    return "{0}{1}{2}+{3}{4}".format(*EM)
  elif len(EM) == 6:
    return "{0}{1}{2}{3}+{4}{5}".format(*EM)
  else:
    return "UNDEFINED INPUT"


Unfortunately it doesn't seem possible to have any square brackets anywhere within the statement (see below). If this was possible, something like the following would work for any length of input > 2:
def FindLabel (esri__measure):
  s = ''.join(['{%s}' % i for i in str(esri__measure)])
  return s[:-6] + '+' + s[-6:]



[/HR]


For others reading this post: Hatch Expression is (only? - I can't find much info) a property of Network Analyst Routes. To find Hatch Expression: Solve an NA Route analysis, use Layer Properties on the Route, select Hatches tab, go to the Hatch Def, under labels tick Label these hatches, click Label Settings, select Build a text expression radio button, click the Expression button... Here is an image showing the steps, and initial state after setting to Python and checking the advanced option:
[ATTACH=CONFIG]26685[/ATTACH]

Things that work (display an output after clicking Verify):
[INDENT]Non-advanced (i.e. single line):
esri__measure

str(esri__measure)

'{0}'.format(esri__measure)
[/INDENT]
[INDENT]Advanced:
def FindLabel ( esri__measure):
  return esri__measure

def FindLabel ( esri__measure):
  return str(esri__measure)

def FindLabel ( esri__measure):
  EM = str(esri__measure)
  return EM
[/INDENT]

Things that fail (display No features found. Could not verify expression. after clicking Verify):
[INDENT]Non-advanced:
str(esri__measure)[0]
[/INDENT]
[INDENT]Advanced:
def FindLabel ( esri__measure):
  EM = str(esri__measure)
  return EM[0] + EM[-1]
[/INDENT]
0 Kudos
StacyRendall1
Occasional Contributor III
The code block, which is simply a python function that takes an input and returns an output, should use a Python variable -- not field names. (The insertion of the field value for [fieldname] only happens in the expression block.)

Expression: FindLabel(![FIELDNAME]!)

Code:
def FindLabel(fn):
  rs = fn[:3] # first three chars
  ls = fn[3:]  # characters four-> end
  return "{0}+{1}".format(rs, ls)  
 


Curtis, I was talking about a Label/Display Expression (assuming that it was the same as a Hatch Expression). It seems to work different to normal code blocks. You can access it through: Layer Properties, Labels tab, Expression button. Here is an image showing it in action:[ATTACH=CONFIG]26680[/ATTACH]

It turns out that Hatch Expression is different again. See my above post for more info.
0 Kudos
BrettMorse
New Contributor
To get to the hatching you have to be using a route.  The esri__measure comes from that automatically and is not a field that requires the [].

To get to the hatch just go to your route properties and it will be a tab at the top.  Under the Hatch Class in the box on the left there will be a Hatch Def(1) or however many you add.  If you click on the Hatch Def you will have options, one of which will be to label the hatches you have set up.  You can control the symbol here like normal.  You can then click the label settings in the label section and click the build a text expression bubble and then click the expression button.

Once you click the expression button the dialogue box looks the exactly the same except it says Hatch Text Expression at the top instead of  Label Expression.  This is why I assume they are the same, just in two different places.

I appreciate the help with this,

Thanks
0 Kudos