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)