I have a point layer that reflects the speed limits and a line layer of the roads. The location of the speed sign indicates in which direction the speed limit applies.

How can I make linear event table on top of the road layer that reflects the speeds? So for each segment, return two speed attributes, one for each direction.

Speed/road layer

  • Can you clarify "The location of the speed sign indicates in which direction the speed limit applies"? Does this mean that if the point is on the right-hand side of the road (based on the road's directionality) the speed applies to the right lane? How close to the road is the point located? May 27, 2014 at 3:12
  • @StephenLead Yes, the sign point is located 1 to 5m from the line layer to indicate in which direction the speed applies
    – dassouki
    May 27, 2014 at 10:18
  • Are there any other attributes stored with the road signs? Sounds like you will need to snap them to the roads first then somehow transfer directionality of the road to the road signs then cut lines by the vertices and transfer attribute values from signs to each segment. Just an idea. Might help if you posted the data. May 27, 2014 at 12:59
  • @Jakub the only attribute I want from the road sign is "posted_speed". The sign layer does not have information on directionality
    – dassouki
    May 27, 2014 at 13:35
  • Do the sighs have any other attributes besides speed? I am asking because there could be something that can link the signs to the roads. Otherwise, what you want to do is not possible without manually snapping the signs onto the road segments, transferring attributes and splitting the road segments. (you could do this programatically but the distances are variable so full automation may not be possible) The result will not be a stand-alone table but rather an attribute table to which all of this information will be transferred. May 27, 2014 at 20:09

2 Answers 2


For linear route event layers, you need to create a table containing the ID of the route and the start and end m-values.

If your roads don't have m-values, you can create routes using the create routes tool.

The second step is to extract the m-values of your roads for each point, which can be done with locate feature along road. If I see well on your figure, the points are located on the same side of the road if they are for the same direction. This is great because you then have a positive or negative distance that tells you on which side you are.

The easiest way to the last step is in Microsoft Excel:

  • Sort your points by roadID and by sign of the distance to the route
  • Add a new column with the m-value of the next point (or the previous point, depending on the direction).
  • There will be one missing value at the end that should be filled with either 0 or the maximum m-value of the segment.

EDIT: after sorting, your table will look like this

 pointID RoadID mvalue dist speed
 15      2      25     1    80
 25      2      30     1    50
 87      2      45     12   70

You see that the points are sorted by m-values. The third column in my case would be the start of the event. the new event layer should have a from and a to field. So in my example it would look like :

pointID RoadID from to speed
15      2      25   30   80    
25      2      30   45   50    
87      2      45   max  70

in the other direction, it would be

pointID RoadID from to speed    
15      2      0    25   80    
25      2      25   30   50    
87      2      30   45   70

You can then make your event layer using the sign as an offset field to locate the speed limitation on the correct side of the routes.

  • So far this is working better than the other solution. Can you explain the excel part about adding previous and next points further please?
    – dassouki
    May 30, 2014 at 16:31

I don't have enough rep to comment, but my question is whether or not the roads are already in segments that correspond to the speed zones, i.e. would each segment generally have 1 speed associated with it per side, or more than one.

Regardless, here's my suggestion, though it is contingent on you having a license level that would allow a one-sided buffer (advanced/ArcInfo, I believe). A similar principal could be applied with basic tools, but would be more complex. Also, I expect this would take a while to run...

import arcpy
def TakeOutTrash(dataset):
    if arcpy.Exists(dataset):
roads = "path/to/roads" #make sure it's in a projected crs with meter units
buff_right = "path/to/new/buffer/feature/class1" #new gdb feature class
buff_left = "path/to/new/buffer/feature/class2" #new gdb feature class

Now you have buffers for each side of each road, that are 6 meters from the center line, which should cover all of the signs. You could do an easy select by location to make sure that this is the case, and if not, rerun the buffer operations with 1 or 2 extra meters.


final_dict = {}
buffers = [buff_right, buff_left]
for i, buffer in enumerate(buffers):
    rows1 = arcpy.SearchCursor(buffer)
    for row1 in rows1:
        final_dict[seg] = [[],[]]
        seg = str(row1.getValue("seg_num"))
        fl = arcpy.management.MakeFeatureLayer(buffer,"fl",'"seg_num" = ' + seg)
        rows2 = arcpy.SearchCursor(signs)
        for row2 in rows2:

So now you have a dictionary in this format:

"seg_num":[[list of speeds on the right],[list of speeds on the left]]

from which you can do whatever you like, for example:

for k,v in final_dict.iteritems():
    print "road segment {0}:".format(str(k))
    print "   speeds on right: {0}".format(", ".join(v[0]))
    print "   speeds on left: {0}".format(", ".join(v[1]))

Or just test for how many speeds there are on each side of the segment, or write it to fields in the original roads feature class, etc. Again, not sure if this could be a final solution with the data you have, but it could certainly work as a part of it. I could see it being used in conjunction with the snapping/splitting process described above.

To write to the roads layer, you could make two new fields, SPD_RIGHT and SPD_LEFT, and for now (unless you know for sure that there is only one speed per segment) make them text fields. Then:

urows = arcpy.UpdateCursor(roads)
for row in urows:
    seg = row.getValue("seg_num")
    right_speeds = ", ".join(final_dict[seg][0])
    left_speeds = ", ".join(final_dict[seg][1])

Of course, it's ideal to have only one speed per segment, but that goes back to the original question of how the segments are currently split.

  • Now that you have any points to comment; where does the speed layer come in place? Did I misunderstand your buffer command?
    – dassouki
    May 28, 2014 at 16:31
  • ok I added a little more to the answer. I hope I'm understanding what you're looking for.
    – mr.adam
    May 28, 2014 at 16:54
  • the segments and speeds might not be split the same way as the data is collected by two different entities; furthermore, a segment can have different speeds in either direction.
    – dassouki
    May 28, 2014 at 16:56
  • Ok, I'm thinking now that the better way to go about this is to first just do a right side buffer, 6m or something, and then select the signs that fall within that and extract them to a new point feature class. That way you could have a feature class for the right side signs and one for the left side signs.
    – mr.adam
    May 28, 2014 at 17:06
  • Jakub's answer in the comments is a good place to start in terms of defining good segments, and it could be supplemented with mine in order to link the speeds to the direction of the road.
    – mr.adam
    May 28, 2014 at 17:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.