import html from htbuilder import H, HtmlElement, styles from htbuilder.units import unit # Only works in 3.7+: from htbuilder import div, span div = H.div span = H.span # Only works in 3.7+: from htbuilder.units import px, rem, em px = unit.px rem = unit.rem em = unit.em # Colors from the Streamlit palette. # These are red-70, orange-70, ..., violet-70, gray-70. PALETTE = [ "#ff4b4b", "#ffa421", "#ffe312", "#21c354", "#00d4b1", "#00c0f2", "#1c83e1", "#803df5", "#808495", ] OPACITIES = [ "33", "66", ] def annotation(body, label="", background=None, color=None, **style): """Build an HtmlElement span object with the given body and annotation label. The end result will look something like this: [body | label] Parameters ---------- body : string The string to put in the "body" part of the annotation. label : string The string to put in the "label" part of the annotation. background : string or None The color to use for the background "chip" containing this annotation. If None, will use a random color based on the label. color : string or None The color to use for the body and label text. If None, will use the document's default text color. style : dict Any CSS you want to apply to the containing "chip". This is useful for things like Examples -------- Produce a simple annotation with default colors: # >>> annotation("apple", "fruit") Produce an annotation with custom colors: # >>> annotation("apple", "fruit", background="#FF0", color="black") Produce an annotation with crazy CSS: # >>> annotation("apple", "fruit", background="#FF0", border="1px dashed red") """ color_style = {} if color: color_style['color'] = color if not background: label_sum = sum(ord(c) for c in label) background_color = PALETTE[label_sum % len(PALETTE)] background_opacity = OPACITIES[label_sum % len(OPACITIES)] background = background_color + background_opacity return ( span( style=styles( background=background, border_radius=rem(0.33), padding=(rem(0.125), rem(0.5)), overflow="hidden", **color_style, **style, ))( html.escape(body), span( style=styles( padding_left=rem(0.5), text_transform="uppercase", ))( span( style=styles( font_size=em(0.67), opacity=0.5, ))( html.escape(label), ), ), ) ) def get_annotated_html(*args): """Writes text with annotations into an HTML string. Parameters ---------- *args : see annotated_text() Returns ------- str An HTML string. """ out = div() for arg in args: if isinstance(arg, str): out(html.escape(arg)) elif isinstance(arg, HtmlElement): out(arg) elif isinstance(arg, tuple): out(annotation(*arg)) else: raise Exception("Bad input") return str(out)