Display hierarchical subterms of custom taxonomy based on depth

I love a good challenge!

The function here:

function get_post_categories_sorted ( $post_id ){

    $terms = wp_get_post_terms( $post_id, 'category' );

    $sorted_terms = [];

    foreach( $terms as $term ){

        $depth = count( get_ancestors( $term->term_id, 'category' ) );

        if( ! array_key_exists( $depth, $sorted_terms ) ){
            $sorted_terms[$depth] = [];
        }

        $sorted_terms[$depth][] = $term;

    }

    return $sorted_terms;

}

will give you an array with the structure in the following image. $sorted_terms[0] contains the top level terms, $sorted_terms[1] all the second level term and so on.

Sorted Terms for a given post

It would definitely be worth using a cache or the transients API to store the data as it could get expensive with a lot of terms to sort through as the call to get_ancestors involves a call back to the database for each level it has to traverse back up the chain.

EDIT

You can use this something like the following:

$sorted_terms = get_post_categories_sorted( get_the_ID() );

foreach( $sorted_terms as $key => $level_items ){

    $number = $key + 1;

    echo sprintf( '<p>Level %s Categories</p>', $number );

    echo '<ul>';

        foreach( $level_items as $term ){
            echo sprintf( '<li>%s</li>', $term->name );
        }

    echo '</ul>';

}

EDIT 2

To just use a specific level, you can simplify the code above like this:

$sorted_terms = get_post_categories_sorted( get_the_ID() );

echo '<p>Level 1 Categories</p>';

echo '<ul>';
    //Change the 0 here to whatever level you need, 
    //just remember is is 0 based; IE the first level is 0, 2nd level is 1 etc.
    //If the number doesn't exist, PHP will throw an undefined index error.

    foreach( $sorted_items[0] as $term ){ 
        echo sprintf( '<li>%s</li>', $term->name );
    }

echo '</ul>';