Get all generic annotations in a view

Basically I want all generic annotations form a (drafting) view.

Found these and strung them together- but not seeing why this isn’t returning generic annotations. Sample file and DYN attached.

Lambda is some kind of magic I don’t fully grasp yet. and the system predicate- heck this whole line is a bit of a mystery but I adapted it to get all generic annotations in the project.:

filterAnnot = System.Predicate[System.Object](lambda x : x.Family.FamilyCategory.Name ==  "Generic Annotations") 

Here is my little function:

import clr
import System

import System.Collections.Generic
from System.Collections.Generic import List

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument

def GetDraftingViewID(strName):
    ##https://forums.autodesk.com/t5/revit-api-forum/view3d-collector/td-p/5277451
    DraftingViewsList = FilteredElementCollector(doc).OfClass(ViewDrafting).ToElements()
    ##DraftingViewTemplates = [v.Id for v in DraftingViewsList if v.IsTemplate == True]
    DraftingViewsList = [v for v in DraftingViewsList if v.IsTemplate == False and v.Name == strName]
    #DraftingViewsList = [v for v in DraftingViewsList if v.Name == strName]
    return DraftingViewsList[0]
    
viewDraft = GetDraftingViewID("bar")

##https://forum.dynamobim.com/t/how-to-get-all-annotation-elements-in-active-view-section-marks-elevation-tags-etc/18716/4
filterAnnot = System.Predicate[System.Object](lambda x : x.Family.FamilyCategory.Name ==  "Generic Annotations") 
symbAnnot = List[Element](FilteredElementCollector(doc, viewDraft.Id).OfClass(FamilySymbol).ToElements()).FindAll(filterAnnot)

OUT = symbAnnot

DYN:
Sample-Generic-Annotation-Design-Bulletin-(GenericAnnos).dyn (4.9 KB)
Rvt:
Sample-Generic-Annotation-Design-Bulletin.rvt (472 KB)

Partly based on:

and the Lambda predicate from this post with @Nick_Boyts and @c.poupin

Try this using a category filter instead of the FindAll.

import clr
import System

import System.Collections.Generic
from System.Collections.Generic import List

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument

def GetDraftingViewID(strName):
    ##https://forums.autodesk.com/t5/revit-api-forum/view3d-collector/td-p/5277451
    DraftingViewsList = FilteredElementCollector(doc).OfClass(ViewDrafting).ToElements()
    ##DraftingViewTemplates = [v.Id for v in DraftingViewsList if v.IsTemplate == True]
    DraftingViewsList = [v for v in DraftingViewsList if v.IsTemplate == False and v.Name == strName]
    #DraftingViewsList = [v for v in DraftingViewsList if v.Name == strName]
    return DraftingViewsList[0]
    
viewDraft = GetDraftingViewID("bar")

OUT = [x.Name for x in FilteredElementCollector(doc,viewDraft.Id).OfCategory(BuiltInCategory.OST_GenericAnnotation).WhereElementIsNotElementType()]

1 Like

FYI, the reason why it wasn’t working to start with is that you can’t use the FEC to get Types in a View because the Symbol doesn’t exist IN a view, but the instance of that symbol does.

So, this code is a small tweak to the original that gets instances, then gets and checks their Type.

import clr
import System

import System.Collections.Generic
from System.Collections.Generic import List

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument

def GetDraftingViewID(strName):
    ##https://forums.autodesk.com/t5/revit-api-forum/view3d-collector/td-p/5277451
    DraftingViewsList = FilteredElementCollector(doc).OfClass(ViewDrafting).ToElements()
    ##DraftingViewTemplates = [v.Id for v in DraftingViewsList if v.IsTemplate == True]
    DraftingViewsList = [v for v in DraftingViewsList if v.IsTemplate == False and v.Name == strName]
    #DraftingViewsList = [v for v in DraftingViewsList if v.Name == strName]
    return DraftingViewsList[0]
    
viewDraft = GetDraftingViewID("bar")

##https://forum.dynamobim.com/t/how-to-get-all-annotation-elements-in-active-view-section-marks-elevation-tags-etc/18716/4
filterAnnot = System.Predicate[System.Object](lambda x : doc.GetElement(x.GetTypeId()).Family.FamilyCategory.Name ==  "Generic Annotations") 
symbAnnot = List[Element](FilteredElementCollector(doc, viewDraft.Id).OfClass(FamilyInstance).ToElements()).FindAll(filterAnnot)

OUT = symbAnnot
1 Like

Thanks @SeanP for explaining : )
Still trying to re-wrap my head around Python after being out of it for 5 years.

1 Like

Yes, there are several different way to do something, and then you throw the transition from IP2 and CP3 in the mix and it gets even more convoluted. And as always, the Revit API doesn’t always make sense to me either!

Good luck!

@SeanP Simple question: Why is the […] required?
for the syntax in CPython3:

