def _get_jupyter_frontend():
    """
    Given that hypertools has been imported into a Jupyter notebook,
    determine whether that notebook is being run through the "classic"
    Jupyter notebook interface (i.e., notebook < 7.0) or the newer
    JupyterLab interface (i.e., JupyterLab or notebook >= 7.0).

    Returns
    -------
    {'classic', 'lab'}
        The Jupyter frontend used by the importing notebook.

    Notes
    -----
    Adapted from `davos.core.config._get_jupyter_interface()`
    (https://github.com/ContextLab/davos/blob/0608a40/davos/core/config.py#L565).
    Structured to prioritize short-circuiting as early as possible to
    minimize runtime, since this function runs on import (in notebooks).
    """
    # first try to inspect the shell command used to start the jupyter
    # notebook/lab server from the parent process (i.e., `jupyter
    # notebook ...` or `jupyter lab ...`)
    shell_cmd = f'ps -o command= -p {os.getppid()}'
    try:
        parent_proc_cmd = check_output(shlex.split(shell_cmd),
                                       encoding=getpreferredencoding())
    except (FileNotFoundError, CalledProcessError):
        # this could fail if the notebook is being run from something
        # like an IDE that manages more complex processes or doesn't
        # launch a typical jupyter server
        server_type = None
    else:
        # when launched normally from the command line, the 2nd item in
        # the list should be the notebook/lab executable, but safer to
        # check more generally in case the user has something unusual
        # like a custom script they called to launch the server
        for item in parent_proc_cmd.split():
            if item.endswith('lab'):
                # if the server was launched with `jupyter lab`, we know
                # we're using the JupyterLab frontend
                return 'lab'
            elif item.endswith('notebook'):
                # if the server was launched with `jupyter notebook`, we
                # need to check the version below to determine the
                # frontend
                server_type = 'notebook'
                break
        else:
            # if we can't identify the server type (or `ps` command
            # fails; see `except` block above), we'll need to use some
            # additional logic below to determine the frontend
            server_type = None

    # server was not launched with `jupyter lab`, so check installed
    # jupyter notebook version to determine the frontend.
    #
    # Run shell commands via `IPython.utils.process.system()` instead of
    # `subprocess.run()`, `os.system()`, etc. to ensure they're executed
    # in the notebook *server* environment, which could be different
    # from the notebook *kernel* environment.
    #
    # `IPython.utils.process.system()` prints output to stdout, so
    # temporarily capture it in a text buffer to get the version info.
    import IPython    # guaranteed to be installed at this point

    with redirect_stdout(StringIO()) as notebook_version_stdout:
        retcode = IPython.utils.process.system('jupyter notebook --version')
    if retcode == 0:
        # base notebook app is installed in the server environment
        notebook_version_stdout = notebook_version_stdout.getvalue().strip()
        notebook_version_tup = tuple(map(int, notebook_version_stdout.split('.')))
        if notebook_version_tup >= (7, 0):
            # notebook >= 7.0 uses the JupyterLab frontend, so no matter
            # how the notebook and/or jupyter server were launched, or
            # whether or not JupyterLab itself is installed, we can
            # assume that's the frontend being used
            return 'lab'
        elif server_type == 'notebook':
            # notebook < 7.0 uses the classic notebook frontend, so if
            # the server was launched by invoking `jupyter notebook`
            # directly, we know that's what we're using
            return 'classic'
    else:
        # base notebook app is not installed in the server environment.
        notebook_version_tup = None

    # two remaining possibilities:
    #   1. the base notebook app is not installed.
    #   2. the base notebook app *is* installed, and the installed
    #      version is an older one that uses the classic frontend, but
    #      the notebook app wasn't directly called to launch the jupyter
    #      server.
    # Since we already know JupyterLab wasn't invoked directly either,
    # this means the notebook is probably being run through some IDE (or
    # maybe an odd Wasm notebook frontend) that either doesn't use a
    # jupyter server, or internally uses a newer version of JupyterLab
    # that doesn't depend on the base notebook app. In either case,
    # the frontend being used is ambiguous, but our "best guess"
    # depends on whether or not JupyterLab is installed.
    with redirect_stdout(StringIO()) as lab_version_stdout:
        retcode = IPython.utils.process.system('jupyter lab --version')
    if retcode == 0:
        # JupyterLab is installed in the server environment, possibly
        # alongside an older version of the base notebook app. Notebook
        # could be running in an IDE or atypical web app. Either way,
        # JupyterLab frontend is more likely being used.
        return 'lab'
    elif notebook_version_tup is not None:
        # JupyterLab is not installed, but an older version of the base
        # notebook app is, so assume the classic notebook frontend
        return 'classic'
    # neither JupyterLab nor the base notebook app are installed. The
    # notebook is most likely being run through some app that doesn't
    # require a jupyter server. Fall back default assumption/old
    # behavior of assuming (probably mocked) classic notebook frontend.
    return 'classic'

    Given that hypertools has been imported into a Jupyter notebook,
    determine whether that notebook is being run through the "classic"
    Jupyter notebook interface (i.e., notebook < 7.0) or the newer
    JupyterLab interface (i.e., JupyterLab or notebook >= 7.0).

    Returns
    -------
    {'classic', 'lab'}
        The Jupyter frontend used by the importing notebook.

    Notes
    -----
    Adapted from `davos.core.config._get_jupyter_interface()`
    (https://github.com/ContextLab/davos/blob/0608a40/davos/core/config.py#L565).
    Structured to prioritize short-circuiting as early as possible to
    minimize runtime, since this function runs on import (in notebooks).
    
hypertools/plot/backend.py