Source code for Report.Web_Report

# Yuncong Ma, 2/14/2024
# Make a web page based report for fast visual examination

from Module.Visualization import *
import shutil


dir_python = os.path.dirname(os.path.abspath(__file__))


[docs]def run_web_report(dir_pnet_result: str): """ generate HTML based web report :param dir_pnet_result: :return: Yuncong Ma, 2/14/2024 """ # get directories of sub-folders dir_pnet_dataInput, dir_pnet_FNC, dir_pnet_gFN, dir_pnet_pFN, dir_pnet_QC, _ = setup_result_folder(dir_pnet_result) # log file logFile = os.path.join(dir_pnet_result, 'Log_Report.log') logFile = open(logFile, 'w') print_log('\nStart generating HTML based web report at ' + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + '\n', logFile=logFile, stop=False) # load settings for data input and FN computation if not os.path.isfile(os.path.join(dir_pnet_dataInput, 'Setting.json')): raise ValueError('Cannot find the setting json file in folder Data_Input') if not os.path.isfile(os.path.join(dir_pnet_FNC, 'Setting.json')): raise ValueError('Cannot find the setting json file in folder FN_Computation') settingDataInput = load_json_setting(os.path.join(dir_pnet_dataInput, 'Setting.json')) settingFNC = load_json_setting(os.path.join(dir_pnet_FNC, 'Setting.json')) setting = {'Data_Input': settingDataInput, 'FN_Computation': settingFNC} print_log('Settings are loaded from folder Data_Input and FN_Computation', logFile=logFile, stop=False) # load basic settings dataType = setting['Data_Input']['Data_Type'] dataFormat = setting['Data_Input']['Data_Format'] Combine_Scan = setting['Data_Input']['Combine_Scan'] # info about the fMRI dataset file_scan = os.path.join(dir_pnet_dataInput, 'Scan_List.txt') file_subject_ID = os.path.join(dir_pnet_dataInput, 'Subject_ID.txt') file_subject_folder = os.path.join(dir_pnet_dataInput, 'Subject_Folder.txt') list_scan = load_txt_list(file_scan) nScan = len(list_scan) list_subject_ID = load_txt_list(file_subject_ID) nSubject = len(np.unique(list_subject_ID)) list_subject, subject_index = np.unique(load_txt_list(file_subject_ID), return_index=True) list_subject_ID_unqiue = list_subject_ID[subject_index] list_subject_folder = load_txt_list(file_subject_folder) list_subject_folder_unique, folder_index = np.unique(list_subject_folder, return_index=True) nFolder = len(list_subject_folder_unique) # =========== Summary =========== # # template for web page template_summary = os.path.join(dir_python, 'Web_Template_Summary.html') # Generate the summary web page file_summary = os.path.join(dir_pnet_result, 'Report.html') pnet_FN_method = setting['FN_Computation']['Method'] K = setting['FN_Computation']['K'] with open(template_summary, 'r') as file: html_as_string = file.read() # report title report_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) html_as_string = html_as_string.replace('{$report_time$}', str(report_time)) # setting html_as_string = html_as_string.replace('{$pnet_FN_method$}', str(pnet_FN_method)) html_as_string = html_as_string.replace('{$K$}', str(K)) html_as_string = html_as_string.replace('{$dataType$}', str(dataType)) html_as_string = html_as_string.replace('{$dataFormat$}', str(dataFormat)) html_as_string = html_as_string.replace('{$nScan$}', str(nScan)) html_as_string = html_as_string.replace('{$nSubject$}', str(nSubject)) # Compress images if not done yet image_size = (2000, 10000) if not os.path.isfile(os.path.join(dir_pnet_gFN, 'All(Compressed).jpg')): compress_image(os.path.join(dir_pnet_gFN, 'All(Compressed).jpg'), os.path.join(dir_pnet_gFN, 'All.jpg'), image_size=image_size) for i in range(nFolder): if os.path.isfile(os.path.join(dir_pnet_pFN, list_subject_folder_unique[i], 'All.jpg')) and not os.path.isfile(os.path.join(dir_pnet_pFN, list_subject_folder_unique[i], 'All(Compressed).jpg')): compress_image(os.path.join(dir_pnet_pFN, list_subject_folder_unique[i], 'All(Compressed).jpg'), os.path.join(dir_pnet_pFN, list_subject_folder_unique[i], 'All.jpg'), image_size=image_size) # gFN if setting['FN_Computation']['Group_FN']['file_gFN'] is None: text_gFN = 'The group FNs are derived using the whole fMRI dataset' else: text_gFN = 'The group FNs are loaded from precomputed results at ' + setting['FN_Computation']['Group_FN']['file_gFN'] html_as_string = html_as_string.replace('{$text_gFN$}', str(text_gFN)) figure_gFN = './Group_FN/All(Compressed).jpg' html_as_string = html_as_string.replace('{$figure_gFN$}', str(figure_gFN)) # pFN examples nMax = 10 frames = [Image.open(os.path.join(dir_pnet_pFN, list_subject_folder[subject_index[i]], 'All(Compressed).jpg')) for i in range(np.minimum(nMax, nSubject))] frame_one = frames[0] frame_one.save(os.path.join(dir_pnet_pFN, 'Example.gif'), format="GIF", append_images=frames, save_all=True, duration=1000, loop=0, optimize=False) pFN_example = './' + os.path.join('Personalized_FN', 'Example.gif') html_as_string = html_as_string.replace('{$pFN_example$}', str(pFN_example)) # pFN links link_pFN = '' pre_sub = list_subject_ID_unqiue[0] for i in range(nFolder): if list_subject_ID[folder_index[i]] != pre_sub: link_pFN = link_pFN + "<br />" pre_sub = list_subject_ID[folder_index[i]] file_pFN_indv = './' + os.path.join('Personalized_FN', list_subject_folder_unique[i], 'Report.html') link_pFN = link_pFN + f" <a href='{file_pFN_indv}' target='_blank' title='{list_subject_folder_unique[i]}'>({list_subject_folder_unique[i]})</a>\n" html_as_string = html_as_string.replace('{$link_pFN$}', str(link_pFN)) # QC Result = load_matlab_single_variable(os.path.join(dir_pnet_QC, 'Result.mat')) n_pass = np.sum(np.min(Result['Delta_Spatial_Correspondence'][0, 0], axis=1) >= 0) n_missmatch = np.sum(np.min(Result['Delta_Spatial_Correspondence'][0, 0], axis=1) < 0) ps_missmatch = np.where(np.min(Result['Delta_Spatial_Correspondence'][0, 0], axis=1) < 0)[0] scan_subject = '' if Combine_Scan: scan_subject = 'subjects' else: scan_subject = 'scans' if n_missmatch == 0: text_qc = 'pFNs of all '+str(n_pass+n_missmatch)+' '+scan_subject+' passed QC. <br />' else: text_qc = 'There are ' + str(n_pass) + ' out of ' + str(n_pass+n_missmatch) + ' '+scan_subject+' passed QC. <br />\n' +\ 'There are ' + str(n_missmatch) +' scans do not pass QC, meaning that they have at least one pFN showing smaller similarity to their group-level counterpart. <br />\n' text_qc += 'Below are the individual reports of '+scan_subject+' that do not pass QC. <br />\n' for i, ps in enumerate(ps_missmatch): file_pFN_indv = './' + os.path.join('Personalized_FN', list_subject_folder_unique[ps], 'Report.html') text_qc = text_qc + f" <a href='{file_pFN_indv}' target='_blank' title='{list_subject_folder_unique[ps]}'>({list_subject_folder_unique[ps]})</a>\n" if (i+1) % 10 == 0: text_qc = text_qc + " <br />" html_as_string = html_as_string.replace('{$text_qc$}', str(text_qc)) file_summary = open(file_summary, 'w') print(html_as_string, file=file_summary) file_summary.close() # =========== Individual =========== # # template for web page template_individual = os.path.join(dir_python, 'Web_Template_Individual.html') pre_sub = '' delta_SC = Result['Delta_Spatial_Correspondence'][0, 0] for i in range(nFolder): if list_subject_ID[folder_index[i]] != pre_sub: link_pFN = link_pFN + "<br />" pre_sub = list_subject_ID[folder_index[i]] with open(template_individual, 'r') as file: html_as_string = file.read() # copy gFN figure shutil.copyfile(os.path.join(dir_pnet_gFN, 'All(Compressed).jpg'), os.path.join(dir_pnet_pFN, list_subject_folder_unique[i], 'gFN_All(Compressed).jpg')) # report title html_as_string = html_as_string.replace('{$subject_info$}', str(pre_sub)) report_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) html_as_string = html_as_string.replace('{$report_time$}', str(report_time)) # setting html_as_string = html_as_string.replace('{$pnet_FN_method$}', str(pnet_FN_method)) html_as_string = html_as_string.replace('{$K$}', str(K)) html_as_string = html_as_string.replace('{$dataType$}', str(dataType)) html_as_string = html_as_string.replace('{$dataFormat$}', str(dataFormat)) html_as_string = html_as_string.replace('{$nScan$}', str(nScan)) html_as_string = html_as_string.replace('{$nSubject$}', str(nSubject)) html_as_string = html_as_string.replace('{$text_gFN$}', str(text_gFN)) if np.sum(delta_SC[i, :] < 0) == 0: text_qc = 'All pFNs passed QC. All of them show higher spatial similarity to their group-level counterparts that others.' else: text_qc = f'This pFN result violates QC, meaning that some pFNs show lower spatial similarity to their group-level counterparts that others. <br /> \n' \ f'<br />\nDetails are below. <br />\n' Result = load_matlab_single_variable(os.path.join(dir_pnet_QC, list_subject_folder_unique[i], 'Result.mat')) Miss_Match = Result['Miss_Match'][0, 0] for j in range(Miss_Match.shape[0]): try: text_qc += f'pFN {Miss_Match[j, 0]} is more similar to gFN {Miss_Match[j, 1]} <br />\n' except: print('the number of Miss Matched is ' + str(Miss_Match.shape[0]) + '\n') html_as_string = html_as_string.replace('{$text_qc$}', str(text_qc)) file_individual = os.path.join(dir_pnet_pFN, list_subject_folder_unique[i], 'Report.html') file_individual = open(file_individual, 'w') print(html_as_string, file=file_individual) file_individual.close()