Spaces:
Paused
Paused
| import pandas as pd | |
| import numpy as np | |
| import panel as pn | |
| import scipy.stats as stats | |
| pn.extension('tabulator') | |
| import hvplot.pandas | |
| import holoviews as hv | |
| from bokeh.models import HoverTool | |
| from bokeh.models import GlyphRenderer, LinearAxis, LinearScale, Range1d | |
| import os | |
| from natsort import natsort_keygen | |
| import threading | |
| import time | |
| import schedule | |
| from datetime import datetime | |
| from huggingface_hub import HfApi | |
| # Initialize HfApi | |
| #repo_id = "pilotakekszel/dashboards_v0.1_retro" | |
| #api_token = os.getenv("HF_API_TOKEN") | |
| #if not api_token: | |
| # raise ValueError("API token not found! Ensure HF_API_TOKEN is set.") | |
| #api = HfApi(token=api_token) | |
| def restart_space(): | |
| response = api.restart_space(repo_id=repo_id) | |
| def schedule_restart(): | |
| # Schedule the restart every minute | |
| # FOR TESTING: | |
| #schedule.every(1).minutes.do(restart_space) | |
| schedule.every().day.at("06:00").do(restart_space) | |
| while True: | |
| schedule.run_pending() | |
| time.sleep(1) | |
| def start_scheduler(): | |
| # Start the scheduler in a separate thread | |
| scheduler_thread = threading.Thread(target=schedule_restart, daemon=True) | |
| scheduler_thread.start() | |
| # In[2]: | |
| if 'data' not in pn.state.cache.keys(): | |
| df = pd.read_csv('kgyc1.csv') | |
| df = df.rename(columns={'ASC-US': 'ASC-US/ASC-H ratio(%)'}) | |
| #df['Referral Rate(%)'] = df['Referral Rate(%)']*100 | |
| df['ASC-US/ASC-H ratio(%)'] = df['ASC-US/ASC-H ratio(%)']*100 | |
| df['ASC-H'] = df['ASC-H']*100 | |
| df = df.rename(columns={'index': 'people'}) | |
| df = df.rename(columns={'HPV/ASC-US': 'hrHPV/ASC-US rate (%)'}) | |
| df = df.rename(columns={'HPV/population': 'hrHPV Prevalence (%)'}) | |
| #df.at[0, 'Number'] = 151 | |
| df.iat[0, 5] = 2.25 | |
| df = df[~((df['people'].str.contains('ytolog')) & (df['Number'] < 1000))] | |
| df = df[~((df['people'].str.contains('path')) & (df['Number'] < 200))] | |
| #df = df[df['year'] != 2017] | |
| # Invalid rows - not representative for other reasons: | |
| #df = df[df['people'] != 'Cytotechnologist 21'] | |
| #df = df.reset_index(drop=True) | |
| #df = df.drop(19) | |
| # Replace 'cytologist' with 'cytotechnologist' in the index | |
| df['people'] = df['people'].str.replace('Cytologist', 'Cytotechnologist', regex=False) | |
| pn.state.cache['data'] = df.copy() | |
| else: | |
| df = pn.state.cache['data'] | |
| # In[3]: | |
| sdot_size = 500 | |
| sdot_person = 1500 | |
| sheight = 800 | |
| f_scale = 2 | |
| f_scale_lab = 1.5 | |
| fpx = '28px' | |
| legend_px = '24px' | |
| pl_title = {'title': 14} | |
| stylesheet = f""" | |
| :host {{ | |
| --handle-width: 30px; | |
| --handle-height: 50px; | |
| --slider-size: 25px; | |
| }} | |
| """ | |
| select_style = """ | |
| .bk-input { | |
| font-size: 20px; | |
| } | |
| """ | |
| mobile_style = {'font-size': f'{fpx}', 'padding': '40px'} | |
| first_year = df['year'].nsmallest(2).iloc[-1] | |
| col_options = ['ASC/LSIL', 'ASC-US/ASC-H ratio(%)','Abnormal Rate(%)','Referral Rate(%)', 'hrHPV/ASC-US rate (%)', 'hrHPV Prevalence (%)'] | |
| column_changer = pn.widgets.Select(name='Select QA Parameter', options=col_options, styles = mobile_style, width = 400, height=150, margin = 0,stylesheets= [select_style]) | |
| year_slider = pn.widgets.Select(name='Select Year', value = int(df.year.max()),options=list(range(int(first_year), int(df.year.max())+1)), styles = mobile_style, width = 400, height=150, margin = 0,stylesheets= [select_style]) | |
| # In[4]: | |
| modal = f""" | |
| <div><br><br><p style = "text-align: justify;"> | |
| <span style="font-size: {fpx}; font-weight: bold">This application's development is in progress. For the more fluent user experience use a tablet or laptop. </span><br><br> | |
| <span style="font-size: {fpx}; font-weight: bold">TABS: </span><br><br> | |
| <span style="font-size: {fpx};">1. With the first level of tabs, outcomes are presented in three formats for the </span>\ | |
| <span style="font-size: {fpx}; font-weight: bold">Laboratory management</span> | |
| <span style="font-size: {fpx};">for the </span> | |
| <span style="font-size: {fpx}; font-weight: bold">Cytopathologists</span> | |
| <span style="font-size: {fpx};">and for the </span> | |
| <span style="font-size: {fpx}; font-weight: bold">Cytologists</span> | |
| <span style="font-size: {fpx};">. You can choose between them by clicking on the tabs. | |
| </span><br> | |
| <span style="font-size: {fpx};">2. You can toggle between </span> | |
| <span style="font-size: {fpx}; font-weight: bold">Performance Results</span> | |
| <span style="font-size: {fpx};">, and</span> | |
| <span style="font-size: {fpx}; font-weight: bold">Results Overviews</span> | |
| <span style="font-size: {fpx};">with the second level tabs. </span><br> | |
| <span style="font-size: {fpx};">3. Use the Year Slider to choose the year of your interest. </span><br> | |
| <span style="font-size: {fpx};">4. Choose the QA parameter. </span> | |
| <br><br><br>\ | |
| <span style="font-size: {fpx}; font-weight: bold">GRAPHS: </span><br><br>\ | |
| <span style="font-size: {fpx}; font-weight: bold">QA Parameter graphs: </span> | |
| <span style="font-size: {fpx};">Results are shown in comparison with </span> | |
| <span style="font-size: {fpx}; font-weight: bold; background-color: #ACFFA0" >laboratory target </span> | |
| <span style="font-size: {fpx}" >,</span> | |
| <span style="font-size: {fpx}; font-weight: bold; background-color: #6AB35F" >borderline </span> | |
| <span style="font-size: {fpx}" >and</span> | |
| <span style="font-size: {fpx}; font-weight: bold; background-color: #B34D93" >attention zones </span> | |
| <span style="font-size: {fpx}">that were defined by standard deviations \ | |
| and absolute percentage values from reference values on professionally established benchmarks. | |
| The dashed line represent the </span> | |
| <span style="font-size: {fpx}; font-weight: bold; color: #5B91D1">laboratory result</span> | |
| <span style="font-size: {fpx}">, while the straight black line represents the </span> | |
| <span style="font-size: {fpx}; font-weight: bold">international reference</span> | |
| <span style="font-size: {fpx}">.<br> | |
| By hitting the dots a tooltip will appear.</span><br><br> | |
| <span style="font-size: {fpx}; font-weight: bold">Reference Curve vs Laboratory Histogram: </span> | |
| <span style="font-size: {fpx};">Without data transformation, results showed no normal distribution (Shapiro-Wilk test p < 0.05). | |
| In case of </span> | |
| <span style="font-size: {fpx};font-weight: bold;">ASC/LSIL ratio, ASC-US/ASC-H ratio (%) and Abnormal ratio, </span> | |
| <span style="font-size: {fpx};font-weight: bold;">reference normal distribution curves</span> | |
| <span style="font-size: {fpx};">were compared with </span> | |
| <span style="font-size: {fpx};font-weight: bold; color: #5B91D1">histograms of laboratory results</span> | |
| <span style="font-size: {fpx};">and </span> | |
| <span style="font-size: {fpx};font-weight: bold; color: #FE0F17">Z scores </span> | |
| <span style="font-size: {fpx};">of outliers were highlighted on the graph.</span><br><br><br> | |
| <span style="font-size: {fpx}; font-weight: bold">RESULTS: </span><br><br>\ | |
| <span style="font-size: {fpx}; font-weight: bold">Results Overviews</span> | |
| <span style="font-size: {fpx};">interpret graphs for the user, highlighting outliers regarding the chosen QA parameter, | |
| and tendencies in performance. | |
| </span><br><br></p> | |
| </div> | |
| """ | |
| # Create a button | |
| modal_style = """ | |
| .bk-btn.bk-btn-default { | |
| font-size: 24px; | |
| font-weight: bold; | |
| } | |
| """ | |
| modal_btn = pn.widgets.Button(name="Click for hints to use", stylesheets = [modal_style]) | |
| # Callback that will open the modal when the button is clicked | |
| def about_callback(event): | |
| template.open_modal() | |
| # Link the button to the callback and append it to the sidebar | |
| modal_btn.on_click(about_callback) | |
| legend_df_indiv = ['Reference', 'Lab result','Lab goal','Borderline', 'Attention'] | |
| # In[5]: | |
| legend_df_indiv = pd.DataFrame({'Legend': legend_df_indiv}) | |
| # In[6]: | |
| vlegend_df_indiv = legend_df_indiv.style | |
| # In[7]: | |
| #COLORS (EGGPLANT): ['#ACFFA0','#6AB35F','#B34D93'] | |
| vlegend_df_indiv.set_table_styles([ # create internal CSS classes | |
| {'selector': '.ref', 'props': f'border: 2px solid #242124; color:black; font-weight: bold; font-size: {legend_px}'}, | |
| {'selector': '.lab', 'props': f'border: 2px dashed #5B91D1; color:#5B91D1; font-weight: bold; font-size: {legend_px}' }, | |
| {'selector': '.goal', 'props': f'background-color: #ACFFA0;; font-weight: bold; font-size: {legend_px}' }, | |
| {'selector': '.att', 'props': f'background-color: #B34D93;; font-weight: bold; font-size: {legend_px}' }, | |
| {'selector': '.bdln', 'props': f'background-color: #6AB35F;; font-weight: bold; font-size: {legend_px}' } | |
| ], overwrite=False) | |
| cell_color = pd.DataFrame([['ref'],['lab'],['goal'],['bdln'],['att']], | |
| index=vlegend_df_indiv.index, | |
| columns=vlegend_df_indiv.columns[:4]) | |
| vertical_legend_indiv=vlegend_df_indiv.set_td_classes(cell_color) | |
| vertical_legend_indiv =vertical_legend_indiv.hide(axis='columns') | |
| vertical_legend_indiv =vertical_legend_indiv.hide(axis='rows') | |
| vertical_legend_indiv= pn.pane.DataFrame(vertical_legend_indiv, index= False) | |
| vertical_legend_indiv= pn.Column("## Legend", vertical_legend_indiv) | |
| zcol = [col_options[0],col_options[1],col_options[2]] | |
| zscore_base = df[zcol] | |
| new_row = [0.75, 12.5, 1.5] | |
| zscore_base.iloc[1] = new_row | |
| zscore_df = (zscore_base.iloc[2:] - zscore_base.iloc[0]) /zscore_base.iloc[1] | |
| zscore_df['year'] = df['year'] | |
| zscore_df['people'] = df['people'] | |
| zscore_eval = zscore_df.groupby(['people']) | |
| # In[8]: | |
| # LAB OVERVIEW | |
| def find_first_decrease_in_performance(lst): | |
| x_values = [] | |
| for i in range(len(lst) - 1): | |
| if lst[i] + 1 == lst[i + 1]: | |
| x_values.append(lst[i]) | |
| else: | |
| x_values = [lst[-1]] | |
| return x_values[0] | |
| def find_values_less_than_previous(input_list): | |
| less_than_previous_indexes = [] | |
| for i in range(1, len(input_list)): | |
| if (input_list[i] < input_list[i - 1]): | |
| less_than_previous_indexes.append(i-1) | |
| return less_than_previous_indexes | |
| def find_values_more_than_previous(input_list): | |
| more_than_previous_indexes = [] | |
| for i in range(1, len(input_list)): | |
| if (input_list[i] > input_list[i - 1]): | |
| more_than_previous_indexes.append(i-1) | |
| return more_than_previous_indexes | |
| def find_last_decreasing_element(lst): | |
| for i in range(1, len(lst)): | |
| if lst[i] != lst[i - 1] - 1: | |
| return lst[i-1] | |
| return lst[len(lst)-1] | |
| def labres(column_changer): | |
| lab_zscore = zscore_eval.get_group('KGYC') | |
| abs_results = df[df['people'] == 'KGYC'] | |
| lab_comment_5 = "" | |
| asc_abn_outliers = zscore_df[(zscore_df['people'].str.contains('Cyto'))&(zscore_df['year']==int(df.year.max()))] | |
| asc_abn_outliers_filtered = asc_abn_outliers[~asc_abn_outliers['people'].str.contains('Cytotechnologist 8', case=False, na=False)] | |
| ref_outlier = df[(df['people'].str.contains('Cytot')) & (df['year'] == int(df.year.max()))] | |
| ref_outlier_filtered = ref_outlier[~ref_outlier['people'].str.contains('Cytotechnologist 8', case=False, na=False)] | |
| #thy_outlier = df[(df['people'].str.contains('Cytop')) & (df['year'] == int(df.year.max()))] | |
| # ASCUS & ABNORMAL: | |
| lab_comment_3= f"No outliers regarding {column_changer}" | |
| lab_comment_4 = "" | |
| if column_changer == col_options[1]: | |
| avg_zscore = zscore_eval.get_group('KGYC')['ASC-US/ASC-H ratio(%)'].mean() | |
| lab_ascus_reference = 90.0 - avg_zscore | |
| lab_asch_reference = 10.0 + avg_zscore | |
| sd_dev = 5 #(95% CI esetén) | |
| goal_zone = (lab_ascus_reference - sd_dev, lab_ascus_reference + sd_dev) | |
| borderline_zone = [(lab_ascus_reference - 2 * sd_dev, lab_ascus_reference - sd_dev), (lab_ascus_reference + sd_dev, lab_ascus_reference + 2 * sd_dev)] | |
| attention_zone = [(lab_ascus_reference - 2 * sd_dev, 0), (lab_ascus_reference + 2 * sd_dev, 100)] #lab_ascus_reference - 3 * sd_dev így lenne helyesebb, de az attention zone valójában már a borderline alsó értékétől számítandó | |
| descript = (f"**Description:** *ASC-US/ASC-H ratio literature reference value 90% / 10%. " | |
| f"Given our average laboratory Z score of {avg_zscore:.2f}, the laboratory's average ratio is " | |
| f"{lab_ascus_reference:.2f}% / {lab_asch_reference:.2f}%.* <br><br> " | |
| f"Given our average laboratory Z score, the goal, borderline, and attention zones calculated with 95% CI are the following: " | |
| f"**Goal Zone:** {goal_zone[0]:.2f} to {goal_zone[1]:.2f}, " | |
| f"**Borderline Zone:** {borderline_zone[0][0]:.2f} to {borderline_zone[0][1]:.2f} " | |
| f"and {borderline_zone[1][0]:.2f} to {borderline_zone[1][1]:.2f}, " | |
| f"**Attention Zone:** {attention_zone[0][0]:.2f} to {attention_zone[0][1]:.2f} " | |
| f"and {attention_zone[1][0]:.2f} to {attention_zone[1][1]:.2f}. <br><br>") | |
| if column_changer == col_options[2]: | |
| descript = "**Description:** *Abnormal Rate represents the relative ratio of ASC, SIL and AGC diagnoses. Alterations ( Z Score: <-2) means a level of insecurity that requires attention.*<br><br>" | |
| if column_changer == col_options[1] or column_changer == col_options[2]: | |
| lab_value = lab_zscore[column_changer].iloc[len(lab_zscore)-1] | |
| if lab_value >= -1: | |
| lab_comment = f"Latest record of laboratory average value is within one standard deviation from reference average (Z score: {lab_value:.2f}), " | |
| elif -1 > lab_value > -2: | |
| lab_comment = f"Latest record of laboratory average value is in the borderline zone regarding performance compared to reference (Z score: {lab_value:.2f}), " | |
| else: | |
| lab_comment = f"Attention needed!, laboratory performance is considerably deviant from reference value, global laboratory practice revision is advised. (Z score {lab_value:.2f})" | |
| if (-1 > lab_value) & (lab_zscore[column_changer].iloc[len(lab_zscore)-1] < lab_zscore[column_changer].iloc[len(lab_zscore)-2]): | |
| decreasing_tendency = find_values_less_than_previous(lab_zscore[column_changer].to_list()) | |
| lab_comment_2 = f"with tendencious decrease in performance since year {decreasing_tendency[0]+int(first_year)}." | |
| else: | |
| lab_comment_2 = "with no relevant tendency or no tendency at all in decrease of performance. " | |
| if (asc_abn_outliers_filtered[column_changer] < -2).any(): | |
| asc_abn_outly = asc_abn_outliers_filtered[asc_abn_outliers_filtered[column_changer] < -2]['people'].to_list() | |
| lab_comment_3 = f"Outliers regarding {column_changer}: **{asc_abn_outly}**," | |
| lab_comment_4 = [] | |
| for o in asc_abn_outly: | |
| if (len(zscore_eval.get_group(o))>1) & (zscore_eval.get_group(o)[column_changer].iloc[len(zscore_eval.get_group(o))-1] <= zscore_eval.get_group(o)[column_changer].iloc[len(zscore_eval.get_group(o))-2]): | |
| first_out = find_values_less_than_previous(zscore_eval.get_group(o)[column_changer].to_list()) | |
| if len(first_out) > 2: | |
| lab_comment_4.append(f"**{o}** with tendencious decrease since **{find_first_decrease_in_performance(first_out)+int(first_year)}**") | |
| else: | |
| lab_comment_4.append(f"**{o}** with tendencious decrease compared to last registered result in **{zscore_eval.get_group(o)['year'].iloc[0]}**") | |
| lab_comment_5= "" | |
| lab_comment_6= "" | |
| # ASCLSIL: | |
| elif column_changer == col_options[0]: | |
| descript = f"**Description:** *ASC/LSIL value represents the ASC-US, ASC-H diagnoses compared to LSIL diagnoses. Considerable elevation (Z Score > 2) from reference value {df.iat[0,5]} requires attention. A lower result than 1.5 could imply an increase in false negative interpretations.*<br><br>" | |
| lab_value = lab_zscore[column_changer].iloc[len(lab_zscore)-1] | |
| if -1 < lab_value < 1: | |
| lab_comment = f"Latest record of laboratory average value is within one standard deviation from reference average (Z score: {lab_value:.2f}), " | |
| elif 1 < lab_value < 2: | |
| lab_comment = f"Latest record of laboratory average value is in the borderline zone regarding performance compared to reference (Z score: {lab_value:.2f}), " | |
| elif lab_value > 2: | |
| lab_comment = f"Laboratory performance is considerably deviant from reference value, global laboratory practice revision is advised. (Z score {lab_value:.2f})" | |
| elif lab_value < -1: | |
| lab_comment = f"Laboratory result is below one standard deviation from reference average (Z score: {lab_value:.2f}), indicating a risk of low sensitivity." | |
| if (lab_value > 1) & (lab_zscore[column_changer].iloc[len(lab_zscore)-1] > lab_zscore[column_changer].iloc[len(lab_zscore)-2]): | |
| increasing_tendency = find_values_more_than_previous(lab_zscore[column_changer].to_list()) | |
| lab_comment_2 = f"with tendencious decrease in performance since year {increasing_tendency[0]+int(first_year)}." | |
| else: | |
| lab_comment_2 = "" | |
| if (asc_abn_outliers_filtered[column_changer] > 2).any(): | |
| asclsil_outly = asc_abn_outliers_filtered[asc_abn_outliers_filtered[column_changer] > 2]['people'].to_list() | |
| lab_comment_3 = f"Outliers regarding {column_changer}: **{asclsil_outly}**," | |
| lab_comment_4 = [] | |
| for o in asclsil_outly: | |
| if (len(zscore_eval.get_group(o))>1) & (zscore_eval.get_group(o)[column_changer].iloc[len(zscore_eval.get_group(o))-1] >= zscore_eval.get_group(o)[column_changer].iloc[len(zscore_eval.get_group(o))-2]): | |
| first_out = find_values_more_than_previous(zscore_eval.get_group(o)[column_changer].to_list()) | |
| if len(first_out) > 2: | |
| lab_comment_4.append(f"**{o}** with tendencious decrease since **{find_first_decrease_in_performance(first_out)+int(first_year)}**") | |
| else: | |
| lab_comment_4.append(f"**{o}** with tendencious decrease compared to last registered result in**{zscore_eval.get_group(o)['year'].iloc[0]}**") | |
| lab_comment_5= "" | |
| lab_comment_6= "" | |
| # Thyroid Rate(%): | |
| #elif column_changer == col_options[2]: | |
| #descript = "**Description:** *Thyroid AUS Rate signifies the ratio of AUS (TBS 3) cytology reports. More than 15% requires attention.* <br><br>" | |
| #thyroid_value = abs_results[column_changer].iloc[len(abs_results)-1] | |
| #if thyroid_value < 10: | |
| # lab_comment = f"Latest record of laboratory result is within laboratory goal zone. {thyroid_value:.2f}%" | |
| #elif 10 < thyroid_value < 15: | |
| # lab_comment = f"Latest record of laboratory result is in laboratory borderline zone. {thyroid_value:.2f}%" | |
| #else: | |
| # lab_comment = f"Latest laboratory result value is {thyroid_value:.2f}%, performance follow up and global laboratory practice revision is advised." | |
| #if (thyroid_value > 10) & (abs_results[column_changer].iloc[len(abs_results)-1] > abs_results[column_changer].iloc[len(abs_results)-2]): | |
| # increasing_tendency = find_values_more_than_previous(lab_zscore[column_changer].to_list()) | |
| # lab_comment_2 = f"with tendencious decrease in performance since year {increasing_tendency[0]+int(first_year)}." | |
| #else: | |
| # lab_comment_2 = "with no relevant tendency or no tendency at all in decrease of performance. " | |
| #if (thy_outlier[column_changer] > 15).any(): | |
| # thy_outly = thy_outlier[thy_outlier[column_changer] > 15]['people'].to_list() | |
| # lab_comment_3 = f"Outliers regarding {column_changer}: **{thy_outly}**," | |
| # for o in thy_outly: | |
| # if (len(df.groupby(['people']).get_group(o))>1) & (df.groupby(['people']).get_group(o)[column_changer].iloc[len(df.groupby(['people']).get_group(o))-1] >= df.groupby(['people']).get_group(o)[column_changer].iloc[len(df.groupby(['people']).get_group(o))-2]): | |
| # first_out = find_values_more_than_previous(df.groupby(['people']).get_group(o)[column_changer].to_list()) | |
| # if len(first_out) > 2: | |
| # lab_comment_4.append(f"**{o}** with tendencious decrease since **{find_first_decrease_in_performance(first_out)+int(first_year)}**") | |
| # else: | |
| # lab_comment_4.append(f"**{o}** with tendencious decrease compared to last registered result in**{zscore_eval.get_group(o)['year'].iloc[first_out[0]]}**") | |
| #lab_comment_5= "" | |
| #lab_comment_6= "" | |
| # Referral Rate(%) | |
| elif column_changer == col_options[3]: | |
| descript = "**Description:** *Referral Rate signifies the ratio the Cytotechnologist consults cases. < 5 % and > 15% requires attention.*<br><br>" | |
| referral_value = abs_results['Referral Rate(%)'].iloc[len(abs_results)-1] | |
| if 7 < referral_value < 13: | |
| lab_comment = f"Latest record of laboratory result is within laboratory goal zone {referral_value:.2f}%. " | |
| lab_comment_2 ="" | |
| elif 5 < referral_value < 7: | |
| lab_comment = f"Latest record of laboratory result is in laboratory borderline zone. {referral_value:.2f}%." | |
| if (abs_results[column_changer].iloc[len(abs_results)-1] < abs_results[column_changer].iloc[len(abs_results)-2]): | |
| lab_comment_2 = f"An underreferral tendency can be observed since last year." | |
| else: | |
| lab_comment_2 ="" | |
| elif 13 < referral_value < 15: | |
| lab_comment = f"Latest record of laboratory result is in laboratory borderline zone {referral_value:.2f}%." | |
| if (abs_results[column_changer].iloc[len(abs_results)-1] > abs_results[column_changer].iloc[len(abs_results)-2]): | |
| lab_comment_2 = f"An overreferral tendency can be observed since last year." | |
| else: | |
| lab_comment_2 ="" | |
| elif (referral_value < 5) or (referral_value > 15): | |
| lab_comment = f"Latest laboratory result value is {referral_value:.2f}%, performance follow up and global laboratory practice revision is advised." | |
| lab_comment_2 = "" | |
| if (ref_outlier_filtered[column_changer] < 5).any(): | |
| ref_outly_down = ref_outlier_filtered[(ref_outlier_filtered[column_changer] < 5)]['people'].to_list() | |
| lab_comment_3 = f"<br>Underreferral in case of **{ref_outly_down}**. " | |
| lab_comment_4 = [] | |
| for o in ref_outly_down: | |
| if (len(df.groupby(['people']).get_group(o))>1) & (df.groupby(['people']).get_group(o)[column_changer].iloc[len(df.groupby(['people']).get_group(o))-1] <= df.groupby(['people']).get_group(o)[column_changer].iloc[len(df.groupby(['people']).get_group(o))-2]): | |
| first_out = find_values_less_than_previous(df.groupby(['people']).get_group(o)[column_changer].to_list()) | |
| if len(first_out) > 2: | |
| lab_comment_4.append(f"**{o}** with tendencious decrease since **{find_first_decrease_in_performance(first_out)+int(first_year)}**") | |
| else: | |
| lab_comment_4.append(f"**{o}** with tendencious decrease compared to last registered result in **{df.groupby(['people']).get_group(o)['year'].iloc[first_out[0]]}**") | |
| if (ref_outlier_filtered[column_changer] > 15).any(): | |
| ref_outly_up = ref_outlier_filtered[(ref_outlier_filtered[column_changer] > 15)]['people'].to_list() | |
| lab_comment_5 = f"<br>Overreferral in case of **{ref_outly_up}**. " | |
| lab_comment_6 = [] | |
| for o in ref_outly_up: | |
| if (len(df.groupby(['people']).get_group(o))>1) & (df.groupby(['people']).get_group(o)[column_changer].iloc[len(df.groupby(['people']).get_group(o))-1] >= df.groupby(['people']).get_group(o)[column_changer].iloc[len(df.groupby(['people']).get_group(o))-2]): | |
| first_out = find_values_more_than_previous(df.groupby(['people']).get_group(o)[column_changer].to_list()) | |
| if len(first_out) > 2: | |
| lab_comment_6.append(f"**{o}** with tendencious decrease since **{find_first_decrease_in_performance(first_out)+int(first_year)}**") | |
| else: | |
| lab_comment_6.append(f"**{o}** with tendencious decrease compared to last registered result in**{zscore_eval.get_group(o)['year'].iloc[first_out[0]]}**") | |
| #hrHPV/ASC-US ratio (%) | |
| elif column_changer == col_options[4]: | |
| abs_results = df[df['people'] == 'KGYC'] | |
| hrhpv_ascus = abs_results['hrHPV/ASC-US rate (%)'].iloc[len(abs_results)-1] | |
| descript = "**Description:** *The hrHPV/ASC-US rate represents the high-risk HPV positive ASC-US cases among all ASC-US diagnoses. The literature reference value is 36.6%. A rate < 30% and > 60% could indicate problems with laboratory protocol or changes in population risk factors.*<br><br>" | |
| if 30 < hrhpv_ascus < 60: | |
| lab_comment = f"Latest record of laboratory result is within laboratory goal zone {hrhpv_ascus:.2f}%. " | |
| lab_comment_2 ="" | |
| elif 20 < hrhpv_ascus < 30: | |
| lab_comment = f"Latest record of laboratory result is in laboratory borderline zone. {hrhpv_ascus:.2f}%." | |
| if (abs_results[column_changer].iloc[len(abs_results)-1] < abs_results[column_changer].iloc[len(abs_results)-2]): | |
| lab_comment_2 = f"A decreasing trend can be observed since last year, a lower than 30% rate could indicate problems with laboratory protocol or changes in population risk factors." | |
| else: | |
| lab_comment_2 ="" | |
| elif 60 < hrhpv_ascus < 70: | |
| lab_comment = f"Latest record of laboratory result is in laboratory borderline zone {hrhpv_ascus:.2f}%." | |
| if (abs_results[column_changer].iloc[len(abs_results)-1] > abs_results[column_changer].iloc[len(abs_results)-2]): | |
| lab_comment_2 = f"An increasing trend can be observed since last year, a higher than 60% rate could indicate problems with laboratory protocol or changes in population risk factors." | |
| else: | |
| lab_comment_2 ="" | |
| elif (hrhpv_ascus < 20) or (hrhpv_ascus > 70): | |
| lab_comment = f"Latest laboratory result value is {hrhpv_ascus:.2f}%, performance follow up and global laboratory practice revision is advised." | |
| lab_comment_2 = "" | |
| #HPV Prevalence (%) | |
| elif column_changer == col_options[5]: | |
| abs_results = df[df['people'] == 'KGYC'] | |
| hrhpv_pop = abs_results['hrHPV Prevalence (%)'].iloc[len(abs_results)-1] | |
| descript = "**Description:** *The hrHPV Prevalence represents the high-risk HPV prevalence rate among the laboratory's population. The literature reference value varies between 11% and 29% based on the region and type of population screened (Eastern Europe - 21%). A rate < 10% and > 30% could indicate problems with laboratory protocol or changes in population risk factors.*<br><br>" | |
| if 10 < hrhpv_pop < 30: | |
| lab_comment = f"Latest record of laboratory result is within laboratory goal zone {hrhpv_pop:.2f}%. " | |
| lab_comment_2 ="" | |
| elif 5 < hrhpv_ascus < 10: | |
| lab_comment = f"Latest record of laboratory result is in laboratory borderline zone. {hrhpv_pop:.2f}%." | |
| if (abs_results[column_changer].iloc[len(abs_results)-1] < abs_results[column_changer].iloc[len(abs_results)-2]): | |
| lab_comment_2 = f"A decreasing trend can be observed since last year, a lower than 10% rate could indicate problems with laboratory protocol or changes in population risk factors." | |
| else: | |
| lab_comment_2 ="" | |
| elif 30 < hrhpv_ascus < 35: | |
| lab_comment = f"Latest record of laboratory result is in laboratory borderline zone {hrhpv_pop:.2f}%." | |
| if (abs_results[column_changer].iloc[len(abs_results)-1] > abs_results[column_changer].iloc[len(abs_results)-2]): | |
| lab_comment_2 = f"An increasing trend can be observed since last year, a higher than 30% rate could indicate problems with laboratory protocol or changes in population risk factors." | |
| else: | |
| lab_comment_2 ="" | |
| elif (hrhpv_pop < 5) or (hrhpv_pop > 35): | |
| lab_comment = f"Latest laboratory result value is {hrhpv_pop:.2f}%, performance follow up and global laboratory practice revision is advised." | |
| lab_comment_2 = "" | |
| lab_comment_6 = lab_comment_6 if 'lab_comment_6' in locals() else [] | |
| return pn.pane.Markdown(f""" ## {column_changer}: | |
| {descript} {lab_comment} {lab_comment_2} | |
| {lab_comment_3} {lab_comment_4} {lab_comment_5} {lab_comment_6} | |
| """, sizing_mode ='stretch_both', styles = {'font-size':fpx}) | |
| inter_labres = pn.bind(labres, column_changer) | |
| def lab_management(year_slider, column_changer): | |
| line_data = df[df['people'].str.contains('KGYC')].sort_values(by="year").reset_index(drop=True) | |
| avg_zscore = zscore_eval.get_group('KGYC')['ASC-US/ASC-H ratio(%)'].mean() | |
| lab_ascus_reference = 90.0 - avg_zscore #Végül 95%-os CI-vel alkottam meg a bdl és att zónákat | |
| lab_asch_reference = 10.0 + avg_zscore | |
| sd_dev = 5 #(95% CI esetén) | |
| goal_zone = (lab_ascus_reference - sd_dev, lab_ascus_reference + sd_dev) | |
| borderline_zone = [(lab_ascus_reference - 2 * sd_dev, lab_ascus_reference - sd_dev), (lab_ascus_reference + sd_dev, lab_ascus_reference + 2 * sd_dev)] | |
| attention_zone = [(lab_ascus_reference - 2 * sd_dev, 0), (lab_ascus_reference + 2 * sd_dev, 100)] | |
| scatterdata = df[(df.year == year_slider)&(df.people.str.contains('KGYC|Cyto'))].sort_values(by="people", \ | |
| ascending=False,key=natsort_keygen()).reset_index(drop=True) | |
| scatterdata_filtered = scatterdata[~scatterdata.people.str.contains('Cytotechnologist 8', case=False, na=False)] | |
| ref = df[column_changer].iloc[0] | |
| lab = scatterdata_filtered[column_changer].iloc[0] | |
| max_x = scatterdata_filtered[column_changer].max() | |
| max_x_abn = scatterdata_filtered[scatterdata_filtered.people.str.contains('ytolog')][column_changer].max() | |
| min_x = scatterdata_filtered[column_changer].min() | |
| if column_changer != 'ASC-US/ASC-H ratio(%)': | |
| tooltips_cp = f""" | |
| <div> | |
| <span style="font-size: {fpx}; font-weight: bold">@people | |
| </span><br> | |
| <span style= "font-size:{fpx}; font-weight: bold; color: #5B91D1">{column_changer}: | |
| </span> | |
| <span style="font-size: {fpx};">@{{{column_changer}}} | |
| </span> | |
| </div> | |
| """ | |
| else: | |
| tooltips_cp = f""" | |
| <div> | |
| <span style="font-size: {fpx}; font-weight: bold">@people | |
| </span><br> | |
| <span style= "font-size:{fpx}; font-weight: bold; color: #5B91D1">ASC-US(%): | |
| </span> | |
| <span style="font-size: {fpx};">@{{{column_changer}}} | |
| </span> | |
| </div> | |
| """ | |
| hover_cp = HoverTool(tooltips=tooltips_cp) | |
| scatter_plot = scatterdata_filtered[scatterdata_filtered.people.str.contains('Cyto', na=False)].hvplot.scatter(x=column_changer, y='people', color='black', size=sdot_size, height= sheight, | |
| xlim=(0,max_x+0.5), xticks = [0,lab,ref, max_x], grid=True, title=column_changer, | |
| xformatter='%.1f',xlabel ='', ylabel='', tools = [hover_cp]).opts(fontsize = pl_title, fontscale=f_scale_lab, shared_axes=False, toolbar=None, default_tools = []) | |
| ref_vline = hv.VLine(x=ref).opts(color='black', alpha = 1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| lab_vline = hv.VLine(x=lab).opts(color='#5B91D1', line_dash ='dashed',alpha=1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| if column_changer == 'ASC/LSIL': | |
| asc_lsil_goal = hv.VSpan(1.5, 3).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_bdln_1 = hv.VSpan(3, 3.75).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_bdln_2 = hv.VSpan(0, 1.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_att = hv.VSpan(3.75, 15).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asclsil_bg =(asc_lsil_goal.opts(color='#ACFFA0', alpha=0.75) * asc_lsil_bdln_2.opts(color='#6AB35F', alpha=0.75) * asc_lsil_bdln_1.opts(color='#6AB35F', alpha=0.75) * asc_lsil_att.opts(color='#B34D93', alpha=0.9)) | |
| return (asclsil_bg* ref_vline * lab_vline * scatter_plot).opts(shared_axes=False) | |
| elif column_changer == 'ASC-US/ASC-H ratio(%)' : | |
| scatter_plot = scatterdata_filtered[scatterdata_filtered.people.str.contains('Cyto', na=False)].hvplot.scatter(x=column_changer, y='people', color='black', size=sdot_size,height= sheight, | |
| xlim=(60,100), xticks = [min_x,lab,ref, max_x], rot=45, grid=True, title=column_changer, | |
| xformatter='%.1f',ylabel='',xlabel='', tools = [hover_cp]).opts(fontsize = pl_title,fontscale=f_scale_lab,shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_goal = hv.VSpan(85, 95).opts(shared_axes=False,toolbar=None, default_tools = []) #hv.VSpan(float(goal_zone[0], float(goal_zone[1])) | |
| asc_us_bdln_1 = hv.VSpan(80, 85).opts(shared_axes=False,toolbar=None, default_tools = []) #hv.VSpan(float(borderline_zone[1][0]), float(borderline_zone[1][1])) | |
| asc_us_bdln_2 = hv.VSpan(95, 98).opts(shared_axes=False,toolbar=None, default_tools = []) #hv.VSpan(float(borderline_zone[0][0]), float(borderline_zone[0][1])) | |
| asc_us_att_1 = hv.VSpan(60, 80).opts(shared_axes=False,toolbar=None, default_tools = []) #hv.VSpan(float(attention_zone[0][0]), float(attention_zone[0][1])) | |
| asc_us_att_2 = hv.VSpan(98, 100).opts(shared_axes=False, toolbar=None, default_tools=[]) #hv.VSpan(float(attention_zone[1][0]), float(attention_zone[1][1])) | |
| ascus_bg = (asc_us_goal.opts(color='#ACFFA0', alpha = 0.75)* asc_us_att_1.opts(color='#B34D93', alpha = 0.9)* asc_us_att_2.opts(color='#B34D93', alpha = 0.9)*\ | |
| asc_us_bdln_1.opts(color='#6AB35F', alpha = 0.75)* asc_us_bdln_2.opts(color='#6AB35F', alpha = 0.75)) | |
| return (ascus_bg* ref_vline * lab_vline*scatter_plot).opts(shared_axes=False) | |
| #elif column_changer =='Thyroid AUS Rate(%)': | |
| # scatter_plot = scatterdata[scatterdata.people.str.contains('Cytop', na=False)].hvplot.scatter(x=column_changer, y='people', color='black', size=sdot_size,height= sheight, | |
| # xlim=(0,30), xticks = [0,lab,10,15,30], grid=True, title=column_changer, | |
| # xformatter='%.0f',ylabel='',xlabel='',tools = [hover_cp]).opts(fontsize = pl_title,fontscale=f_scale_lab,shared_axes=False,toolbar=None, default_tools = []) | |
| # | |
| # aus_goal = hv.VSpan(0, 10).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| # aus_bdln = hv.VSpan(10,15).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| # aus_att = hv.VSpan(15, 30).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| # aus_bg = (aus_goal.opts(color='#ACFFA0', alpha = 0.75)* aus_att.opts(color='#B34D93', alpha = 0.9)*\ | |
| # aus_bdln.opts(color='#6AB35F', alpha = 0.75)) | |
| # | |
| # return (aus_bg* lab_vline * scatter_plot).opts(shared_axes=False) | |
| # | |
| elif column_changer == 'Abnormal Rate(%)': | |
| scatter_plot = scatterdata_filtered[scatterdata_filtered.people.str.contains('Cytot', na=False)].hvplot.scatter(x=column_changer, y='people', color='black', size=sdot_size,height= sheight, | |
| xlim=(0,max_x_abn), xticks = [0,lab,ref,3, max_x_abn], grid=True, title=column_changer, | |
| xformatter='%.1f',ylabel='', xlabel='',tools = [hover_cp]).opts(fontsize = pl_title,fontscale=f_scale_lab,shared_axes=False,toolbar=None, default_tools = []) | |
| asc_agc_goal = hv.VSpan(4.5, 6.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_agc_bdln_1 = hv.VSpan(2.5, 4.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_agc_bdln_2 = hv.VSpan(6.5, max_x_abn).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_agc_att = hv.VSpan(0, 2.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ascagc_bg = (asc_agc_goal.opts(color='#ACFFA0', alpha=0.75)* asc_agc_bdln_1.opts(color='#6AB35F', alpha=0.75) * \ | |
| asc_agc_bdln_2.opts(color='#6AB35F', alpha=0.75) *asc_agc_att.opts(color='#B34D93', alpha=0.9)) | |
| return (ascagc_bg* ref_vline * lab_vline*scatter_plot).opts(toolbar='above', default_tools=[]).opts(shared_axes=False) | |
| elif column_changer == 'Referral Rate(%)': | |
| scatter_plot = scatterdata_filtered[scatterdata_filtered.people.str.contains('Cytot', na=False)].hvplot.scatter(x=column_changer, y='people', color='black', size=sdot_size,height= sheight, | |
| xlim=(0,max_x+0.5), xticks = [0,lab, max_x], grid=True, title=column_changer, | |
| xformatter='%.1f',ylabel='', xlabel='',tools = [hover_cp]).opts(fontsize = pl_title,fontscale=f_scale_lab,shared_axes=False,toolbar=None, default_tools = []) | |
| ref_goal = hv.VSpan(7, 13).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_bdln_1 = hv.VSpan(5, 7).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_bdln_2 = hv.VSpan(13, 15).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_att_1 = hv.VSpan(15, max_x+0.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_att_2 = hv.VSpan(0, 5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_bg = (ref_goal.opts(color='#ACFFA0', alpha=0.75)* ref_bdln_1.opts(color='#6AB35F', alpha=0.75) * \ | |
| ref_bdln_2.opts(color='#6AB35F', alpha=0.75)) *ref_att_1.opts(color='#B34D93', alpha = 0.9) *\ | |
| ref_att_2.opts(color='#B34D93', alpha = 0.9) | |
| return (ref_bg * lab_vline * scatter_plot).opts(toolbar='above', default_tools=[]).opts(shared_axes=False) | |
| elif column_changer == 'hrHPV/ASC-US rate (%)': | |
| ref_value = 36.6 | |
| ref_hline = hv.HLine(y=ref_value).opts(color='black', alpha=1, line_width=2).opts(shared_axes=False, toolbar=None, default_tools=[]) | |
| line_plot = line_data.hvplot.line(x='year', y=column_changer, color='#5B91D1', line_dash ='dashed', line_width=2, height=600, title=column_changer, xlabel='Year', ylabel='hrHPV positivity (%)', tools=[hover_cp]).opts(fontsize=pl_title, fontscale=f_scale_lab, shared_axes=False, toolbar=None, default_tools=[], ylim=(10, 90)) | |
| selected_year = line_data[line_data['year'] == year_slider] | |
| point = hv.Points(selected_year, ['year', column_changer]).opts(color='black', size=20, marker='o', line_color='black') | |
| hpvascus_goal = hv.HSpan(30, 60).opts(shared_axes=False, toolbar=None, default_tools = []) | |
| hpvascus_bdln_1 = hv.HSpan(20, 30).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| hpvascus_bdln_2 = hv.HSpan(60, 70).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| hpvascus_att_1 = hv.HSpan(0, 20).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| hpvascus_att_2 = hv.HSpan(70, 100).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| hpvascus_bg = (hpvascus_goal.opts(color='#ACFFA0', alpha=0.75) * hpvascus_bdln_1.opts(color='#6AB35F', alpha=0.75) * hpvascus_bdln_2.opts(color='#6AB35F', alpha=0.75)) * hpvascus_att_1.opts(color='#B34D93', alpha = 0.9) * hpvascus_att_2.opts(color='#B34D93', alpha = 0.9) | |
| return (hpvascus_bg * ref_hline * line_plot * point).opts(toolbar='above', default_tools=[]).opts(shared_axes=False) | |
| elif column_changer == 'hrHPV Prevalence (%)': | |
| ref_value = 21 | |
| ref_hline = hv.HLine(y=ref_value).opts(color='black', alpha=1, line_width=2).opts(shared_axes=False, toolbar=None, default_tools=[]) | |
| line_plot = line_data.hvplot.line(x='year', y=column_changer, color='#5B91D1', line_dash ='dashed', line_width=2, height=600, title=column_changer, xlabel='Year', ylabel='hrHPV positivity (%)', tools=[hover_cp]).opts(fontsize=pl_title, fontscale=f_scale_lab, shared_axes=False, toolbar=None, default_tools=[], ylim=(0, 50)) | |
| selected_year = line_data[line_data['year'] == year_slider] | |
| point = hv.Points(selected_year, ['year', column_changer]).opts(color='black', size=20, marker='o', line_color='black') | |
| hpvprev_goal = hv.HSpan(11, 29).opts(shared_axes=False, toolbar=None, default_tools = []) | |
| hpvprev_bdln_1 = hv.HSpan(5, 11).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| hpvprev_bdln_2 = hv.HSpan(29, 35).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| hpvprev_att_1 = hv.HSpan(0, 5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| hpvprev_att_2 = hv.HSpan(35, 50).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| hpvprev_bg = (hpvprev_goal.opts(color='#ACFFA0', alpha=0.75) * hpvprev_bdln_1.opts(color='#6AB35F', alpha=0.75) * hpvprev_bdln_2.opts(color='#6AB35F', alpha=0.75)) * hpvprev_att_1.opts(color='#B34D93', alpha = 0.9) * hpvprev_att_2.opts(color='#B34D93', alpha = 0.9) | |
| return (hpvprev_bg * ref_hline * line_plot * point).opts(toolbar='above', default_tools=[]).opts(shared_axes=False) | |
| def add_no_cases_lab(year_slider): | |
| scatterdata = df[(df.year == year_slider)&(df.people.str.contains('KGYC'))].sort_values(by='year').reset_index(drop=True) | |
| gyncase_no = scatterdata['Number'].iloc[0] | |
| #thycase_no = scatterdata['ThyAC Number'].iloc[0] | |
| return pn.pane.Markdown(f""" **Case number: {gyncase_no}** """, | |
| styles = {'font-size':fpx}) | |
| interactive_no_lab = pn.bind(add_no_cases_lab, year_slider) | |
| interactive_func = pn.bind(lab_management, year_slider, column_changer) | |
| #COLORS (EGGPLANT): ['#ACFFA0','#6AB35F','#B34D93'] | |
| # In[9]: | |
| unique_values = df[df['people'].str.contains('Cytot', na=False)] | |
| unique_values = unique_values.sort_values(by='people',ascending=True,key=natsort_keygen()) | |
| technician_list = unique_values[~unique_values['people'].str.contains('Cytotechnologist 8', case=False, na=False)]['people'].unique().tolist() | |
| technician_list | |
| ct_select = pn.widgets.Select(name='Select', options=technician_list, value = 'Cytotechnologist 1', styles = mobile_style, width = 400, height=150, stylesheets= [select_style]) | |
| #Overviews | |
| # # CT ABNORMAL RATE OVERVIEW: | |
| def abnormal_rate_overview_ct(ct_select): | |
| ct_result = df[df['people'] == ct_select][['Abnormal Rate(%)','year']] | |
| if len(ct_result) > 1: | |
| last_result = ct_result['Abnormal Rate(%)'].iloc[-1] | |
| second_last_result = ct_result['Abnormal Rate(%)'].iloc[-2] | |
| last_year = ct_result['year'].iloc[-1] | |
| second_last_year = ct_result['year'].iloc[-2] | |
| if 4 < last_result < 7: | |
| ct_comment = f"Your latest result from **{last_year}** is within the laboratory goal zone **{last_result:.1f}**." | |
| ct_comment_2 = "" | |
| elif (2.5 < last_result < 4) or (7 < last_result < 8.5): | |
| ct_comment = f"Your latest record from **{last_year}** is in the laboratory borderline zone **{last_result:.1f}**." | |
| if last_result < second_last_result: | |
| ct_comment_2 = f"A decrease in the abnormal rate can be observed compared to your previous record **({second_last_result:.1f}%)** from **{second_last_year}**." | |
| else: | |
| ct_comment_2 ="" | |
| elif last_result < 2.5: | |
| ct_comment = f"Your latest registered result from **{last_year}** is **{last_result:.1f}%**, your abnormal rate is too low. You use the cytology abnormality categories to rarely, that means an elevated risk in overlooking them! " | |
| if last_result > second_last_result: | |
| ct_comment_2 = f"You performed better compared to your previous record **({second_last_result:.1f}%)** from **{second_last_year}**, but please consult with a cytopathologist." | |
| else: | |
| ct_comment_2 = f"<br>Please consult with a cytopathologist about your result since your abnormal rate worsened compared to your previous record **({second_last_result:.1f}%)** from **{second_last_year}**." | |
| elif last_result > 8.5: | |
| ct_comment = f"Your latest registered result from **{last_year}** is **{last_result:.1f}%**, your abnormal rate is too high. You are using the abnormality categories too much." | |
| if last_result < second_last_result: | |
| ct_comment_2 = f"You performed better compared to your previous record **({second_last_result:.1f}%)** from **{second_last_year}**, but please consult with a cytopathologist." | |
| else: | |
| ct_comment_2 = f"<br>Please consult with a cytopathologist about your result since your abnormal rate worsened compared to your previous record **({second_last_result:.1f}%)** from **{second_last_year}**." | |
| return pn.pane.Markdown(f""" | |
| ## Abnormal Rate Overview: | |
| **Description:** *The abnormal Rate represents the relative ratio of ASC, SIL and AGC diagnoses. Alterations ( Z Score: <-2) means a level of insecurity that requires attention.*<br><br> | |
| **Result:** {ct_comment} {ct_comment_2} | |
| """, sizing_mode ="stretch_width", styles={'font-size': fpx}) | |
| else: | |
| return pn.pane.Markdown(""" | |
| ### Not enough data to calculate parameters. | |
| """, styles={'font-size': '24px'}) | |
| inter_abnorm_ct = pn.bind(abnormal_rate_overview_ct, ct_select) | |
| # # CT ASCUS RATE OVERVIEW: | |
| def ascus_rate_overview_ct(ct_select): | |
| ct_result = df[df['people'] == ct_select][['ASC-US/ASC-H ratio(%)','year']] | |
| if len(ct_result) > 1: | |
| last_result = ct_result['ASC-US/ASC-H ratio(%)'].iloc[-1] | |
| last_year = ct_result['year'].iloc[-1] | |
| second_last_result = ct_result['ASC-US/ASC-H ratio(%)'].iloc[-2] | |
| second_last_year = ct_result['year'].iloc[-2] | |
| avg_zscore = zscore_eval.get_group('KGYC')['ASC-US/ASC-H ratio(%)'].mean() | |
| lab_ascus_reference = 90.0 - avg_zscore #Végül 95%-os CI-vel alkottam meg a bdl és att zónákat | |
| lab_asch_reference = 10.0 + avg_zscore | |
| sd_dev = 5 #(95% CI esetén) | |
| goal_zone = (lab_ascus_reference - sd_dev, lab_ascus_reference + sd_dev) | |
| borderline_zone = [(lab_ascus_reference - 2 * sd_dev, lab_ascus_reference - sd_dev), (lab_ascus_reference + sd_dev, lab_ascus_reference + 2 * sd_dev)] | |
| attention_zone = [(lab_ascus_reference - 2 * sd_dev, 0), (lab_ascus_reference + 2 * sd_dev, 100)] | |
| if goal_zone[0] <= last_result <= goal_zone[1]: | |
| ct_comment = f"Your latest result from **{last_year}** is within the laboratory goal zone **{last_result:.0f}%/{(100-last_result):.0f}%**." | |
| ct_comment_2 = "" | |
| elif any(lower <= last_result < upper for lower, upper in borderline_zone): | |
| ct_comment = f"Your latest record from **{last_year}** is in the laboratory borderline zone **{last_result:.0f}%/{(100-last_result):.0f}%**." | |
| if last_result < second_last_result: | |
| ct_comment_2 = f"A decrease in the ASC-US/ASC-H ratio can be observed since last record **({second_last_result:.0f}%/{(100-second_last_result):.0f}%)** from **{second_last_year}**." | |
| else: | |
| ct_comment_2 ="" | |
| elif any(lower <= last_result <= upper for lower, upper in attention_zone): | |
| ct_comment = f"Your latest registered result from **{last_year}** is **{last_result:.0f}%/{(100-last_result):.0f}%**, your ASC-US/ASC-H ratio is too low. You use the ASC-US category very rarely and/or you use the ASC-H category too often. " | |
| if last_result > second_last_result: | |
| ct_comment_2 = f"You performed better compared to your previous record **({second_last_result:.0f}%/{(100-second_last_result):.0f}%)** from **{second_last_year}**, but please consult with a cytopathologist." | |
| else: | |
| ct_comment_2 = f"<br>Please consult with a cytopathologist about your result since your ASC-US/ASC-H ratio worsened since your last record **({second_last_result:.0f}%/{(100-second_last_result):.0f}%)** from **{second_last_year}**." | |
| return pn.pane.Markdown(f""" | |
| ## ASC-US/ASC-H ratio Overview: | |
| **Description:** *ASC-US/ASC-H ratio literature reference value 90% / 10%. Given our average laboratory Z score of {avg_zscore:.2f}, the laboratory's average ratio is {lab_ascus_reference:.2f}% / {lab_asch_reference:.2f}%.* <br> | |
| Given our average laboratory Z score, the goal, borderline, and attention zones calculated with 95% CI are the following: **Goal Zone:** {goal_zone[0]:.2f} to {goal_zone[1]:.2f}, **Borderline Zone:** {borderline_zone[0][0]:.2f} to {borderline_zone[0][1]:.2f} and {borderline_zone[1][0]:.2f} to {borderline_zone[1][1]:.2f}, **Attention Zone:** {attention_zone[0][0]:.2f} to {attention_zone[0][1]:.2f} and {attention_zone[1][0]:.2f} to {attention_zone[1][1]:.2f}. <br><br> | |
| **Result:** {ct_comment} {ct_comment_2} | |
| """, sizing_mode ="stretch_width", styles={'font-size': fpx}) | |
| else: | |
| return None | |
| inter_ascus_ct = pn.bind(ascus_rate_overview_ct, ct_select) | |
| # # CT ASC/LSIL OVERVIEW: | |
| def asclsil_rate_overview_ct(ct_select): | |
| ct_result = df[df['people'] == ct_select][['ASC/LSIL','year']] | |
| if len(ct_result) > 1: | |
| last_result = ct_result['ASC/LSIL'].iloc[-1] | |
| second_last_result = ct_result['ASC/LSIL'].iloc[-2] | |
| last_year = ct_result['year'].iloc[-1] | |
| second_last_year = ct_result['year'].iloc[-2] | |
| if 1.5 < last_result < 3: | |
| ct_comment = f"Your latest result from **{last_year}** is within the laboratory goal zone **{last_result:.1f}**." | |
| ct_comment_2 = "" | |
| elif last_result < 1.5: | |
| ct_comment = f"Your latest record from **{last_year}** is in the laboratory borderline zone **{last_result:.1f}**. This means your ASC/LSIL is low, and there is a higher risk of you overlooking abnormalities." | |
| if last_result < second_last_result: | |
| ct_comment_2 = f"A decrease in the ASC/LSIL ratio can be observed since last record **({second_last_result:.1f})** from **{second_last_year}**. Please consult with a cytopathologist" | |
| else: | |
| ct_comment_2 ="" | |
| elif 3 < last_result < 3.75: | |
| ct_comment = f"Your latest record from **{last_year}**is in the laboratory borderline zone **{last_result:.1f}**." | |
| if last_result > second_last_result: | |
| ct_comment_2 = f"An increase in the ASC/LSIL ratio can be observed since last record **({second_last_result:.1f})** from **{second_last_year}**." | |
| else: | |
| ct_comment_2 ="" | |
| elif last_result > 3.75: | |
| ct_comment = f"Your latest registered result from **{last_year}** is **{last_result:.1f}**, your ASC/LSIL ratio is too high. You use the ASC category too often. " | |
| if last_result < second_last_result: | |
| ct_comment_2 = f"You performed better compared to your previous record **({second_last_result:.1f})** from **{second_last_year}**, but please consult with a cytopathologist." | |
| else: | |
| ct_comment_2 = f"<br>Please consult with a cytopathologist about your result since your ASC/LSIL ratio worsened since your last record **({second_last_result:.1f})** from **{second_last_year}**." | |
| return pn.pane.Markdown(f""" | |
| ## ASC/LSIL Overview: | |
| **Description:** *ASC/LSIL value represents the ASC-US, ASC-H diagnoses compared to LSIL diagnoses. Considerable elevation (Z Score > 2) from reference value {df.iat[0,5]} requires attention. A lower result than 1.5 could imply an increase in false negative interpretations.*<br><br> | |
| **Result:** {ct_comment} {ct_comment_2} | |
| """, sizing_mode ="stretch_width", styles={'font-size': fpx}) | |
| else: | |
| return None | |
| inter_asclsil_ct = pn.bind(asclsil_rate_overview_ct, ct_select) | |
| # # CT REFERRAL OVERVIEW | |
| # In[50]: | |
| def referral_rate_overview_ct(ct_select): | |
| ct_result = df[df['people'] == ct_select][['Referral Rate(%)','year']] | |
| if len(ct_result) > 1: | |
| last_result = ct_result['Referral Rate(%)'].iloc[len(ct_result)-1] | |
| second_last_result = ct_result['Referral Rate(%)'].iloc[-2] | |
| last_year = ct_result['year'].iloc[-1] | |
| second_last_year = ct_result['year'].iloc[-2] | |
| if 7 < last_result < 13: | |
| ct_comment = f"Your latest result from **{last_year}** is within the laboratory goal zone **{last_result:.1f}%**." | |
| ct_comment_2 = "" | |
| elif 5 < last_result < 7: | |
| ct_comment = f"Your latest record from **{last_year}** is in the laboratory borderline zone **{last_result:.1f}%**." | |
| if last_result < second_last_result: | |
| ct_comment_2 = f"An underreferral tendency can be observed since your last record **({second_last_result:.f}%)** from **{second_last_year}**." | |
| else: | |
| ct_comment_2 ="" | |
| elif 13 < last_result < 15: | |
| ct_comment = f"Your latest record from **{last_year}** is in the laboratory borderline zone **{last_result:.1f}%**." | |
| if last_result > second_last_result: | |
| ct_comment_2 = f"An overreferral tendency can be observed since your last record **({second_last_result:.f}%)** from **{second_last_year}**." | |
| else: | |
| ct_comment_2 ="" | |
| elif last_result < 5: | |
| ct_comment = f"Your latest registered result from **{last_year}** is **{last_result:.1f}%**, your referral rate is too low. You might overlook cytology abnormalities! " | |
| if last_result > second_last_result: | |
| ct_comment_2 = f"You performed better compared to your previous record **({second_last_result:.1f}%)** from **{second_last_year}**. Please consult with a cytopathologist about your result." | |
| else: | |
| ct_comment_2 = f"<br>Please consult with a cytopathologist about your result since your referral rate worsened since your previous record **({second_last_result:.1f}%)** from **{second_last_year}**." | |
| elif last_result > 15: | |
| ct_comment = f"Your latest registered result is **{last_result:.1f}%** from **{last_year}**, your referral rate is high." | |
| ct_comment_2 = "" | |
| return pn.pane.Markdown(f""" | |
| ## Referral Rate Overview: | |
| **Description:** *Referral Rate signifies the ratio the Cytotechnologist consults cases. < 5% or > 15% requires attention.*<br><br> | |
| **Result:** {ct_comment} {ct_comment_2} | |
| """, sizing_mode ="stretch_width", styles={'font-size': fpx}) | |
| else: | |
| return None | |
| inter_referral_ct = pn.bind(referral_rate_overview_ct, ct_select) | |
| # In[10]: | |
| def update_scatter_ct(year_slider,ct_select): | |
| scatterdata = df[(df.year == year_slider)&(df['people'] == ct_select)] | |
| if len(scatterdata) > 0: | |
| labdata = df[df.year == year_slider] | |
| avg_zscore = zscore_eval.get_group('KGYC')['ASC-US/ASC-H ratio(%)'].mean() | |
| lab_ascus_reference = 90.0 - avg_zscore #Végül 95%-os CI-vel alkottam meg a bdl és att zónákat | |
| lab_asch_reference = 10.0 + avg_zscore | |
| sd_dev = 5 #(95% CI esetén) | |
| goal_zone = (lab_ascus_reference - sd_dev, lab_ascus_reference + sd_dev) | |
| borderline_zone = [(lab_ascus_reference - 2 * sd_dev, lab_ascus_reference - sd_dev), (lab_ascus_reference + sd_dev, lab_ascus_reference + 2 * sd_dev)] | |
| attention_zone = [(lab_ascus_reference - 2 * sd_dev, 0), (lab_ascus_reference + 2 * sd_dev, 100)] | |
| #ASC/#LSIL | |
| ref_lsil = df['ASC/LSIL'].iloc[0] | |
| lab_lsil = labdata.iloc[0]['ASC/LSIL'] | |
| max_x_lsil = labdata['ASC/LSIL'].max() | |
| tooltips_asc_lsil = f"""<div><span style="font-size: {fpx}; font-weight: bold">@{{ASC/LSIL}} </span></div>""" | |
| hover_asc_lsil = HoverTool(tooltips=tooltips_asc_lsil) | |
| scatter_lsil = scatterdata.iloc[0:1].hvplot.scatter(x='ASC/LSIL', y='people', color='black', size=sdot_person,height= 160, width=800, | |
| xlim=(0,max_x_lsil+0.5), xticks = [0,lab_lsil,ref_lsil, 5], yaxis = 'bare',grid=True, title='ASC/LSIL', | |
| xformatter='%.1f',xlabel ='', ylabel='', tools = [hover_asc_lsil]).opts(fontsize = pl_title,shared_axes=False,toolbar=None, default_tools = []) | |
| ref_lsil_vline = hv.VLine(x=ref_lsil).opts(color='black', alpha = 1).opts(fontscale=f_scale, shared_axes=False,toolbar=None, default_tools = []) | |
| lab_lsil_vline = hv.VLine(x=lab_lsil).opts(color='#5B91D1', line_dash ='dashed', alpha = 1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_goal = hv.VSpan(1.5, 3).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_bdln_1 = hv.VSpan(3, 3.75).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_bdln_2 = hv.VSpan(0, 1.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_att = hv.VSpan(3.75, 15).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asclsil_bg =(asc_lsil_goal.opts(color='#ACFFA0', alpha=0.75) * asc_lsil_bdln_2.opts(color='#6AB35F', alpha=0.75) * asc_lsil_bdln_1.opts(color='#6AB35F', alpha=0.75) * asc_lsil_att.opts(color='#B34D93', alpha=0.9)) | |
| #ASC-US/ASC-H ratio(%) | |
| ref_ascus = df['ASC-US/ASC-H ratio(%)'].iloc[0] | |
| lab_ascus = labdata['ASC-US/ASC-H ratio(%)'].iloc[0] | |
| max_x_ascus = labdata['ASC-US/ASC-H ratio(%)'].max() | |
| min_x_ascus = labdata['ASC-US/ASC-H ratio(%)'].min() | |
| tooltips_ascus = f"""<div><span style="font-size: {fpx};font-weight: bold">@{{ASC-US/ASC-H ratio(%)}} </span></div>""" | |
| hover_ascus = HoverTool(tooltips=tooltips_ascus) | |
| scatter_ascus = scatterdata.iloc[0:1].hvplot.scatter(x='ASC-US/ASC-H ratio(%)', y='people', color='black', size=sdot_person,height= 160, width=800, | |
| xlim=(17,100), xticks = [min_x_ascus,lab_ascus,ref_ascus, 100], yaxis = 'bare', grid=True, title='ASC-US/ASC-H ratio(%)', | |
| xformatter='%.0f',xlabel ='', ylabel='', tools = [hover_ascus]).opts(fontsize = pl_title,shared_axes=False,toolbar=None, default_tools = []) | |
| ref_ascus_vline = hv.VLine(x=ref_ascus).opts(color='black', alpha = 1).opts(fontscale=f_scale, shared_axes=False,toolbar=None, default_tools = []) | |
| lab_ascus_vline = hv.VLine(x=lab_ascus).opts(color='#5B91D1', line_dash ='dashed', alpha = 1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_goal = hv.VSpan(float(goal_zone[0]), float(goal_zone[1])).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_bdln_1 = hv.VSpan(float(borderline_zone[1][0]), float(borderline_zone[1][1])).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_bdln_2 = hv.VSpan(float(borderline_zone[0][0]), float(borderline_zone[0][1])).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_att_1 = hv.VSpan(float(attention_zone[0][0]), float(attention_zone[0][1])).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_att_2 = hv.VSpan(float(attention_zone[1][0]), float(attention_zone[1][1])).opts(shared_axes=False, toolbar=None, default_tools=[]) | |
| ascus_bg = (asc_us_goal.opts(color='#ACFFA0', alpha = 0.75)* asc_us_att_1.opts(color='#B34D93', alpha = 0.9)* asc_us_att_2.opts(color='#B34D93', alpha = 0.9)*\ | |
| asc_us_bdln_1.opts(color='#6AB35F', alpha = 0.75)* asc_us_bdln_2.opts(color='#6AB35F', alpha = 0.75)) | |
| #LSIL, ASC-US, AGC(%) | |
| ref_agc = df['Abnormal Rate(%)'].iloc[0] | |
| lab_agc = labdata['Abnormal Rate(%)'].iloc[0] | |
| max_x_agc = labdata[labdata.people.str.contains('ytolog')]['Abnormal Rate(%)'].max() | |
| tooltips_agc = f"""<div><span style="font-size: {fpx};font-weight: bold">@{{Abnormal Rate(%)}} </span></div>""" | |
| hover_agc = HoverTool(tooltips=tooltips_agc) | |
| scatter_agc = scatterdata.iloc[0:1].hvplot.scatter(x='Abnormal Rate(%)', y='people', color='black', size=sdot_person,height= 160, width=800, | |
| xlim=(0,max_x_agc), xticks = [0,lab_agc,ref_agc], yaxis = 'bare',grid=True, title='Abnormal Rate(%)', | |
| xformatter='%.1f',xlabel ='', ylabel='', tools= [hover_agc]).opts(fontsize = pl_title,shared_axes=False,toolbar=None, default_tools = []) | |
| ref_agc_vline = hv.VLine(x=ref_agc).opts(color='black', alpha = 1).opts(fontscale=f_scale, shared_axes=False,toolbar=None, default_tools = []) | |
| lab_agc_vline = hv.VLine(x=lab_agc).opts(color='#5B91D1', line_dash ='dashed', alpha = 1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_agc_goal = hv.VSpan(4.5, 6.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_agc_bdln_1 = hv.VSpan(2.5, 4.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_agc_bdln_2 = hv.VSpan(6.5, max_x_agc).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_agc_att = hv.VSpan(0, 2.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ascagc_bg = (asc_agc_goal.opts(color='#ACFFA0', alpha=0.75)* asc_agc_bdln_1.opts(color='#6AB35F', alpha=0.75) * \ | |
| asc_agc_bdln_2.opts(color='#6AB35F', alpha=0.75) *asc_agc_att.opts(color='#B34D93', alpha=0.9)) | |
| #Referral Rate(%) | |
| scatterdata_filtered = scatterdata[~scatterdata['people'].str.contains('Cytotechnologist 8', case=False, na=False)] | |
| labdata_filtered = labdata[~labdata['people'].str.contains('Cytotechnologist 8', case=False, na=False)] | |
| lab_ref_rate = labdata_filtered['Referral Rate(%)'].iloc[0] | |
| max_x_ref_rate = labdata_filtered['Referral Rate(%)'].max() | |
| tooltips_ref = f"""<div><span style="font-size: {fpx};font-weight: bold">@{{Referral Rate(%)}} </span></div>""" | |
| hover_ref = HoverTool(tooltips=tooltips_ref) | |
| scatter_ref_rate = scatterdata_filtered.iloc[0:1].hvplot.scatter(x='Referral Rate(%)', y='people', color='black', size=sdot_person,height= 160, width=800, | |
| xlim=(0,max_x_ref_rate+1), xticks = [0,lab_ref_rate,max_x_ref_rate], yaxis = 'bare',grid=True, title='Referral Rate(%)', | |
| xformatter='%.1f',xlabel ='', ylabel='', tools = [hover_ref]).opts(fontsize = pl_title,fontscale=f_scale, shared_axes=False,toolbar=None, default_tools = []) | |
| lab_ref_rate_vline = hv.VLine(x=lab_ref_rate).opts(color='#5B91D1', line_dash ='dashed', alpha = 1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_goal = hv.VSpan(7, 13).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_bdln_1 = hv.VSpan(5, 7).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_bdln_2 = hv.VSpan(13, 15).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_att_1 = hv.VSpan(15, max_x_ref_rate+1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_att_2 = hv.VSpan(0, 5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| ref_bg = ref_goal.opts(color='#ACFFA0', alpha=0.75)* ref_bdln_1.opts(color='#6AB35F', alpha=0.75) * \ | |
| ref_bdln_2.opts(color='#6AB35F', alpha=0.75) *ref_att_1.opts(color='#B34D93', alpha=0.9)*\ | |
| ref_att_2.opts(color='#B34D93', alpha=0.9) | |
| return ((asclsil_bg* ref_lsil_vline * lab_lsil_vline * scatter_lsil).opts(toolbar='above') +\ | |
| (ascus_bg* ref_ascus_vline * lab_ascus_vline*scatter_ascus) +\ | |
| (ascagc_bg* ref_agc_vline * lab_agc_vline*scatter_agc) + \ | |
| (ref_bg * lab_ref_rate_vline * scatter_ref_rate)).opts(shared_axes=False).cols(1) | |
| else: | |
| return pn.pane.Markdown('# N/A', styles = {'font-size':'20px'}) | |
| #COLORS (EGGPLANT): ['#ACFFA0','#6AB35F','#B34D93'] | |
| def add_no_cases_ct(year_slider,ct_select): | |
| scatterdata = df[(df.year == year_slider)&(df['people'] == ct_select)] | |
| if len(scatterdata) > 0: | |
| case_no = scatterdata['Number'].iloc[0] | |
| return pn.pane.Markdown(f'# Cases examined: {case_no}') | |
| else: | |
| return None | |
| interactive_no_ct = pn.bind(add_no_cases_ct,year_slider, ct_select) | |
| interactive_qa_ct = pn.bind(update_scatter_ct,year_slider, ct_select) | |
| ct_performance = pn.Tabs(('Performance results',pn.Column(pn.Row(ct_select, year_slider), interactive_no_ct, \ | |
| pn.Row(pn.Column(pn.pane.Markdown("<br><br><br>"),vertical_legend_indiv),interactive_qa_ct, height = 600),\ | |
| pn.Column(pn.pane.Markdown("<br><br><br>"),modal_btn))),\ | |
| ('Results overview',pn.Column(ct_select, inter_asclsil_ct, inter_ascus_ct, inter_abnorm_ct, inter_referral_ct)),styles = {'font-size': '20px'}) | |
| # In[11]: | |
| unique_values_cp = df[df['people'].str.contains('Cytopath', na=False)] | |
| unique_values_cp = unique_values_cp.sort_values(by='people',ascending=True,key=natsort_keygen()) | |
| citopath_list = unique_values_cp['people'].unique().tolist() | |
| cp_select = pn.widgets.Select(name='Select', options=citopath_list, value ='Cytopathologist 1', styles = mobile_style, stylesheets= [select_style], width = 400, height = 150) | |
| # # CP ASCUS RATE OVERVIEW: | |
| def ascus_rate_overview_cp(cp_select): | |
| ct_result = df[df['people'] == cp_select][['ASC-US/ASC-H ratio(%)','year']] | |
| if len(ct_result) > 1: | |
| last_result = ct_result['ASC-US/ASC-H ratio(%)'].iloc[-1] | |
| last_year = ct_result['year'].iloc[-1] | |
| second_last_result = ct_result['ASC-US/ASC-H ratio(%)'].iloc[-2] | |
| second_last_year = ct_result['year'].iloc[-2] | |
| avg_zscore = zscore_eval.get_group('KGYC')['ASC-US/ASC-H ratio(%)'].mean() | |
| lab_ascus_reference = 90.0 - avg_zscore #Végül 95%-os CI-vel alkottam meg a bdl és att zónákat | |
| lab_asch_reference = 10.0 + avg_zscore | |
| sd_dev = 5 #(95% CI esetén) | |
| goal_zone = (lab_ascus_reference - sd_dev, lab_ascus_reference + sd_dev) | |
| borderline_zone = [(lab_ascus_reference - 2 * sd_dev, lab_ascus_reference - sd_dev), (lab_ascus_reference + sd_dev, lab_ascus_reference + 2 * sd_dev)] | |
| attention_zone = [(lab_ascus_reference - 2 * sd_dev, 0), (lab_ascus_reference + 2 * sd_dev, 100)] | |
| if goal_zone[0] <= last_result <= goal_zone[1]: | |
| ct_comment = f"Your latest result from **{last_year}** is within the laboratory goal zone **{last_result:.0f}%/{(100-last_result):.0f}%**." | |
| ct_comment_2 = "" | |
| elif any(lower <= last_result < upper for lower, upper in borderline_zone): | |
| ct_comment = f"Your latest record from **{last_year}** is in the laboratory borderline zone **{last_result:.0f}%/{(100-last_result):.0f}%**." | |
| if last_result < second_last_result: | |
| ct_comment_2 = f"A decrease in the ASC-US/ASC-H ratio can be observed since last record **({second_last_result:.0f}%/{(100-second_last_result):.0f}%)** from **{second_last_year}**." | |
| else: | |
| ct_comment_2 ="" | |
| elif any(lower <= last_result < upper for lower, upper in attention_zone): | |
| ct_comment = f"Your latest registered result from **{last_year}** is **{last_result:.0f}%/{(100-last_result):.0f}%**, your ASC-US/ASC-H ratio is too low. You use the ASC-US category very rarely and/or you use the ASC-H category too often. " | |
| if last_result > second_last_result: | |
| ct_comment_2 = f"You performed better compared to your previous record **({second_last_result:.0f}%/{(100-second_last_result):.0f}%)** from **{second_last_year}**, but please consult with a cytopathologist." | |
| else: | |
| ct_comment_2 = f"<br>Please consult with a cytopathologist about your result since your ASC-US/ASC-H ratio worsened since your last record **({second_last_result:.0f}%/{(100-second_last_result):.0f}%)** from **{second_last_year}**." | |
| return pn.pane.Markdown(f""" | |
| ## ASC-US/ASC-H ratio Overview: | |
| **Description:** *ASC-US/ASC-H ratio literature reference value 90% / 10%. Given our average laboratory Z score of {avg_zscore:.2f}, the laboratory's average ratio is {lab_ascus_reference:.2f}% / {lab_asch_reference:.2f}%.* <br> | |
| Given our average laboratory Z score, the goal, borderline, and attention zones calculated with 95% CI are the following: **Goal Zone:** {goal_zone[0]:.2f} to {goal_zone[1]:.2f}, **Borderline Zone:** {borderline_zone[0][0]:.2f} to {borderline_zone[0][1]:.2f} and {borderline_zone[1][0]:.2f} to {borderline_zone[1][1]:.2f}, **Attention Zone:** {attention_zone[0][0]:.2f} to {attention_zone[0][1]:.2f} and {attention_zone[1][0]:.2f} to {attention_zone[1][1]:.2f}. <br><br> | |
| **Result:** {ct_comment} {ct_comment_2} | |
| """, sizing_mode ="stretch_width", styles={'font-size': fpx}) | |
| else: | |
| return None | |
| inter_ascus_cp = pn.bind(ascus_rate_overview_ct, cp_select) | |
| # # CP ASC/LSIL OVERVIEW: | |
| def asclsil_rate_overview_cp(cp_select): | |
| ct_result = df[df['people'] == cp_select][['ASC/LSIL','year']] | |
| if len(ct_result) > 1: | |
| last_result = ct_result['ASC/LSIL'].iloc[-1] | |
| second_last_result = ct_result['ASC/LSIL'].iloc[-2] | |
| last_year = ct_result['year'].iloc[-1] | |
| second_last_year = ct_result['year'].iloc[-2] | |
| if 1.5 < last_result < 3: | |
| ct_comment = f"Your latest result from **{last_year}** is within the laboratory goal zone **{last_result:.1f}**." | |
| ct_comment_2 = "" | |
| elif last_result < 1.5: | |
| ct_comment = f"Your latest record from **{last_year}** is in the laboratory borderline zone **{last_result:.1f}**." | |
| if last_result < second_last_result: | |
| ct_comment_2 = f"A decrease in the ASC/LSIL ratio can be observed since last record **({second_last_result:.1f})** from **{second_last_year}**. Please consult with a cytopathologist." | |
| else: | |
| ct_comment_2 ="" | |
| elif 3 < last_result < 3.75: | |
| ct_comment = f"Your latest record from **{last_year}** is in the laboratory borderline zone **{last_result:.1f}**." | |
| if last_result > second_last_result: | |
| ct_comment_2 = f"An increase in the ASC/LSIL ratio can be observed since previous record **({second_last_result:.1f})** from **{second_last_year}**." | |
| else: | |
| ct_comment_2 ="" | |
| elif last_result > 3.75: | |
| ct_comment = f"Your latest registered result from **{last_year}** is **{last_result:.1f}**, your ASC/LSIL ratio is too high. You use the ASC category too often. " | |
| if last_result < second_last_result: | |
| ct_comment_2 = f"You performed better compared to your previous record **({second_last_result:.1f})** from **{second_last_year}**, but please consult with a cytopathologist." | |
| else: | |
| ct_comment_2 = f"<br>Please consult with a cytopathologist about your result since your ASC/LSIL ratio worsened since your last record **({second_last_result:.1f})** from **{second_last_year}**." | |
| return pn.pane.Markdown(f""" | |
| ## ASC/LSIL Overview: | |
| **Description:** *ASC/LSIL value represents the ASC-US, ASC-H diagnoses compared to LSIL diagnoses. Considerable elevation (Z Score > 2) from reference value {df.iat[0,5]} requires attention. A lower result than 1.5 could imply an increase in false negative interpretations.*<br><br> | |
| **Result:** {ct_comment} {ct_comment_2} | |
| """, sizing_mode ="stretch_width", styles={'font-size': fpx}) | |
| else: | |
| return pn.pane.Markdown(""" | |
| ## Not enough data to calculate parameters. | |
| """, styles = {'font-size':fpx}) | |
| inter_asclsil_cp = pn.bind(asclsil_rate_overview_cp, cp_select) | |
| # # CP THYROID AUS RATE OVERVIEW | |
| # In[57]: | |
| #def thyroid_rate_overview_cp(cp_select): | |
| # ct_result = df[df['people'] == cp_select][['Thyroid AUS Rate(%)','year']] | |
| # if ct_result['Thyroid AUS Rate(%)'].sum() > 0.0: | |
| # | |
| # if len(ct_result) > 1: | |
| # last_result = ct_result['Thyroid AUS Rate(%)'].iloc[-1] | |
| # second_last_result = ct_result['Thyroid AUS Rate(%)'].iloc[-2] | |
| # last_year = ct_result['year'].iloc[-1] | |
| # second_last_year = ct_result['year'].iloc[-2] | |
| # if 0 < last_result < 10: | |
| # ct_comment = f"Your latest result from **{last_year}** is within the laboratory goal zone **{last_result:.1f}%**." | |
| # ct_comment_2 = "" | |
| # elif 10 <last_result < 15: | |
| # ct_comment = f"Your latest record from **{last_year}** is in the laboratory borderline zone **{last_result:.1f}%**." | |
| # if last_result > second_last_result: | |
| # ct_comment_2 = f"A decrease in the thyroid AUS ratio can be observed compared to your previous record **({second_last_result:.1f}%)** from **{second_last_year}**." | |
| # else: | |
| # ct_comment_2 ="" | |
| #elif last_result > 15: | |
| # ct_comment = f"Your latest registered result from **{last_year}** is **{last_result:.1f}%**, your thyroid AUS ratio is too high. You use the AUS (TBS 3) category too much. " | |
| # if last_result < second_last_result: | |
| # ct_comment_2 = f"You performed better compared to your previous record **({second_last_result:.1f}%)** from **{second_last_year}**, but please consult with an experienced cytopathologist." | |
| #else: | |
| # ct_comment_2 = f"<br>Please consult with an experienced cytopathologist about your result since your thyroid AUS ratio worsened compared to your previous record **({second_last_result:.1f}%)** from **{second_last_year}**." | |
| # | |
| # | |
| # | |
| # return pn.pane.Markdown(f""" | |
| # ## Thyroid AUS Rate(%) Overview: | |
| # *Thyroid AUS Rate signifies the ratio of TBS 3 cytology reports. More than 15% requires attention.* <br><br> | |
| # {ct_comment} {ct_comment_2} | |
| # """, sizing_mode ="stretch_width", styles = {'font-size':fpx}) | |
| # else: | |
| # return pn.pane.Markdown(""" | |
| # ## Not enough data to calculate parameters. | |
| # """, styles = {'font-size':fpx}) | |
| #else: | |
| # return pn.pane.Markdown(""" | |
| # ## Current cytopathologist doesn't examine thyroid FNA cases. | |
| # """, styles = {'font-size':fpx}) | |
| #inter_thyroid_cp = pn.bind(thyroid_rate_overview_cp, cp_select) | |
| # In[12]: | |
| # In[13]: | |
| def update_scatter(year_slider,cp_select): | |
| avg_zscore = zscore_eval.get_group('KGYC')['ASC-US/ASC-H ratio(%)'].mean() | |
| lab_ascus_reference = 90.0 - avg_zscore #Végül 95%-os CI-vel alkottam meg a bdl és att zónákat | |
| lab_asch_reference = 10.0 + avg_zscore | |
| sd_dev = 5 #(95% CI esetén) | |
| goal_zone = (lab_ascus_reference - sd_dev, lab_ascus_reference + sd_dev) | |
| borderline_zone = [(lab_ascus_reference - 2 * sd_dev, lab_ascus_reference - sd_dev), (lab_ascus_reference + sd_dev, lab_ascus_reference + 2 * sd_dev)] | |
| attention_zone = [(lab_ascus_reference - 2 * sd_dev, 0), (lab_ascus_reference + 2 * sd_dev, 100)] | |
| scatterdata = df[(df.year == year_slider)&(df['people'] == cp_select)] | |
| if len(scatterdata) > 0: | |
| #thy_exist = scatterdata['Thyroid AUS Rate(%)'].iloc[0] | |
| labdata = df[(df.year == year_slider)] | |
| ref_lsil = df['ASC/LSIL'].iloc[0] | |
| lab_lsil = labdata['ASC/LSIL'].iloc[0] | |
| max_x_lsil = labdata['ASC/LSIL'].max() | |
| xlim = (0, max_x_lsil) if max_x_lsil > 7 else (0,7) | |
| xticks = [0,lab_lsil,ref_lsil, max_x_lsil] | |
| tooltips_asc_lsil = f"""<div><span style="font-size: {fpx};font-weight: bold">@{{ASC/LSIL}} </span></div>""" | |
| hover_asc_lsil = HoverTool(tooltips=tooltips_asc_lsil) | |
| scatter_lsil = scatterdata.iloc[0:1].hvplot.scatter(x='ASC/LSIL', y='people', color='black', size=sdot_person,height= 160, width=800, | |
| xlim=xlim, xticks = xticks, yaxis = 'bare',grid=True, title='ASC/LSIL', | |
| xformatter='%.1f',xlabel ='', ylabel='', tools = [hover_asc_lsil]).opts(fontsize = pl_title,fontscale=f_scale, shared_axes=False,toolbar=None, default_tools = []) | |
| ref_lsil_vline = hv.VLine(x=ref_lsil).opts(color='black', alpha = 1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| lab_lsil_vline = hv.VLine(x=lab_lsil).opts(color='#5B91D1', line_dash ='dashed', alpha=1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_goal = hv.VSpan(1.5, 3).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_bdln_1 = hv.VSpan(3, 3.75).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_bdln_2 = hv.VSpan(0, 1.5).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_lsil_att = hv.VSpan(3.75, 15).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asclsil_bg =(asc_lsil_goal.opts(color='#ACFFA0', alpha =0.75) * asc_lsil_bdln_2.opts(color='#6AB35F', alpha =0.75) * asc_lsil_bdln_1.opts(color='#6AB35F', alpha =0.75) * asc_lsil_att.opts(color='#B34D93', alpha =0.9)) | |
| ref_ascus = df['ASC-US/ASC-H ratio(%)'].iloc[0] | |
| lab_ascus = labdata['ASC-US/ASC-H ratio(%)'].iloc[0] | |
| max_x_ascus = labdata['ASC-US/ASC-H ratio(%)'].max() | |
| min_x_ascus = labdata['ASC-US/ASC-H ratio(%)'].min() | |
| tooltips_ascus = f"""<div><span style="font-size: {fpx};font-weight: bold">@{{ASC-US/ASC-H ratio(%)}} </span></div>""" | |
| hover_ascus = HoverTool(tooltips=tooltips_ascus) | |
| scatter_ascus = scatterdata.iloc[0:1].hvplot.scatter(x='ASC-US/ASC-H ratio(%)', y='people', color='black', size=sdot_person,height= 160, width=800, | |
| xlim=(17,100), xticks = [min_x_ascus,lab_ascus,ref_ascus, 100], yaxis = 'bare', grid=True, title='ASC-US/ASC-H ratio(%)', | |
| xformatter='%.0f',xlabel ='', ylabel='', tools=[hover_ascus]).opts(fontsize = pl_title,fontscale=f_scale, shared_axes=False,toolbar=None, default_tools = []) | |
| ref_ascus_vline = hv.VLine(x=ref_ascus).opts(color='black', alpha = 1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| lab_ascus_vline = hv.VLine(x=lab_ascus).opts(color='#5B91D1', line_dash ='dashed', alpha=1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_goal = hv.VSpan(float(goal_zone[0]), float(goal_zone[1])).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_bdln_1 = hv.VSpan(float(borderline_zone[1][0]), float(borderline_zone[1][1])).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_bdln_2 = hv.VSpan(float(borderline_zone[0][0]), float(borderline_zone[0][1])).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_att_1 = hv.VSpan(float(attention_zone[0][0]), float(attention_zone[0][1])).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| asc_us_att_2 = hv.VSpan(float(attention_zone[1][0]), float(attention_zone[1][1])).opts(shared_axes=False, toolbar=None, default_tools=[]) | |
| ascus_bg = (asc_us_goal.opts(color='#ACFFA0', alpha = 0.75)* asc_us_att_1.opts(color='#B34D93', alpha = 0.9)* asc_us_att_2.opts(color='#B34D93', alpha = 0.9)*\ | |
| asc_us_bdln_1.opts(color='#6AB35F', alpha = 0.75)* asc_us_bdln_2.opts(color='#6AB35F', alpha = 0.75)) | |
| #if pd.isna(scatterdata['Thyroid AUS Rate(%)'].iloc[0]): | |
| # return ((asclsil_bg* ref_lsil_vline * lab_lsil_vline * scatter_lsil).opts(toolbar='above') +\ | |
| # (ascus_bg* ref_ascus_vline * lab_ascus_vline*scatter_ascus).opts(toolbar='above')).cols(1).opts(shared_axes=False) | |
| #else: | |
| # ref_aus = df['Thyroid AUS Rate(%)'].iloc[0] | |
| # lab_aus = labdata['Thyroid AUS Rate(%)'].iloc[0] | |
| # max_x_aus = labdata['Thyroid AUS Rate(%)'].max() | |
| # tooltips_aus = f"""<div><span style="font-size: {fpx};font-weight: bold">@{{Thyroid AUS Rate(%)}} </span></div>""" | |
| # hover_aus = HoverTool(tooltips=tooltips_aus) | |
| # scatter_aus = scatterdata.iloc[0:1].hvplot.scatter(x='Thyroid AUS Rate(%)', y='people', color='black', size=sdot_person,height= 160, | |
| # xlim=(0,30), xticks = [0,lab_aus,10,15,30], yaxis = 'bare',grid=True, title='Thyroid AUS Rate(%)', | |
| # xformatter='%.1f',xlabel ='', ylabel='', tools = [hover_aus]).opts(fontsize = pl_title,fontscale=f_scale, shared_axes=False,toolbar=None, default_tools = []) | |
| # lab_aus_vline = hv.VLine(x=lab_aus).opts(color='#5B91D1', line_dash ='dashed', alpha=1).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| # aus_goal = hv.VSpan(0, 10).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| # aus_bdln = hv.VSpan(10,15).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| # aus_att = hv.VSpan(15, 30).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| # aus_bg = (aus_goal.opts(color='#ACFFA0', alpha = 0.75)* aus_att.opts(color='#B34D93', alpha = 0.9)*\ | |
| # aus_bdln.opts(color='#6AB35F', alpha = 0.75)) | |
| return ((asclsil_bg* ref_lsil_vline * lab_lsil_vline * scatter_lsil).opts(toolbar='above') +\ | |
| (ascus_bg* ref_ascus_vline * lab_ascus_vline*scatter_ascus).opts(toolbar='above')).cols(1).opts(shared_axes=False) | |
| else: | |
| return pn.pane.Markdown("# N/A", styles={'font-size':'20px'}) | |
| #COLORS (EGGPLANT): ['#ACFFA0','#6AB35F','#B34D93'] | |
| def add_no_cases_cp(year_slider,cp_select): | |
| scatterdata = df[(df.year == year_slider)&(df['people'] == cp_select)] | |
| if len(scatterdata) > 0: | |
| case_no = scatterdata['Number'].iloc[0] | |
| #if pd.isna(scatterdata['Thyroid AUS Rate(%)'].iloc[0]): | |
| # return pn.pane.Markdown(f'# Gyn Cases examined: {case_no}') | |
| #else: | |
| # ac_no =scatterdata['ThyAC Number'].iloc[0] | |
| return pn.pane.Markdown(f'# Gyn Cases examined: {case_no}') | |
| else: | |
| return None | |
| interactive_qa = pn.bind(update_scatter,year_slider, cp_select) | |
| interactive_no_cp = pn.bind(add_no_cases_cp,year_slider,cp_select) | |
| cp_performance = pn.Tabs(('Performance results',pn.Column(pn.Row(cp_select,year_slider),interactive_no_cp,\ | |
| pn.Row(pn.Column(pn.pane.Markdown("<br><br>"),vertical_legend_indiv),interactive_qa, height = 600 )\ | |
| ,pn.Column(pn.pane.Markdown("<br><br>"),modal_btn)))\ | |
| ,('Results overview',pn.Column(cp_select, inter_asclsil_cp, inter_ascus_cp)),styles = {'font-size': '20px'}) | |
| # In[ ]: | |
| # In[ ]: | |
| # In[14]: | |
| results = df[df['year'] != 2017] | |
| results_filtered = results[~results['people'].str.contains('Cytotechnologist 8', na=False)] | |
| med_ref_distribution = pd.concat([results_filtered[results_filtered.people.str.contains('KGYC')],results.iloc[[0]]])[['ASC/LSIL','ASC-US/ASC-H ratio(%)', 'Abnormal Rate(%)','Referral Rate(%)', 'hrHPV/ASC-US rate (%)', 'hrHPV Prevalence (%)']] | |
| med_ref_distribution.loc[len(med_ref_distribution)] = {'ASC/LSIL':0.75,'ASC-US/ASC-H ratio(%)':12.5, 'Abnormal Rate(%)':1.5} | |
| # In[15]: | |
| def hook_lsil(plot, element): | |
| # Adds right y-axis | |
| p = plot.handles["plot"] | |
| p.extra_y_scales = {"right": LinearScale()} | |
| p.extra_y_ranges = {"right": Range1d(0,0.55)} | |
| p.add_layout(LinearAxis(y_range_name="right"), "right") | |
| # find the last line and set it to right | |
| lines = [p for p in p.renderers if isinstance(p, GlyphRenderer)] | |
| lines[-1].y_range_name = "right" | |
| def hook_ascus(plot, element): | |
| # Adds right y-axis | |
| p = plot.handles["plot"] | |
| p.extra_y_scales = {"right": LinearScale()} | |
| p.extra_y_ranges = {"right": Range1d(0,0.045)} | |
| p.add_layout(LinearAxis(y_range_name="right"), "right") | |
| # find the last line and set it to right | |
| lines = [p for p in p.renderers if isinstance(p, GlyphRenderer)] | |
| lines[-1].y_range_name = "right" | |
| def hook_abnorm(plot, element): | |
| # Adds right y-axis | |
| p = plot.handles["plot"] | |
| p.extra_y_scales = {"right": LinearScale()} | |
| p.extra_y_ranges = {"right": Range1d(0,0.3)} | |
| p.add_layout(LinearAxis(y_range_name="right"), "right") | |
| # find the last line and set it to right | |
| lines = [p for p in p.renderers if isinstance(p, GlyphRenderer)] | |
| lines[-1].y_range_name = "right" | |
| # In[16]: | |
| def add_norm_curves(column_changer,year_slider): | |
| if column_changer == 'Referral Rate(%)' or column_changer == 'hrHPV/ASC-US rate (%)' or column_changer == 'hrHPV Prevalence (%)': | |
| return None | |
| else: | |
| mu= med_ref_distribution.iloc[-2][column_changer] | |
| variance = med_ref_distribution.iloc[-1][column_changer]**2 | |
| sigma = np.sqrt(variance) | |
| x = np.linspace(mu - 3 * np.sqrt(variance), mu + 3 * np.sqrt(variance), 32) | |
| distrib_df = pd.DataFrame({'x': x}) | |
| distrib_df['Reference Distribution'] = stats.norm.pdf(x, mu, sigma) | |
| curve_plot = distrib_df.hvplot.line(x='x', xlabel =f'{column_changer}', ylabel='Probability Density', title=f'Reference Curve vs Laboratory Histogram', color='black', hover=False).opts(fontsize = pl_title,fontscale = f_scale*0.75, shared_axes=False,toolbar=None, default_tools = []) | |
| if column_changer == 'ASC/LSIL' or column_changer == 'ASC-US/ASC-H ratio(%)': | |
| outliers_df = results_filtered[(results_filtered.year == year_slider)&(results_filtered.people.str.contains('Cyto'))][['ASC/LSIL','ASC-US/ASC-H ratio(%)','people']] | |
| outliers_df['zscore_ref'] = ((outliers_df[column_changer] - mu)/np.sqrt(variance)).map(lambda x: round(x, 3)) | |
| tooltips= f""" | |
| <div> | |
| <span style="font-size: {fpx}; font-weight: bold">@people | |
| </span><br> | |
| <span style= "font-size:{fpx}; font-weight: bold; color: #5B91D1">Z Score: | |
| </span> | |
| <span style="font-size: {fpx};">@zscore_ref | |
| </span> | |
| </div> | |
| """ | |
| d = np.linspace(mu - 3 * np.sqrt(variance), mu + 3 * np.sqrt(variance), len(outliers_df)) | |
| else: | |
| outliers_df = results_filtered[(results_filtered.year == year_slider)&(results_filtered.people.str.contains('ytolog'))][['Abnormal Rate(%)', 'people']] | |
| outliers_df['zscore_ref'] = ((outliers_df[column_changer] - mu)/np.sqrt(variance)).map(lambda x: round(x, 3)) | |
| tooltips= f""" | |
| <div> | |
| <span style="font-size: {fpx}; font-weight: bold">@people | |
| </span><br> | |
| <span style= "font-size:{fpx}; font-weight: bold; color: #5B91D1">Z Score: | |
| </span> | |
| <span style="font-size: {fpx};">@zscore_ref | |
| </span> | |
| </div> | |
| """ | |
| d = np.linspace(mu - 3 * np.sqrt(variance), mu + 3 * np.sqrt(variance), len(outliers_df)) | |
| outliers_df['Reference Distribution'] = (outliers_df[column_changer].apply(lambda x_val: stats.norm.pdf(x_val, mu, np.sqrt(variance))))#*10 | |
| hover = HoverTool(tooltips=tooltips) | |
| bins = 60 | |
| if column_changer=='ASC/LSIL': | |
| outliers_df['Reference Distribution'] *= 2.5 | |
| scatter_plot = outliers_df[outliers_df['zscore_ref'] > 2].hvplot.scatter(x=column_changer, y='Reference Distribution', color='red', size=sdot_size , hover_cols=['people','zscore_ref'], tools = [hover]).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| histo_data = results_filtered[(results_filtered.people.str.contains('Cyto'))&(results_filtered.year == year_slider)][[column_changer, 'people']] | |
| histo_plot = histo_data.hvplot.hist(y=column_changer, bins=bins, ylabel='Frequency',color = '#5B91D1', alpha=0.7,hover=False).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| overlay_plot = (histo_plot*curve_plot.opts(hooks=[hook_lsil])*scatter_plot) | |
| elif column_changer=='ASC-US/ASC-H ratio(%)': | |
| outliers_df['Reference Distribution'] *= 10 | |
| scatter_plot = outliers_df[outliers_df['zscore_ref'] < -2].hvplot.scatter(x=column_changer, y='Reference Distribution', color='red', size=sdot_size, hover_cols=['people','zscore_ref'], tools = [hover]).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| histo_data = results_filtered[(results_filtered.people.str.contains('Cyto'))&(results_filtered.year == year_slider)][[column_changer, 'people']] | |
| histo_plot = histo_data.hvplot.hist(y=column_changer, bins=bins, ylabel='Frequency', color = '#5B91D1', alpha=0.7,hover=False).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| overlay_plot = (histo_plot*curve_plot.opts(hooks=[hook_ascus])*scatter_plot) | |
| elif column_changer=='Abnormal Rate(%)': | |
| outliers_df['Reference Distribution'] | |
| scatter_plot = outliers_df[outliers_df['zscore_ref'] < -2].hvplot.scatter(x=column_changer, y='Reference Distribution', color='red', size=sdot_size ,height= 800, hover_cols=['people','zscore_ref',], tools = [hover]).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| histo_data = results_filtered[(results_filtered.people.str.contains('Cytot'))&(results_filtered.year == year_slider)][[column_changer, 'people']] | |
| histo_plot = histo_data.hvplot.hist(y=column_changer, bins=bins, ylabel='Frequency',color = '#5B91D1', alpha=0.7, hover=False).opts(shared_axes=False,toolbar=None, default_tools = []) | |
| overlay_plot = (histo_plot*curve_plot.opts(hooks=[hook_abnorm])*scatter_plot) | |
| return overlay_plot.opts(width = 820, height = 400) | |
| interact_norm_curve = pn.bind(add_norm_curves, column_changer,year_slider) | |
| # In[17]: | |
| lab_performance= pn.Tabs(('Performance results',pn.Column(pn.Row(column_changer, year_slider), interactive_no_lab,\ | |
| pn.Row(pn.Column(pn.pane.Markdown("<br><br><br>"),vertical_legend_indiv), interactive_func,interact_norm_curve),\ | |
| modal_btn)),('Results overview', \ | |
| pn.Column(column_changer, inter_labres)),styles = {'font-size': '20px'}) | |
| # In[18]: | |
| tabs = pn.Tabs(('Introduction', pn.pane.Markdown("""Welcome to the Dashboards!""")), | |
| ('Laboratory management', lab_performance), | |
| ('Cytotechnologist', ct_performance), | |
| ('Cytopathologist',cp_performance), sizing_mode = 'stretch_both', styles = {'font-size':'20px'}) | |
| # In[ ]: | |
| # In[20]: | |
| #Layout using Template | |
| template = pn.template.FastListTemplate( | |
| title='Interactive Quality Assurance Dashboards', | |
| main=[tabs], | |
| modal = modal, | |
| accent_base_color="#0072B5", | |
| header_background="#787878", theme_toggle = False, | |
| ) | |
| #start_scheduler() | |
| template.servable() |