Source code for graphbrain.notebook

from html import escape
from IPython.core.display import display, HTML
from graphbrain import *


SYMBOL_COLOR = '#404040'
NAMESPACE_COLOR = '#7F7F6F'
EDGE_COLORS = ['#a65628', '#377eb8', '#4daf4a', '#984ea3', '#ff7f00',
               '#ffff33', '#e41a1c', '#f781bf']


def _edge2html_r(edge, roots_only=True, formatting='indented', indent=False,
                 close=True, depth=0, color='#000', conn=False, close_html=''):
    assert(formatting in {'indented', 'compact', 'oneline'})

    # default value for close html string that is returned to caller
    ret_close_html = ''

    # font size
    if formatting == 'indented':
        fs = 14 - depth
    elif formatting == 'compact':
        fs = 12
    elif formatting == 'oneline':
        fs = 11
    font_size = 'font-size:{}pt;'.format(fs)

    # indent-dependent variables
    if indent:
        main_tag = 'div'
        margin = 'margin-left:20px;'
    else:
        main_tag = 'span'
        margin = ''

    # color
    color_html = 'color:{}'.format(color)

    # different renders depending on weather:
    # ... edge is an atom:
    if edge.is_atom():
        # connectors are rendered in bold
        bold_style = 'font-weight:bold;' if conn else ''

        # render atom root
        html = """
        <span style="{}{}">{}</span>
        """.format(bold_style,
                   color_html,
                   escape(str(edge.root()).strip())).strip()

        # render non-root part, if requested
        if not roots_only:
            escaped_codes = '/'.join(edge.parts()[1:])
            escaped_codes = escape(escaped_codes).strip()
            html = """
            {}<span style="color:{};font-size:8pt">/{}</span>
            """.format(html,
                       NAMESPACE_COLOR,
                       escaped_codes)

        # render atom
        html = """
        <{} style="{}{}">{}</{}>
        """.format(main_tag, margin, font_size, html, main_tag).strip()
    # ... edge is an edge
    else:
        et = edge.type()[0]
        arity = len(edge)
        contains_edges = any(not child.is_atom() for child in edge)
        color = EDGE_COLORS[depth % len(EDGE_COLORS)]
        color_html = 'color:{}'.format(color)

        # surroundings symbols depending on edge type
        if et == 'c':
            open_symbol = '['
            close_symbol = ']'
        elif et in {'s', 'x'}:
            open_symbol = '{'
            close_symbol = '}'
        else:
            open_symbol = '('
            close_symbol = ')'

        # render opening symbol
        html = """
        <span style="font-weight:bold;{}">{}</span>
        """.format(font_size, open_symbol).strip()

        close_html = '</{}>'.format(main_tag)

        # render edge children
        for i in range(arity):
            # first edge (connector)?
            if i == 0:
                child_indent = False
                child_color = color
                child_conn = True
                sep = ''
            # not connector
            else:
                # indent depending on formatting
                if formatting == 'indented':
                    child_indent = contains_edges if child.is_atom() else True
                elif formatting == 'compact':
                    # edges with only two items are rendered in one line
                    child_indent = arity > 2
                    if child_indent and child.is_atom() and not contains_edges:
                        child_indent = False
                elif formatting == 'oneline':
                    child_indent = False

                child_color = SYMBOL_COLOR
                child_conn = conn
                sep = ' '

            child = edge[i]
            if child.is_atom():
                child_html, _ = _edge2html_r(child,
                                             roots_only=roots_only,
                                             formatting=formatting,
                                             indent=child_indent,
                                             depth=depth,
                                             color=child_color,
                                             conn=child_conn)
            else:
                # Do not render closing html of children that are the last
                # edge in a hyperedge. Instead, let some higher-level edge
                # render it to avoid ugly multi-line staircases when closing
                # a sequence of edges.
                child_close = i < arity - 1

                child_html, child_cl_html = _edge2html_r(child,
                                                         roots_only=roots_only,
                                                         formatting=formatting,
                                                         indent=child_indent,
                                                         close=child_close,
                                                         depth=depth + 1,
                                                         conn=child_conn)
                # accumulate close_html of child
                close_html = '{}{}'.format(child_cl_html, close_html)
            html = '{}{}{}'.format(html, sep, child_html)

        # if closing html should not be rendered at the end o this edge
        # representation, then return it to the parent
        if not close:
            ret_close_html = close_html
            close_html = ''

        # render close symbol
        html = """
        {}<span style="{}">
            <span style="font-weight:bold;{}">{}</span>
        </span>
        """.format(html, color_html, font_size, close_symbol).strip()

        # render edge
        html = """
        <{} style="{}{}">{}{}
        """.format(main_tag, margin, color_html, html, close_html).strip()
    # ... edge is an atom

    return html, ret_close_html


def _edge2html(edge, roots_only=True, formatting='indented'):
    return _edge2html_r(edge, roots_only=roots_only, formatting=formatting)[0]


[docs]def show(edge, roots_only=True, style='indented'): """Displays a representation of the edge in the notebook. Keyword arguments: roots_only -- only show roots of atoms (default: True) style -- render style ('indented', 'compact' or 'oneline') (default: 'indented') """ html = _edge2html(edge, roots_only=roots_only, formatting=style) display(HTML(html))