Get viewport from view

Python is a tweaked version of : View.Viewport - Get Viewport from View - #6 by gerhard.p

But I’m getting empty lists. How do I get the viewport of these views?

Looks like this views are not placed on a sheet, or they are view templates?

If you are sure they are placed on a sheet, select the view on the sheet with selectmodelelement to get the viewport and it’s id to compare it with all viewports ans see why there is no match.

I am creating views and placing them on sheets. I want to alter the viewtype in the same script, not a new script.

These are views, not view templates.

This is following on from this thread:

I’ve realised that I was creating a viewport in my script already…

But question still stands out of interest, how do I find a viewport from a view?

A pretty fast way might be to build a dictionary of viewports grouped against their ViewId as a key, then ask that dictionary to retrieve the viewports at the key of its Id. I got it to run pretty quickly on a large set of views (dictionaries scale very well vs lists when they suit a task). Function apply helps manage out any nulls.

The nice part here is it can also retrieve groups of viewports for views which can be more than once such as legends.

Get view viewports.dyn (24.6 KB)

3 Likes

This looks like a good method. :slight_smile:
Thanks.

btw does this annoy anyone else?
image

2 Likes

Ahahaha yes it annoyed me doing it for sure. It’s such a common outcome when constructing dictionaries in Dynamo as well, GroupByKey is its best friend.

If you want to do this in Python there are various ways listed in this thread:

1 Like

Dunno why but I’m not that fond of dictionaries. I know they’re super useful, I do sometimes use them… but meh, I prefer other methods.

Bit like I hate design options in Revit I suppose :smiley:

I wasn’t fond of them until lately. I’ve found they sometimes save a heck of a lot of time, they really are that much quicker than lists when you’re dealing with very large sets of data in Python. I had a play with it and got it to work in Python also. Might be some shortcuts I’ve missed but still running quite quickly. I’ve hashed all my keys into strings here vs Ids, not sure if Ids can be valid keys - I assume going to from Id to string is very quick so likely low risk on speed there.

My understanding is dictionaries act like hash tables so you can look them up very quickly if the keys can be out of order. Lists have to be iterated across in order to reach the items you’re searching for, so lists slow relative to their size whilst dictionaries don’t (O(1) vs O(n) in computer science terms, with O1 being same speed regardless of item count - the holy speed grail). Learning this alone in cs50 was enough to motivate me to use them more often.

# Made by Gavin Crump
# Free for use
# BIM Guru, www.bimguru.com.au

# Boilerplate text
import clr

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

clr.AddReference("RevitAPI")
import Autodesk 
from Autodesk.Revit.DB import FilteredElementCollector, Viewport, ElementId

# Current doc/app/ui
doc = DocumentManager.Instance.CurrentDBDocument

# Define list/unwrap list functions
def uwlist(input):
    result = input if isinstance(input, list) else [input]
    return UnwrapElement(result)

# Get viewports
viewports = FilteredElementCollector(doc).OfClass(Viewport).ToElements()

# Make first dictionary
dict1 = {}

for vp in viewports:
    dict1[vp.Id.ToString()] = vp.ViewId.ToString()

# Swap dictionary to lists by key
dict2 = {}

for key, value in sorted(dict1.items()):
    dict2.setdefault(value, []).append(key)

dict2Keys = dict2.keys()

# Return views for keys
views = uwlist(IN[0])

viewportsList = []

for v in views:
    try:
        checkKey = v.Id.ToString()
    except:
        checkKey = "N/A"
    if checkKey in dict2Keys:
        vpIds = dict2[checkKey]
        viewportsList.append([doc.GetElement(ElementId.Parse(vpId)) for vpId in vpIds])
    else:
        viewportsList.append([])

# Preparing output to Dynamo
OUT = viewportsList
3 Likes

Could it have been that those views arent placed on a sheet so don’t have a corresponding viewport?

Not in this case.

Without seeing a graph it´s just guessing but the problem might be that you pass “old” views to view.viewport node. The node never fails if you use it right.

See this upper branch that for sure wont give a result for getting the viewport because it is the fastest branch in the graph and wont reload after the views are placed on a sheet.

Show your graph and a tuneup-run then we will see what is happening when and why it fails.

They’re views that have just been created by the script and placed on sheets…

I was just using the new views… but realised I’d obviously created viewports so I just used that (as per image below).

But… what I was doing originally was trying to use one of the lists of views from one of the red arrows and find the viewport from that…

Even with a wait node it wasn’t working but I guess Dynamo probably made the view and changed the parameters before creating the viewport?

Yep thats the problem, you used the view before the viewport was created.
Use tune up and you will see the parameter changes and the view.viewport happen way much before the viewport creation. So when maipulating views like that you best always stay in the same branch to always have the most recent view/viewport.

Because the python double loop is awful to look at. here is the version with a dict.

https://www.revitpythondocs.com/?search=Viewport%20From%20View

import clr
clr.AddReference("RevitNodes")
clr.AddReference("RevitServices")

import Revit
clr.ImportExtensions(Revit.Elements)

from RevitServices.Persistence import DocumentManager
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory

doc = DocumentManager.Instance.CurrentDBDocument

viewport_dict = {vp.ViewId: vp for vp in FilteredElementCollector(doc)
                 .OfCategory(BuiltInCategory.OST_Viewports)
                 .WhereElementIsNotElementType()
                 .ToElements()}

views = UnwrapElement(IN[0]) if isinstance(IN[0], list) else [UnwrapElement(IN[0])]

matching_viewports = [viewport_dict.get(view.Id) for view in views if view.Id in viewport_dict]

OUT = matching_viewports
3 Likes

I did put in a bunch of wait nodes (but probably in the wrong place).

Create the views, wait to place them on sheets, end the transaction and start a new one, then get the view port.

The document needs to regenerate before things are there. :slight_smile:

Wouldnt that yield duplicate keys if legends are involved? That was my main reason for pivoting from viewport id as key to grouped in my example before. Good to know you can dict from a list though, handy!