Interactive Web application with Dash

Authors: Prof. med. Thomas Ganslandt Thomas.Ganslandt@medma.uni-heidelberg.de
and Kim Hee HeeEun.Kim@medma.uni-heidelberg.de
Heinrich-Lanz-Center for Digital Health (HLZ) of the Medical Faculty Mannheim
Heidelberg University

This tutorial is prepared for TMF summer school on 03.07.2019

Prerequisite: MIMIC-III files locally

You should place the following MIMIC-III data files in the data/ subfolder:

  • D_LABITEMS.csv
  • LABEVENTS.csv
  • PRESCRIPTIONS.csv

Dash

  • https://dash.plot.ly/gallery
  • Dash is a Python framework for creating data-driven web applications
  • Dash apps are written on top of Flask, Plotly, and React
    • Flask is a Python web framework
    • Plotly is specifically a charting library built on top of D3.js
    • React is a JavaScript library for building user interfaces maintained by Facebook and a community

Case Study 2: Labitems Trend Visualization

Trend analysis is the widespread practice of collecting information and attempting to spot a pattern. This case study will illustrate a drug reaction of a sepsis patient. This case study tracks the biomarker and prescription history of patient 41976. It visualizes the relation between two key biomarkers of sepsis (White Blood Cells and Neutrophils) and

  • '41976' patient is choosen for this case study because this patient contains most and interesting records among other sepsis patients '10006', '10013', '10036', '10056', '40601'

Import Python pakages (1/6)


In [ ]:
# # Dash packages installation
# !conda install -c conda-forge dash-renderer -y
# !conda install -c conda-forge dash -y
# !conda install -c conda-forge dash-html-components -y
# !conda install -c conda-forge dash-core-components -y
# !conda install -c conda-forge plotly -y

In [ ]:
import dash
import dash_core_components as dcc
import dash_html_components as html
import flask
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import numpy as np
import pandas as pd
pd.set_option('display.max_columns', 999)
import pandas.io.sql as psql

Data collection (2/6)

  • Query d_labitems table (Dictionary table for mapping)
  • Query labevents table (History of the labitem order)
  • Join two tables
  • Query prescriptions table (History of the prscription order)

In [ ]:
d_lab = pd.read_csv("data/D_LABITEMS.csv")
d_lab.columns = map(str.lower, d_lab.columns)
d_lab.drop(columns = ['row_id'], inplace = True)

lab = pd.read_csv("data/LABEVENTS.csv")
lab.columns = map(str.lower, lab.columns)
lab = lab[lab['subject_id'] == 41976]
lab.drop(columns = ['row_id'], inplace = True)

lab = pd.merge(d_lab, lab, on = 'itemid', how = 'inner')
print(lab.columns)
lab[['subject_id', 'hadm_id', 'itemid', 'label', 'value']].head()

In [ ]:
presc = pd.read_csv("data/PRESCRIPTIONS.csv")
presc.columns = map(str.lower, presc.columns)
presc = presc[presc['subject_id'] == 41976]
presc.drop(columns = ['row_id'], inplace = True)
print(presc.columns)
presc[['subject_id', 'hadm_id', 'icustay_id', 'drug']].head()

Data preparation for labevents table (3/6)

  • Convert data type to datetime and extract only year value

In [ ]:
lab['charttime'] = pd.to_datetime(lab['charttime'], errors = 'coerce')
lab.sort_values(by='charttime', inplace=True)
lab.set_index('charttime', inplace = True)
lab.head(1)

Data preparation for prescriptions table (4/6)

  • Filter conditions:
    • unit: 'mg'
    • antibiotics medicines: ('Vancomycin','Meropenem','Levofloxacin')
  • Contruct a normalized dose column
  • Convert data type to datetime and extract only year value

In [ ]:
presc['dose_val_rx'] = pd.to_numeric(presc['dose_val_rx'], errors = 'coerce')
presc = presc[presc['dose_unit_rx']=='mg']
presc = presc[presc['drug'].isin(['Vancomycin','Meropenem','Levofloxacin'])]

temp_df = pd.DataFrame()
for item in presc.drug.unique():
    temp = presc[presc['drug'].str.contains(item)]
    temp['norm_size'] = temp['dose_val_rx'] / temp['dose_val_rx'].max()
    temp_df = temp_df.append(temp)
presc = pd.merge(presc, temp_df, on=list(presc.columns))

presc['startdate'] = pd.to_datetime(presc['startdate'], errors = 'coerce')
presc.sort_values(by='startdate', inplace=True)
presc.set_index('startdate', inplace = True)
presc.head(1)

Create a structure and presentation of your web with HTML and CSS (5/6)


In [ ]:
list_patient = ['41976']
list_biomarker = ['White Blood Cells', 'Neutrophils']
list_drug = ['Vancomycin','Meropenem','Levofloxacin']

# stylesheets = ['./resources/bWLwgP.css']
app = dash.Dash()

app.layout = html.Div([

    dcc.Dropdown(
        id = 'patient',
        value = '41976',
        multi = False,
        options = [{'label': i, 'value': i} for i in list_patient],
    ),
    dcc.Dropdown(
        id = 'biomarker',
        value = 'White Blood Cells',
        multi = False,
        options = [{'label': i, 'value': i} for i in list_biomarker],
    ),
    dcc.Dropdown(
        id = 'drug',
        value = ['Vancomycin'],
        multi = True,
        options = [{'label': i, 'value': i} for i in list_drug],
    ),
    dcc.Graph(id = 'graph'),
])

Define the reactive behavior with Python (6/6)


In [ ]:
@app.callback(Output('graph', 'figure'), 
              [Input('patient', 'value'),
               Input('biomarker', 'value'),
               Input('drug', 'value')])
def update_graph(patient, biomarker, drug):
    traces = []
    temp_l = lab[lab['subject_id'].astype(str) == patient]
    temp_p = presc[presc['subject_id'].astype(str) == patient]
    temp_min = 0
    
    item = biomarker
    temp = temp_l[temp_l['label'] == item]
    temp_min = float(temp.value.astype(float).min())
    trace = go.Scatter(
                x = temp.index,
                y = temp.value,
                name = item,
                mode = 'lines+markers',
            )
    traces.append(trace)
        
    for i, item in enumerate(drug):
        temp = temp_p[ temp_p['drug'] == item]
        trace = go.Scatter(
                    x = temp.index,
                    y = np.ones((1, len(temp)))[0] * temp_min - i - 1,
                    name = item,
                    mode = 'markers',
                    marker = {
                        'size': temp.norm_size * 10
                    }
                )
        traces.append(trace)
    
    layout = go.Layout(
        legend = {'x': 0.5, 'y': -0.1, 'orientation': 'h', 'xanchor': 'center'},
        margin = {'l': 300, 'b': 10, 't': 10, 'r': 300},
        hovermode = 'closest',
    )
    return {'data': traces, 'layout': layout}

In [ ]:
app.run_server(port = 8050)

Takeaway

  • Python is excellent for data science
    • Easy to analyze and visualize data
    • Quickly develop a data-driven web application

External Resources (1/2)

External Resources (2/2)

Question?

Authors: Prof. med. Thomas Ganslandt Thomas.Ganslandt@medma.uni-heidelberg.de
and Kim Hee HeeEun.Kim@medma.uni-heidelberg.de

Heinrich-Lanz-Center for Digital Health (HLZ) of the Medical Faculty Mannheim
Heidelberg University

This is a part of a tutorial prepared for TMF summer school on 03.07.2019