This can be done easiest by bfsing through each level, since it goes level by level for you automatically. This keeps everything in order.
class Solution:
def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
levels = defaultdict(list)
q = deque([(root, 0)])
start = 0
end = 0
while q:
node, col = q.popleft()
if not node:
continue
levels[col].append(node.val)
start = min(start, col)
end = max(end, col)
q.append((node.left, col - 1))
q.append((node.right, col + 1))
return [levels[n] for n in range(start, end + 1)]