from io import StringIO
import logging
from typing import Optional
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import uploader.io
from uploader.models import Observable, Patient, SpectralData
from biospecdb.util import to_uuid
logger = logging.getLogger(__name__)
def fig_to_html(fig) -> str:
""" Convert a ploty figure to html. """
buffer = StringIO()
fig.write_html(buffer, auto_open=False, full_html=False)
buffer.seek(0)
graph = buffer.getvalue()
buffer.close()
return graph
def count_bool_observables(result: "QueryResult"): # noqa: F821
""" Count boolean observables present in data result. """
if len(result.data) < 1:
return
bool_observables = [d.name for d in Observable.objects.all() if d.value_class == "BOOL"]
df = pd.DataFrame(result.data, columns=result.header_strings)
cols = set(bool_observables) & set(df.columns)
if not cols:
return
df = df[list(cols)]
df.replace({"True": True, "False": False}, inplace=True)
return df.sum()
[docs]def get_pie_chart(result: "QueryResult") -> Optional[str]: # noqa: F821
""" Generate ploty pi chart of boolean Observation data present in data result. """
try:
counts = count_bool_observables(result)
if counts is None:
return
fig = px.pie(counts, values=counts.values, names=counts.index, title=f"SQL query: '{result.sql}'")
return fig_to_html(fig)
except Exception as error:
logger.exception(f"Exception raised from `get_pie_chart`: {error}")
return
[docs]def get_line_chart(result: "QueryResult") -> Optional[str]: # noqa: F821
""" Generate ploty line chart of spectral data present in data result. """
if len(result.data) < 1:
return
try:
df = pd.DataFrame(result.data, columns=result.header_strings)
if Patient.patient_id.field.name not in df.columns or SpectralData.data.field.name not in df.columns:
return
df = df[[Patient.patient_id.field.name, SpectralData.data.field.name]]
fig = go.Figure()
fig.update_layout(xaxis_title="Wavelength",
yaxis_title="Intensity",
title=f"Spectral Data for SQL query: '{result.sql}'")
for row in df.itertuples():
spectral_data = uploader.io.read_spectral_data(row.data)
assert to_uuid(spectral_data.patient_id) == to_uuid(row.patient_id)
fig.add_scatter(x=spectral_data.wavelength,
y=spectral_data.intensity,
name=str(row.patient_id))
return fig_to_html(fig)
except Exception as error:
logger.error(f"Exception raised from `get_line_chart`: {error}")
return