3

I am trying to incorporate spaCy's NER pre-trained model into my Dash Dashboard. I know Dash currently does not have the ability to render raw html so I am looking for a solution. I have search the online extensively without finding a solution. Currently, I have a dashboard that looks like this:

[Dashboard] enter image description here

Where I would like the SpaCy's NER output to show underneath if possible. As an example please see the image below:

[NER Example Output] enter image description here

If anyone has managed to find a solution that works with Dash, please let me know. If it isn't possible then it isn't the end of the world. I know it can be done in Flask albeit it is harder to code in HTML!

Many thanks!

Cellan
  • 63
  • 9

1 Answers1

3

it's not possible to render it in one line through displacy. However, you should be able to abstract the html through python functions and manually render the results. Here's an example app:

import dash
import dash_html_components as html

import spacy
from spacy.displacy.render import DEFAULT_LABEL_COLORS


# Initialize the application
app = dash.Dash(__name__)


def entname(name):
    return html.Span(name, style={
        "font-size": "0.8em",
        "font-weight": "bold",
        "line-height": "1",
        "border-radius": "0.35em",
        "text-transform": "uppercase",
        "vertical-align": "middle",
        "margin-left": "0.5rem"
    })


def entbox(children, color):
    return html.Mark(children, style={
        "background": color,
        "padding": "0.45em 0.6em",
        "margin": "0 0.25em",
        "line-height": "1",
        "border-radius": "0.35em",
    })


def entity(children, name):
    if type(children) is str:
        children = [children]

    children.append(entname(name))
    color = DEFAULT_LABEL_COLORS[name]
    return entbox(children, color)


def render(doc):
    children = []
    last_idx = 0
    for ent in doc.ents:
        children.append(doc.text[last_idx:ent.start_char])
        children.append(
            entity(doc.text[ent.start_char:ent.end_char], ent.label_))
        last_idx = ent.end_char
    children.append(doc.text[last_idx:])
    return children


text = "When Sebastian Thrun started working on self-driving cars at Google in 2007, few people outside of the company took him seriously."
nlp = spacy.load("en_core_web_sm")
doc = nlp(text)
print("Entities:", doc.ents)

# define de app
app.layout = html.Div(
    children=render(doc)
)

# Run the app
if __name__ == "__main__":
    app.run_server(debug=True)

This produces the following result: enter image description here

In the example above, the entname and entbox functions will respectively generate an html.Span and html.Mark with the style copied from the output html in displacy. Then, the function entity abstracts the previous two functions to easily generate an entity box. Finally, the render function will take spacy's Doc object and convert it into a list of Dash html components, which can be used inside the Dash layout.

xhluca
  • 868
  • 5
  • 22
  • 1
    Hi, thanks for your reply. It works great! May I ask how do you know how to do this? I am quite new to Dash and I have no experience in HTML. I was just wondering if you know of any good resources I can refer to? – Cellan Mar 23 '21 at 17:38
  • You are welcome @cellan! The best way to get started with Dash is through the docs: https://dash.plotly.com. Specifically, the "layout" chapter covers the basics of styling in Dash. Once you learn how Dash interacts with HTML through the `html` components, and with `CSS` through the `style` argument, you can start translating HTML/CSS into Dash components; which is exactly what I did here. In this specific case, I was able to find the style with a simple inspect element. – xhluca Mar 23 '21 at 20:49