def tabulate(
    obj,
    v_level_indexes=None,
    h_level_indexes=None,
    v_level_visibility=None,
    h_level_visibility=None,
    v_level_sort_keys=None,
    h_level_sort_keys=None,
    v_level_titles=None,
    h_level_titles=None,
    empty="",
):
    level_keys = breadth_first(obj)
    v_level_indexes, h_level_indexes = validate_level_indexes(
        len(level_keys), v_level_indexes, h_level_indexes
    )
    if v_level_visibility is None:
        v_level_visibility = [True] * len(v_level_indexes)
    if h_level_visibility is None:
        h_level_visibility = [True] * len(h_level_indexes)
    table, v_key_tuples, h_key_tuples = tabulate_body(
        obj, level_keys, v_level_indexes, h_level_indexes, v_level_sort_keys, h_level_sort_keys
    )
    table, v_key_tuples = strip_missing_rows(table, v_key_tuples)
    table, h_key_tuples = strip_missing_columns(table, h_key_tuples)
    v_key_tuples = strip_hidden(v_key_tuples, v_level_visibility)
    h_key_tuples = strip_hidden(h_key_tuples, h_level_visibility)
    return assemble_table(
        table, v_key_tuples, h_key_tuples, v_level_titles, h_level_titles, empty=empty
    )