OUT = [x.Name for x in FilteredElementCollector(doc,viewDraft.Id).OfCategory(BuiltInCategory.OST_GenericAnnotation).WhereElementIsNotElementType()]

How is python treating the brackets? […] Creates a list is a list (or is it now a collection?) and is it forcing the evaluation to place it in the list?

Where the […] enclose the :

  • x.Name = VARIABLE_Modified_TO_RETURN
    *Iterate syntax = for
  • x =VARIABLE_TO_ITERATE over the list of the
  • FEC(Filtered element collector)

Brackets in this case is starting list comprehension. Syntax is as follows:

[ actionOn(item) for item in largerList if filteronItem ]

It’s basically a pythonic way to do a for loop without having to add all the extra lines.

We covered this a bit in in the Snakes on a (Dynamo) Plane community conversation last fall.

2 Likes

Thanks Jacob! Wasn’t sure.

Finally got my Visual Studio editing Python with the stubs installed! Details here:

And here on my local blog:

1 Like

Hello,
there are several ways to filter a FilteredElementCollector
some examples here

1 Like

Erik Frits shared a nice document on Linkedin:

2 Likes

There are so many great resources out there. Thanks for sharing @jw.vanasselt and @c.poupin. Here is another by Jeremy!

2 Likes

@jw.vanasselt No content though? e-book publish date TBD?

I don’t know, I see a post sometime :slight_smile:

@jacob.small the List Comprehension - very cool!

Found a good resource and examples in PY here:
https://web.archive.org/web/20180309053826/http://www.secnetix.de/olli/Python/list_comprehensions.hawk

Python: List Comprehensions

Note: Lines beginning with “>>>” and “...” indicate input to Python (these are the default prompts of the interactive interpreter). Everything else is output from Python.

Python supports a concept called “list comprehensions”. It can be used to construct lists in a very natural, easy way, like a mathematician is used to do.

The following are common ways to describe lists (or sets, or tuples, or vectors) in mathematics.

S = {x² : x in {0 ... 9}}
V = (1, 2, 4, 8, ..., 2¹²)
M = {x | x in S and x even}

You probably know things like the above from mathematics lessons at school. In Python, you can write these expression almost exactly like a mathematician would do, without having to remember any special cryptic syntax.

This is how you do the above in Python:

>>> ``S = [x**2 for x in range(10)]
>>> ``V = [2**i for i in range(13)]
>>> ``M = [x for x in S if x % 2 == 0]
>>> ``` >>> ``print S; print V; print M`

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096]
[0, 4, 16, 36, 64]

I’m sure you want to see a more complicated example. :slight_smile: The following is yet another way to compute prime numbers. The interesting thing is that we first build a list of non-prime numbers, using a single list comprehension, then use another list comprehension to get the “inverse” of the list, which are prime numbers.

>>> ``noprimes = [j for i in range(2, 8) for j in range(i*2, 50, i)]
>>> ``primes = [x for x in range(2, 50) if x not in noprimes]
>>> ``print primes

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

NB: You can nest list comprehensions inside of each other, so you could write the above example with a single statement (without the need for the temporary variable “noprimes”). However, such lines tend to get long and less readable, so this is not recommended.

Of course, list comprehensions don’t only work for numbers. Lists can contain any type of elements, including strings, nested lists and functions. You can even mix different types within a list.

The following works on a list of strings and produces a list of lists. Each of the sublists contains two strings and an integer.

>>> ``words = 'The quick brown fox jumps over the lazy dog'.split()
>>> ``print words

['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog']

>>> ``` >>> stuff = [[w.upper(), w.lower(), len(w)] for w in words]` `>>> for i in stuff: … `` print i … ```

['THE', 'the', 3]
['QUICK', 'quick', 5]
['BROWN', 'brown', 5]
['FOX', 'fox', 3]
['JUMPS', 'jumps', 5]
['OVER', 'over', 4]
['THE', 'the', 3]
['LAZY', 'lazy', 4]
['DOG', 'dog', 3]

>>> ``` >>> stuff = map(lambda w: [w.upper(), w.lower(), len(w)], words)` `>>> for i in stuff: … `` print i … ```

['THE', 'the', 3]
['QUICK', 'quick', 5]
['BROWN', 'brown', 5]
['FOX', 'fox', 3]
['JUMPS', 'jumps', 5]
['OVER', 'over', 4]
['THE', 'the', 3]
['LAZY', 'lazy', 4]
['DOG', 'dog', 3]

The above example also demonstrates that you can do exactly the same thing with map() and a lambda function. However, there are cases when you cannot use map() and have to use a list comprehension instead, or vice versa. When you can use both, then it is often preferable to use a list comprehension, because this is more efficient and easier to read, most of the time.

You cannot use list comprehensions when the construction rule is too complicated to be expressed with “for” and “if” statements, or if the construction rule can change dynamically at runtime. In this case, you better use map() and / or filter() with an appropriate function. Of course, you can combine that with list comprehensions.