def update_id_output(n_clicks, value): if n_clicks > 0: if value: samples = sf.master_df() samples.drop_duplicates(inplace=True) parsed_samples = [x.strip() for x in value.split(",")] status_df = samples[samples['run_sample_id'].isin(parsed_samples)].iloc[:, [0,1,3,11,10,15,19,17,18]] status_df['accession_date'] = status_df['accession_date'] + ', ' + \ pd.to_datetime( status_df['accession_date']).dt.strftime('%a') sample_status = dash_table.DataTable(columns=[{"name": i, "id": i} for i in status_df], data=status_df.to_dict( 'records'), style_data_conditional=[ { 'if': {'row_index': 'odd'}, 'backgroundColor': 'rgb(248,248,248)' } ], style_table={'height': min(40 + 35 * (len(status_df)), 500), 'overflowY': 'auto'} ) return sample_status
def per_detect(fc_click, start_date, end_date, value): fig = go.Figure() if fc_click and value: x_lower = (dt.strptime(start_date, '%Y-%m-%d') - timedelta(days=1)).strftime('%m-%d-%Y') x_upper = (dt.strptime(end_date, '%Y-%m-%d') + timedelta(days=1)).strftime('%m-%d-%Y') samples = sf.master_df() g_samples = samples[(samples['date'] >= pd.to_datetime(start_date)) & (samples['date'] <= pd.to_datetime(end_date))] g_samples.loc[:, 'call_map'] = g_samples.call.map({ 'not_detected': 0, 'detected': 1 }) * 100 percent_detect = g_samples[g_samples['Site Name'].isin(value)].groupby( ['Site Name', 'date']).mean().reset_index().rename( columns={'call_map': 'Percent Detected'}) fig = {} try: title = "Percent Detected By Site From " + start_date[: 10] + " To " + end_date[: 10] plot_title = {'text': [title], 'fontSize': 16} chart = alt.Chart(percent_detect).mark_line().encode( x=alt.X('date', title='Date', axis=alt.Axis(titleFontSize=14, labelFontSize=12, formatType='time', format='%a, %b-%d', labelAngle=45, grid=False), scale=alt.Scale(domain=[x_lower, x_upper])), y=alt.Y( 'Percent Detected', title='Percent Detected', scale=alt.Scale(domain=[ 0, max(percent_detect['Percent Detected']) * 1.05 ])), tooltip=['date', 'Percent Detected', 'Site Name'], color='Site Name') fig = chart.properties( title=plot_title, width=1200, height=250).configure_title(anchor='middle').to_dict() except Exception: pass return fig
def pie_chart(n_clicks): samples = sf.master_df() percent = samples[samples['call'] == 'detected'].dropna( subset=['Site Name']).replace( {'Healing Grove Health Center': 'Healing Grove'}) low_sites = percent.groupby('Site Name').count()[['runid']].reset_index() low_sites['runid'] = (low_sites['runid'] / low_sites.runid.sum()).mul(100).round(2) low_sites = low_sites.query("runid < 1")['Site Name'].values.tolist() percent.loc[percent['Site Name'].isin(low_sites), 'Site Name'] = "Other" percent = percent['Site Name'].value_counts( normalize=True).mul(100).round(2) data = go.Pie(labels=percent.index.tolist(), values=percent.values.tolist()) layout = go.Layout(annotations=[ dict(xref='paper', yref='paper', x=0.5, y=-0.22, showarrow=False, text= f'Other Testing Sites: {*low_sites[0:3],} <br> {*low_sites[3:],}') ], title={ 'text': '% Positive Detection By Site', 'y': 0.9, 'x': 0.5, 'xanchor': 'center', 'yanchor': 'top' }) fig = go.Figure(data=data, layout=layout) fig.update_traces(textinfo='percent+label', marker=dict(line=dict(color='#000000', width=2)), textposition='outside') return fig
def update_query_output(n_clicks, start_date, end_date, value): if n_clicks > 0: samples = sf.master_df() samples.drop_duplicates(inplace=True) samples = samples[samples['Specimen receipt date'] != 0] if value and not start_date and not end_date: status_df = samples[samples['Site Name'].isin(value)].sort_values(by='date', ascending=False) \ .iloc[:, [0,1,3,11,10,15,19,17,18]] elif start_date and end_date and not value: status_df = samples[(samples['date'] >= pd.to_datetime(start_date)) & ( samples['date'] <= pd.to_datetime(end_date))] \ .iloc[:, [0,1,3,11,10,15,19,17,18]] elif start_date and end_date and value: status_df = samples[(samples['date'] >= pd.to_datetime(start_date)) & ( samples['date'] <= pd.to_datetime(end_date))] status_df = status_df[status_df['Site Name'].isin(value)].sort_values(by='date', ascending=False) \ .iloc[:, [0,1,3,11,10,15,19,17,18]] else: return status_df['accession_date'] = status_df['accession_date'] + ', ' + \ pd.to_datetime( status_df['accession_date']).dt.strftime('%a') sample_status = dash_table.DataTable(columns=[{"name": i, "id": i} for i in status_df], data=status_df.to_dict('records'), style_data_conditional=[ { 'if': {'row_index': 'odd'}, 'backgroundColor': 'rgb(248,248,248)' } ], style_table={'height': 500, 'overflowY': 'auto'}, sort_action='native' ) return sample_status
def sample_status(fc_click, start_date, end_date): fig = {} sample_status = [] if fc_click: x_lower = (dt.strptime(start_date, '%Y-%m-%d') - timedelta(days=1)).strftime('%m-%d-%Y') x_upper = (dt.strptime(end_date, '%Y-%m-%d') + timedelta(days=1)).strftime('%m-%d-%Y') samples = sf.master_df() g_samples = samples[(samples['date'] >= pd.to_datetime(start_date)) & (samples['date'] <= pd.to_datetime(end_date))] dummies = pd.get_dummies(g_samples.flags) result = pd.concat([g_samples, dummies], axis=1) result = result.groupby('date').mean().reset_index() wout_pass = np.delete(g_samples.flags.unique(), np.where(g_samples.flags.unique() == 'pass')) for i in wout_pass: result[i] = (result[i] * 100).round(2) result.rename(columns={i: 'percent-' + i}, inplace=True) status = pd.wide_to_long(result, 'percent', i="date", j="condition", sep='-', suffix=r'.*').reset_index() title = "Percent Flag Occurrence From " + start_date[: 10] + " To " + end_date[: 10] plot_title = {'text': [title], 'fontSize': 16} chart = alt.Chart(status).mark_line().encode( x=alt.X('date', title='Date', axis=alt.Axis(titleFontSize=14, labelFontSize=12, formatType='time', format='%a, %b-%d', labelAngle=45, grid=False), scale=alt.Scale(domain=[x_lower, x_upper])), y=alt.Y('percent', title='Percent Occurrence', scale=alt.Scale(domain=[0, max(status.percent) * 1.05])), tooltip=['date', 'percent', 'condition'], color='condition') annotation = alt.Chart(status).mark_text( align='center', fontSize=15, dy=-10).encode(x='date', y='percent', text='percent').transform_filter( (datum.percent > 0)) fig = (chart + annotation).properties( title=plot_title, width=1200, height=250).configure_title(anchor='middle').to_dict() status_df = g_samples[g_samples['flags'] != 'pass'] \ .sort_values(by='date', ascending=False).iloc[:, [0, 1, 3, 11, 15, 19, 17, 18]] status_df['accession_date'] = status_df['accession_date'] + ', ' + \ pd.to_datetime( status_df['accession_date']).dt.strftime('%a') sample_status = dash_table.DataTable(columns=[{ "name": i, "id": i } for i in status_df], data=status_df.to_dict('records'), style_data_conditional=[{ 'if': { 'row_index': 'odd' }, 'backgroundColor': 'rgb(248,248,248)' }], style_table={ 'height': '450px', 'overflowY': 'auto' }, sort_action='native') return fig, sample_status
def samples_plot(n_clicks, start_date, end_date): fig_total = {} fig_tat = {} if n_clicks: x_lower = (dt.strptime(start_date, '%Y-%m-%d') - timedelta(days=1)).strftime('%m-%d-%Y') x_upper = (dt.strptime(end_date, '%Y-%m-%d') + timedelta(days=1)).strftime('%m-%d-%Y') samples = sf.master_df() samples = samples[(samples['date'] >= pd.to_datetime(start_date)) & (samples['date'] <= pd.to_datetime(end_date))] #### Total Sample Plot #### total_samples = samples.copy() total_samples.loc[:, 'sample_type'].replace({'Sample': 1}, inplace=True) total = total_samples.groupby( 'date').sum().loc[:, ['sample_type']].reset_index() # make fig title = "Total Clinical Samples per Day, " + start_date[:10] + " to " + end_date[:10] + ": " + str( total['sample_type'].sum()) + " Samples" plot_title = {'text': [title], 'fontSize': 16} bars = alt.Chart(total).mark_bar(size=15).encode( x=alt.X('date:T', title='Date', axis=alt.Axis(titleFontSize=14, labelFontSize=12, formatType='time', format='%a, %b-%d', labelAngle=45, grid=False), scale=alt.Scale(domain=[x_lower, x_upper])), y=alt.Y( 'sample_type:Q', axis=alt.Axis(labelFontSize=12, titleFontSize=14, title='Number of Samples', domain=False), scale=alt.Scale(domain=[0, max(total['sample_type']) * 1.1])), tooltip=['date', 'sample_type']) bar_text = bars.mark_text( baseline='top', align='center', dy=-15, color='black', fontSize=13, ).encode(text=alt.Text('sample_type:Q')) fig_total = (bars + bar_text).properties( title=plot_title, width=1200, height=250).configure_title( anchor='middle').interactive().to_dict() #### Turnaround Time Plot #### tat_samples = samples.copy() tat_samples.dropna(subset=['AIMS Reporting Notified Date'], inplace=True) time_diff = pd.to_datetime(tat_samples['AIMS Reporting Notified Date']) \ - pd.to_datetime(tat_samples['accession_date']) tat_samples['Turnaround Time in Hours'] = ( time_diff.dt.total_seconds() / 3600) tat_samples = tat_samples.groupby('date').agg({ 'Turnaround Time in Hours': 'mean' }).astype('int').reset_index() # make fig title = "Turnaround Time of Samples per Day, " + start_date[:10] + " to " + end_date[ :10] + " Average Turnaround Time: " + \ str(tat_samples['Turnaround Time in Hours'].mean().astype('int')) + " Hours" plot_title = {'text': [title], 'fontSize': 16} bars = alt.Chart(tat_samples).mark_bar(size=15).encode( x=alt.X('date:T', title='Date', axis=alt.Axis(titleFontSize=14, labelFontSize=12, formatType='time', format='%a, %b-%d', labelAngle=45, grid=False), scale=alt.Scale(domain=[x_lower, x_upper])), y=alt.Y( 'Turnaround Time in Hours:Q', axis=alt.Axis(labelFontSize=12, titleFontSize=14, title='Number of Samples', domain=False), scale=alt.Scale(domain=[ 0, max(tat_samples['Turnaround Time in Hours']) * 1.1 ])), tooltip=['date', 'Turnaround Time in Hours']) bar_text = bars.mark_text( baseline='top', align='center', dy=-15, color='black', fontSize=13, ).encode(text=alt.Text('Turnaround Time in Hours:Q')) rule = alt.Chart(tat_samples).mark_rule( color='red', opacity=0.5, strokeDash=[3, 3]).encode(y='mean(Turnaround Time in Hours):Q') fig_tat = (bars + bar_text + rule).properties( title=plot_title, width=1200, height=250).configure_title( anchor='middle').interactive().to_dict() return fig_total, fig_tat
def get_layout(): master = sf.master_df() positive = master[master['call'] == 'detected'] time_diff = pd.to_datetime(master['AIMS Reporting Notified Date']) \ - pd.to_datetime(master['accession_date']) tat = (time_diff.dropna().dt.total_seconds() / 3600).mean().astype(int) heading = sf.make_row(children=[ sf.make_col(children=[ html.H2(f"To this day, we have processed {len(master)} samples."), html.Div( html.H2(f"Of those samples, {len(positive)} are positive.")), html.Div( html. H2(f"Average Turnaround Time: {tat} Hours from Accessioning to Reporting." )) ]), sf.make_col( dcc.Graph(id='location-pie', style={'height': 500}, config={'displayModeBar': False})) ]) date_range = html.Div([ dcc.DatePickerRange(id='date-picker-range'), html.Div(id='output-container-date-picker-range') ]) fc_submit = sf.make_row(children=[ sf.make_col(html.Button("Submit", id="fc-button-clinical", n_clicks=0, n_clicks_timestamp=0), col_num=1) ]) submit_res = html.Div(id='button-res-clinical') site = pd.read_csv( '/ghds/groups/labdesk/bshih/c19dash/c19_dashboard/c19_tat.csv').fillna( 0) site = site[site['Site Name'].notnull()]['Site Name'].unique() site.sort() site_dropdown = html.Div( dcc.Dropdown(id='percent-detect-site-dropdown', options=[{ "label": i, "value": i } for i in site], placeholder='Collection Site', multi=True)) tot_smp_plot = html.Div([dav.VegaLite(id='tot-smp-plot')], style={ 'width': '100%', 'height': '400px' }) tat_plot = html.Div([dav.VegaLite(id='tat-plot')], style={ 'width': '100%', 'height': '400px' }) percent_detect = html.Div([dav.VegaLite(id='percent-detect-plot')], style={ 'width': '100%', 'height': '400px' }) total_sample = html.Div([dav.VegaLite(id='total-sample-plot')], style={ 'width': '100%', 'height': '400px' }) smp_status_plot = html.Div([dav.VegaLite(id='smp-status-plot')], style={ 'width': '100%', 'height': '400px' }) smp_status_table = html.Div(id='smp-status-table', style={ 'width': '100%', 'overflowX': 'auto' }) layout = html.Div([ heading, html.H3('Pick a date range '), date_range, fc_submit, submit_res, html.H3('Sample Statistics'), tot_smp_plot, tat_plot, html.H3('Site Specific Metrics'), site_dropdown, percent_detect, total_sample, html.H3('Sample Status'), smp_status_plot, smp_status_table ], style={'width': '100%'}) return layout