14.3.225. crate_anon/crateweb/specimen_archives/tree/snippets/single_nlp_page.mako

## -*- coding: utf-8 -*-
<%doc>

crate_anon/crateweb/specimen_archives/tree/snippets/single_nlp_page.mako

===============================================================================

    Copyright (C) 2015, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CRATE.

    CRATE is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CRATE is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CRATE. If not, see <https://www.gnu.org/licenses/>.

===============================================================================

Query parameters (from URL):

    tablename:
        str: table to query
    description:
        str: description of the NLP tool
    column_csv:
        str: CSV of column names, other than the ever-present ones

</%doc>

<%inherit file="../inherit/plotting.mako"/>

<%!
import logging
from typing import Iterable

from cardinal_pythonlib.dbfunc import genrows, get_fieldnames_from_cursor

from crate_anon.crateweb.research.archive_func import (
    delimit_sql_identifier,
    json_compact,
)
from crate_anon.crateweb.research.views import (
    FN_SRCDB,
    FN_SRCTABLE,
    FN_SRCFIELD,
    FN_SRCPKFIELD,
    FN_SRCPKVAL,
    FN_SRCPKSTR,
)

log = logging.getLogger(__name__)

SILENT_COLS = [
    FN_SRCDB,
    FN_SRCTABLE,
    FN_SRCFIELD,
    FN_SRCPKFIELD,
    FN_SRCPKVAL,
    FN_SRCPKSTR,
]  # hard-coded special order; MUST MATCH results_table_nlp.mako
STARTCOLS = [
    "_srcdatetimeval AS 'Source time'",
]
ENDCOLS = [
    "_when_fetched_utc AS 'NLP time'",
] + SILENT_COLS
DATECOLNAME = "_srcdatetimeval"


def nlp_sql(tablename: str, columns: Iterable[str]) -> str:
    tablename = delimit_sql_identifier(tablename)
    final_columns = (
        STARTCOLS +
        [delimit_sql_identifier(c) for c in columns] +
        ENDCOLS
    )
    colstr = ", ".join(final_columns)
    return (
        f"SELECT {colstr} "
        f"FROM {tablename} "
        f"WHERE brcid = ? "
        f"ORDER BY _srcdatetimeval ASC"
    )

%>

<%

tablename = query_params["tablename"]
description = query_params["description"]
column_csv = query_params["column_csv"]
n_graph_columns = int(query_params["n_graph_columns"])

columns = column_csv.split(",")
cursor = execute(nlp_sql(tablename, columns), [patient_id])

nrows = cursor.rowcount
datecolidx = 0

if n_graph_columns > 0 and datecolidx is not None and nrows > 0:
    do_chart = True
    data = []
    for idx_in_columns in range(n_graph_columns):
        idx_in_query = idx_in_columns + len(STARTCOLS)
        d_v = [(row[datecolidx].isoformat(),
                row[idx_in_query]) for row in cursor]
        dates, values = zip(*d_v)
        data.append({
            "type": "scatter",
            "x": dates,
            "y": values,
            "name": columns[idx_in_columns],
            "mode": "lines+markers",
            "showlegend": True,
        })
    # log.critical(f"data: {data!r}")
    layout = {
        "title": description
    }
    filename = f"{patient_id}_{tablename}"
else:
    do_chart = False

%>

<div class="pad">
    <h1>${description}</h1>

    <p>Natural Language Processing (NLP) results.
        “Source time” is when the record relates to.
        “NLP time” is when the NLP software processed this data.
        <b>NLP is imperfect:</b> it may miss mentions (false negatives), or
        misinterpret something irrelevant/incorrect (false positives).</p>

    <%include file="results_table_nlp.mako" args="cursor=cursor"/>
</div>

%if do_chart:

    <div id="chart"></div>

    <script>

        // ====================================================================
        // Graph
        // ====================================================================

        let chart = document.getElementById("chart");
        const data = ${json_compact(data)};
        const layout = ${json_compact(layout)};

        plotly_config["toImageButtonOptions"]["filename"] = ${json_compact(filename)};
        console.log(plotly_config);

        Plotly.plot(chart, data, layout, plotly_config);

    </script>

%endif