vizualization_asymetry_index_fa.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Tue Nov 5 14:25:19 2024
  4. @author: arefks
  5. """
  6. # -*- coding: utf-8 -*-
  7. """
  8. Created on Mon Nov 4 17:54:46 2024
  9. @author: arefk
  10. """
  11. import os
  12. import pandas as pd
  13. import numpy as np
  14. import seaborn as sns
  15. import matplotlib.pyplot as plt
  16. from scipy.stats import pearsonr, spearmanr, shapiro
  17. from statsmodels.stats.multitest import multipletests
  18. # Get the directory where the code file is located
  19. code_dir = os.path.dirname(os.path.abspath(__file__))
  20. parent_dir = os.path.dirname(code_dir)
  21. # Make sure these variables are set according to your selected settings
  22. selected_groups = ["Stroke"] # Example: Stroke group vs. Control group
  23. selected_qtype = "fa" # Example: fa Qtype
  24. selected_mask_names = [
  25. "CRuT_MOp-RN_ipsilesional_CCcut",
  26. "CRuT_MOp-RN_contralesional_mirrored_CCcut",
  27. "CReT_MOp-TRN_ipsilesional_CCcut",
  28. "CReT_MOp-TRN_contralesional_CCcut",
  29. "CST_MOp-int-py_ipsilesional_selfdrawnROA+CCcut",
  30. "CST_MOp-int-py_contralesional_selfdrawnROA+CCcut",
  31. "TC_DORsm-SSp_ll+SSp_ul_ipsilesional_END+higherstepsize_",
  32. "TC_DORsm-SSp_ll+SSp_ul_contralesional_END+higherstepsize"
  33. ] # Updated list of specific masks # Updated list of specific masks
  34. selected_timepoints = [3] # Example: multiple selected timepoints
  35. selected_dialation_amount = 3 # Example: dilation value for the time point
  36. # Define simple anatomical names for the masks
  37. mask_name_mapping = {
  38. "CC_MOp-MOp_cut": "Corpus Callosum",
  39. "CRuT_MOp-RN_ipsilesional_CCcut": "Rubropsinal (Ipsilesional)",
  40. "CRuT_MOp-RN_contralesional_mirrored_CCcut": "Rubropsinal (Contralesional)",
  41. "TC_DORsm-SSp_ll+SSp_ul_ipsilesional_END+higherstepsize_": "Thalamocortical (Ipsilesional)",
  42. "TC_DORsm-SSp_ll+SSp_ul_contralesional_END+higherstepsize": "Thalamocortical (Contralesional)",
  43. "CReT_MOp-TRN_contralesional_CCcut": "Reticulospinal (Contralesional)",
  44. "CReT_MOp-TRN_ipsilesional_CCcut": "Reticulospinal (Ipsilesional)",
  45. "CST_MOp-int-py_contralesional_selfdrawnROA+CCcut": "Corticospinal (Contralesional)",
  46. "CST_MOp-int-py_ipsilesional_selfdrawnROA+CCcut": "Corticospinal (Ipsilesional)",
  47. "OT_och-lgn_lgncut": "Optic"
  48. }
  49. # Load the CSV data
  50. input_file_path = os.path.join(parent_dir, 'output', "Quantitative_outputs", 'Quantitative_results_from_dwi_processing_merged_with_behavior_data.csv')
  51. df = pd.read_csv(input_file_path, low_memory=False)
  52. # Remove duplicate rows
  53. df = df.drop_duplicates()
  54. # Define output paths
  55. figures_folder = os.path.join(parent_dir, 'output', 'Figures')
  56. pythonFigs_folder = os.path.join(figures_folder, 'pythonFigs')
  57. # Create directories if they do not exist
  58. os.makedirs(pythonFigs_folder, exist_ok=True)
  59. # Store all p-values for multiple test correction
  60. all_p_values = []
  61. # Create the figure for subplots
  62. fig, axes = plt.subplots(4, 1, figsize=(14 / 2.54, 20 / 2.54)) # 1 column, 4 rows # 2 columns, 5 rows
  63. axes = axes.flatten() if isinstance(axes, np.ndarray) else [axes] # Flatten the axes array for easy iteration
  64. # File to store all correlation results
  65. correlation_text_path = os.path.join(pythonFigs_folder, 'fa_behavior_correlation_asymmetry_index.txt')
  66. with open(correlation_text_path, 'w') as f:
  67. f.write('Asymmetry Index Correlation Results for All Masks\n')
  68. f.write('=' * 60 + '\n')
  69. # Iterate over each pair of ipsilesional and contralesional mask names
  70. for idx in range(0, len(selected_mask_names), 2):
  71. ipsilesional_mask_name = selected_mask_names[idx]
  72. contralesional_mask_name = selected_mask_names[idx + 1]
  73. for selected_timepoint in selected_timepoints:
  74. # Filter the DataFrame based on selected settings for each group
  75. df_filtered_ipsi_list = []
  76. df_filtered_contra_list = []
  77. for group in selected_groups:
  78. df_filtered_ipsi = df[(df['Group'] == group) &
  79. (df['Qtype'] == selected_qtype) &
  80. (df['mask_name'] == ipsilesional_mask_name) &
  81. (df['dialation_amount'] == selected_dialation_amount) &
  82. (df['merged_timepoint'] == selected_timepoint)]
  83. df_filtered_contra = df[(df['Group'] == group) &
  84. (df['Qtype'] == selected_qtype) &
  85. (df['mask_name'] == contralesional_mask_name) &
  86. (df['dialation_amount'] == selected_dialation_amount) &
  87. (df['merged_timepoint'] == selected_timepoint)]
  88. df_filtered_ipsi_list.append(df_filtered_ipsi)
  89. df_filtered_contra_list.append(df_filtered_contra)
  90. # Combine the filtered DataFrames
  91. df_filtered_ipsi = pd.concat(df_filtered_ipsi_list, ignore_index=True)
  92. df_filtered_contra = pd.concat(df_filtered_contra_list, ignore_index=True)
  93. # Remove NaNs and ensure we have matching data for asymmetry index calculation
  94. df_filtered_ipsi = df_filtered_ipsi.dropna(subset=['Value', 'DeficitScore'])
  95. df_filtered_contra = df_filtered_contra.dropna(subset=['Value', 'DeficitScore'])
  96. # Ensure that we have matching rows for both ipsilesional and contralesional masks
  97. if not df_filtered_ipsi.empty and not df_filtered_contra.empty:
  98. # Calculate the Asymmetry Index (AI)
  99. df_filtered_ipsi['AsymmetryIndex'] = (
  100. (df_filtered_contra['Value'].values - df_filtered_ipsi['Value'].values) /
  101. (0.5 * (df_filtered_contra['Value'].values + df_filtered_ipsi['Value'].values))
  102. )
  103. # Plot the data if available
  104. y_min = df_filtered_ipsi['DeficitScore'].min() - 0.1 * df_filtered_ipsi['DeficitScore'].max()
  105. y_max = df_filtered_ipsi['DeficitScore'].max() + 0.3 * df_filtered_ipsi['DeficitScore'].max()
  106. ax = axes[idx // 2] # Select the appropriate subplot axis
  107. group_p_values = []
  108. correlation_results = []
  109. for group in selected_groups:
  110. group_data = df_filtered_ipsi[df_filtered_ipsi['Group'] == group]
  111. if not group_data.empty:
  112. # Shapiro-Wilk test for normality
  113. shapiro_statValue, shapiro_pvalueAI = shapiro(group_data['AsymmetryIndex'])
  114. shapiro_statScore, shapiro_pvalueBehavior = shapiro(group_data['DeficitScore'])
  115. # Calculate Pearson or Spearman based on normality test
  116. if shapiro_pvalueAI < 0.05 or shapiro_pvalueBehavior < 0.05:
  117. # Use Spearman if data is not normally distributed
  118. correlation_coefficient, p_value = spearmanr(group_data['AsymmetryIndex'], group_data['DeficitScore'])
  119. else:
  120. # Use Pearson if data is normally distributed
  121. correlation_coefficient, p_value = pearsonr(group_data['AsymmetryIndex'], group_data['DeficitScore'])
  122. # Store p-value for multiple testing correction
  123. group_p_values.append(p_value)
  124. all_p_values.append(p_value)
  125. # Store correlation result
  126. correlation_results.append((group, correlation_coefficient, p_value))
  127. # Apply multiple test correction for this group
  128. corrected_p_values = multipletests(group_p_values, method='fdr_bh')[1]
  129. corrected_p_index = 0
  130. for group, correlation_coefficient, p_value in correlation_results:
  131. # Retrieve corrected p-value
  132. corrected_p_value = corrected_p_values[corrected_p_index]
  133. corrected_p_index += 1
  134. # Determine significance level
  135. pval_text = ''
  136. if corrected_p_value < 0.001:
  137. pval_text = '***'
  138. elif corrected_p_value < 0.01:
  139. pval_text = '**'
  140. elif corrected_p_value < 0.05:
  141. pval_text = '*'
  142. else:
  143. pval_text = ' '
  144. # Plot the regression
  145. sns.regplot(
  146. x='AsymmetryIndex', y='DeficitScore', data=group_data, ci=95, ax=ax,
  147. line_kws={'color': 'lightcoral', 'alpha': 0.6}, # Regression line in light red with higher transparency
  148. scatter_kws={'color': 'red', 'alpha': 0.6, 's': 10}, # Scatter points in red
  149. label=f'{group} (R={correlation_coefficient:.2f} {pval_text})'
  150. )
  151. # Add text annotation for R and significance level
  152. ax.text(0.05, 0.95, f'R={correlation_coefficient:.2f}{pval_text}', transform=ax.transAxes,
  153. fontsize=10, verticalalignment='top', bbox=dict(boxstyle='round,pad=0.3', facecolor='white', alpha=0))
  154. # Save correlation results to the text file
  155. with open(correlation_text_path, 'a') as f:
  156. f.write(f'Mask Pair: {ipsilesional_mask_name} & {contralesional_mask_name} | Group: {group}\n')
  157. f.write(f'Correlation Coefficient (uncorrected): {correlation_coefficient:.4f}\n')
  158. f.write(f'P-Value (uncorrected): {p_value:.4e}\n')
  159. f.write(f'P-Value (corrected): {corrected_p_value:.4e}\n')
  160. f.write('-' * 40 + '\n')
  161. # Set consistent y-limits
  162. ax.set_ylim([y_min, y_max])
  163. # Set labels and customize font settings
  164. anatomical_name = mask_name_mapping.get(ipsilesional_mask_name, ipsilesional_mask_name)
  165. ax.set_ylabel('Deficit Score [a.u]', fontsize=12, fontname='Calibri')
  166. ax.set_xlabel(f'Asymmetry Index ({anatomical_name})', fontsize=12, fontname='Calibri')
  167. # Remove gridlines
  168. ax.grid(False)
  169. sns.despine(ax=ax) # Remove the top and right spines for cleaner look
  170. else:
  171. print(f"No data available for the selected settings: Groups={selected_groups}, Qtype={selected_qtype}, Mask Pair=({ipsilesional_mask_name}, {contralesional_mask_name}), Dilation value={selected_dialation_amount}, Timepoint={selected_timepoint}.")
  172. # Adjust layout
  173. plt.tight_layout()
  174. # Save the complete figure with all subplots
  175. fig_filename = 'fa_behavior_correlation_asymmetry_index_all_masks_timepoint_56_groups_comparison.svg'
  176. plt.savefig(os.path.join(pythonFigs_folder, fig_filename), dpi=300, bbox_inches='tight', format="svg", transparent=True)
  177. # Show the figure
  178. plt.show()