Search code examples
pythonspacydashboardplotly-dashnamed-entity-recognition

Is there a way to render spaCy's NER output on a Dash dashboard?


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!


Solution

  • 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.