Sort and label tags using Python and Dynamo

Sort and label tags using Python and Dynamo

Regardless of discipline, Archi, Structural or MEP, labeling elements in a Revit model has always an essential yet painful part of the documentation process. This post will walk you through how to perform a simple yet powerful sort and label process.

The columns in the layout below will be used for demonstration, the same concept could be extended to other types of elements as well (with a tweak of course).

Label using Dynamo

With a few simple nodes, we can write data to each element’s parameter (“Mark” parameter was used in this case, but you could use any instance parameter fitting to your case).

A simple tag can be created to annotate the corresponding mark on each column. After tagging all Columns yields the following. Now, the sequence of results are random which is rather meaningless, but we could perform some sorting to rearrange the labels.

Python sorted( ) method

There are ways to perform sorting in Dynamo by using nodes such as SortByKey or SortByFunction. But I found that rather inefficient and messy in comparison to Python, especially when performing nested sorting functions. After I discovered the sorted( ) method in Python, I rarely used nodes for sorting again. The sorted( ) method’s syntax and parameters are as follows.

Syntax

sorted( iterable, key= key, reverse= bool )

Parameters

ParameterDescription
Iterable (Required)The sequence to sort, list, dictionary, tuple etc.
Key (Optional)A Function to execute to decide sequencing. Default is None
Reverse (Optional)A Boolean type. True will sort descending, False will sort ascending. Default is False

Now, that we have a general understanding of sorted( ) method, let’s implement sorting of the columns by its X-coordinates, then by its Y-coordinates. The latter looks like this.

import clr
import math

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

columns = IN[0]

sortedElements = sorted (columns,key=lambda col:( math.ceil( col.GetLocation().X ), math.ceil( col.GetLocation().Y )))

OUT = sortedElements

That’s it! The results are as follows. If you are curious to understand a little more about the code, do read on.

Code walkthrough

There’s essentially only 1 line of code, but it could be rather intimidating to beginners. Don’t worry I was there not long ago, but I’ll try my best to walk you through.

The first parameter columns , which is an iterable, refers to the list of columns we want to sort.

The second parameter, which requires keys, is the tricky one. lambda col: allows us to access individual column’s properties in the iterable columns , using col as an identifier (You could define any identifier you want).

col.GetLocation( ).X retrieves the X-coordinate and col.GetLocation( ).Y retrieves the Y-coordinate. These anonymous functions are the most important part of the entire line of code, as it sorts the list by X then by Y. If you want to sort it by Y then by X, just simply reverse the order.

math.ceil helps negate the minor dimension inaccuracies present in Revit, which is inevitable even if you aligned the columns perfectly.

Now, with this understanding, you could nest even more sorting logic to achieve your objective by simply adding another key in the function. Perhaps sorting by level, or Z-coordinates or even by type depending on your case.

If you have such encounters or a big idea you wish to implement and require some help, I’d love to hear about it. Drop me a DM and let’s discuss! Else, as always, happy coding!

This Post Has 9 Comments

  1. Simone

    Hello, thank you very much for this, very enlightening.
    I would have one question. I am trying to use the reverse function, but with no luck.
    The version you post places the 1 on the bottom left (X-Y, reverse=False).
    I would be after the 1 on top left, with numbers growing on the X axis, hence I reckon I should use Y-X.. but not able to get there.
    Many thanks in advance
    Cheers.

    1. Han

      Dear Simone,

      I’m very glad that this post has helped you.

      For your case, you simply have to reverse the “Y” arrangement by including a negative sign, try this.
      sortedElements = sorted (columns,key=lambda ele:(math.ceil( ele.GetLocation().X ), -math.ceil( ele.GetLocation().Y )))

      Let me know how this turns out.

      regards,
      Han

    2. JunKang

      Agrees with Han, you cant use reverse in your particular case as it just inverts the sorted list as a whole

  2. Simone

    Dear Han,
    Apologise per the late reply and thanks for yours.
    I tried your script but it is not exactly what I was after.
    It sorts as shown below
    1 3 5
    2 4 6
    I would like
    1 2 3
    4 5 6

    Any Idea?
    Thanks

    1. Han

      Hello Simone,

      Seems like you need to sort by Y then by X to achieve that. Try this!
      sortedElements = sorted (columns,key=lambda ele:(math.ceil( ele.GetLocation().Y ), math.ceil( ele.GetLocation().X )))

      Play around with the negative signs and sequences of the keys, you’ll gain better clarity after!

      regards,
      Han

  3. Henrique

    How i can do with framings? can you explain?

    1. Han

      hello henrique,

      Concept is the same .
      1. Get Framing center XYZ
      2. Sort by its coordinates
      3. Label

  4. JJorge

    Gracias. Dios te Bendiga!

Leave a Reply