|
| 1 | +import os, csv |
| 2 | +import numpy as np |
| 3 | +import matplotlib.pyplot as plt |
| 4 | + |
| 5 | + |
| 6 | +#################### Parse csv file |
| 7 | + |
| 8 | +with open('../extended_data/all_submissions.csv', 'r') as csvfile: |
| 9 | + csv_lines = [line for line in csvfile] |
| 10 | + |
| 11 | +csv_lines = csv_lines[1:] |
| 12 | + |
| 13 | +csv_lines = csv.reader(csv_lines, quotechar='"', delimiter=',', quoting=csv.QUOTE_ALL, skipinitialspace=True) |
| 14 | +csv_lines = [l for l in csv_lines] |
| 15 | + |
| 16 | + |
| 17 | +#From target_residue_list in all_submissions.csv |
| 18 | +def contacts_TF_list_from_csv_list(clist): |
| 19 | + true_false_list = [True if (i + 1) in clist else False for i in range(621)] #True/False for all res in EGFR. True if it's in contact with binder design |
| 20 | + return np.array(true_false_list) |
| 21 | + |
| 22 | + |
| 23 | +class Binder_csv: |
| 24 | + def __init__(self, csvline): |
| 25 | + self.csvline = csvline |
| 26 | + self.id = csvline[0] |
| 27 | + self.round = int(csvline[1]) |
| 28 | + self.selected = csvline[3] |
| 29 | + if self.selected == 'No': |
| 30 | + self.binding = 'Not tested' |
| 31 | + else: |
| 32 | + self.binding = csvline[12] |
| 33 | + if len(csvline[52]) == 2: |
| 34 | + self.target_res_list = [] |
| 35 | + else: |
| 36 | + self.target_res_list = [int(i) for i in csvline[52][1:-1].split(', ')] |
| 37 | + self.target_contacts = contacts_TF_list_from_csv_list(self.target_res_list) |
| 38 | + self.method = csvline[7] |
| 39 | + |
| 40 | + |
| 41 | +def contact_tf_matrix_to_chimera_file(tfmatrix, attrfile): |
| 42 | + num_designs = len(tfmatrix) |
| 43 | + tfmatrix = tfmatrix.sum(axis = 0) |
| 44 | + full_contacts_sum_norm = tfmatrix / num_designs |
| 45 | + header_lines = ['#\n', '# Binder contact frequency to map onto EGFR\n', '#\n', '# From Adaptyv Bio Protein Design Competition (all_submissions.csv)\n', '#\n', '# Use this file to assign the attribute in Chimera with the\n', '# Define Attribute tool or the command defattr.\n', '#\n', 'attribute: contactfreq\n', 'match mode: 1-to-1\n', 'recipient: residues\n'] |
| 46 | + data_lines = [f' :{i + 1} {full_contacts_sum_norm[i]}\n' for i in range(len(full_contacts_sum_norm))] |
| 47 | + with open(attrfile, 'w') as outfile: |
| 48 | + for line in header_lines: |
| 49 | + outfile.write(line) |
| 50 | + for line in data_lines: |
| 51 | + outfile.write(line) |
| 52 | + |
| 53 | + |
| 54 | +binders = [Binder_csv(line) for line in csv_lines] |
| 55 | + |
| 56 | + |
| 57 | + |
| 58 | +all_submissions_contact_tf_matrix = np.array([b.target_contacts for b in binders]) |
| 59 | + |
| 60 | +round1_submissions_contact_tf_matrix = np.array([b.target_contacts for b in binders if b.round == 1]) |
| 61 | + |
| 62 | +round2_submissions_contact_tf_matrix = np.array([b.target_contacts for b in binders if b.round == 2]) |
| 63 | + |
| 64 | +successful_binders_contact_tf_matrix = np.array([b.target_contacts for b in binders if b.binding in ['Strong', 'Medium', 'Weak']]) |
| 65 | + |
| 66 | +nonbinders_contact_tf_matrix = np.array([b.target_contacts for b in binders if b.binding == 'None']) |
| 67 | + |
| 68 | + |
| 69 | +print(f'All: {len(all_submissions_contact_tf_matrix)}') |
| 70 | +print(f'Round 1: {len(round1_submissions_contact_tf_matrix)}') |
| 71 | +print(f'Round 2: {len(round2_submissions_contact_tf_matrix)}') |
| 72 | +print(f'Binders: {len(successful_binders_contact_tf_matrix)}') |
| 73 | +print(f'Non-binders: {len(nonbinders_contact_tf_matrix)}') |
| 74 | + |
| 75 | + |
| 76 | +contact_tf_matrix_to_chimera_file(all_submissions_contact_tf_matrix, 'contact_freq_from_csv_all_submissions.txt') |
| 77 | + |
| 78 | +contact_tf_matrix_to_chimera_file(round1_submissions_contact_tf_matrix, 'contact_freq_from_csv_round1_submissions.txt') |
| 79 | + |
| 80 | +contact_tf_matrix_to_chimera_file(round2_submissions_contact_tf_matrix, 'contact_freq_from_csv_round2_submissions.txt') |
| 81 | + |
| 82 | +contact_tf_matrix_to_chimera_file(successful_binders_contact_tf_matrix, 'contact_freq_from_csv_successful_binders_both_rounds.txt') |
| 83 | + |
| 84 | +contact_tf_matrix_to_chimera_file(nonbinders_contact_tf_matrix, 'contact_freq_from_csv_nonbinders_both_rounds.txt') |
| 85 | + |
| 86 | + |
| 87 | +#################### Split by design method: |
| 88 | + |
| 89 | +successful_binders_OPTDIV_contact_tf_matrix = np.array([b.target_contacts for b in binders if ((b.binding in ['Strong', 'Medium', 'Weak']) and (b.method in ['Optimized binder', 'Diversified binder']))]) |
| 90 | + |
| 91 | +nonbinders_OPTDIV_contact_tf_matrix = np.array([b.target_contacts for b in binders if ((b.binding == 'None') and (b.method in ['Optimized binder', 'Diversified binder']))]) |
| 92 | + |
| 93 | + |
| 94 | +successful_binders_DENOVOHAL_contact_tf_matrix = np.array([b.target_contacts for b in binders if ((b.binding in ['Strong', 'Medium', 'Weak']) and (b.method in ['De novo', 'Hallucination']))]) |
| 95 | + |
| 96 | +nonbinders_DENOVOHAL_contact_tf_matrix = np.array([b.target_contacts for b in binders if ((b.binding == 'None') and (b.method in ['De novo', 'Hallucination']))]) |
| 97 | + |
| 98 | + |
| 99 | +successful_binders_OTHER_contact_tf_matrix = np.array([b.target_contacts for b in binders if ((b.binding in ['Strong', 'Medium', 'Weak']) and (b.method not in ['Optimized binder', 'Diversified binder', 'De novo', 'Hallucination']))]) |
| 100 | + |
| 101 | +nonbinders_OTHER_contact_tf_matrix = np.array([b.target_contacts for b in binders if ((b.binding == 'None') and (b.method not in ['Optimized binder', 'Diversified binder', 'De novo', 'Hallucination']))]) |
| 102 | + |
| 103 | + |
| 104 | +Unknown_contact_tf_matrix = np.array([b.target_contacts for b in binders if (b.binding == 'Unknown')]) |
| 105 | + |
| 106 | +#Split by method, just designs where binding success/failure is known (i.e. they were expressed successfully): |
| 107 | +all_expressed_OPTDIV_contact_tf_matrix = np.array([b.target_contacts for b in binders if ((b.method in ['Optimized binder', 'Diversified binder']) and (b.binding in ['Strong', 'Medium', 'Weak', 'None']))]) |
| 108 | + |
| 109 | +all_expressed_DENOVOHAL_contact_tf_matrix = np.array([b.target_contacts for b in binders if ((b.method in ['De novo', 'Hallucination']) and (b.binding in ['Strong', 'Medium', 'Weak', 'None']))]) |
| 110 | + |
| 111 | + |
| 112 | +print(f'All expressed OPTDIV: {len(all_expressed_OPTDIV_contact_tf_matrix)}') |
| 113 | +print(f'All expressed DENOVOHAL: {len(all_expressed_DENOVOHAL_contact_tf_matrix)}') |
| 114 | +print(f'OPTDIV binders: {len(successful_binders_OPTDIV_contact_tf_matrix)}') |
| 115 | +print(f'OPTDIV non-binders: {len(nonbinders_OPTDIV_contact_tf_matrix)}') |
| 116 | +print(f'DENOVOHAL binders: {len(successful_binders_DENOVOHAL_contact_tf_matrix)}') |
| 117 | +print(f'DENOVOHAL non-binders: {len(nonbinders_DENOVOHAL_contact_tf_matrix)}') |
| 118 | +print(f'OTHER binders: {len(successful_binders_OTHER_contact_tf_matrix)}') |
| 119 | +print(f'OTHER non-binders: {len(nonbinders_OTHER_contact_tf_matrix)}') |
| 120 | +print(f'Unknown binding: {len(Unknown_contact_tf_matrix)}') |
| 121 | + |
| 122 | + |
| 123 | +contact_tf_matrix_to_chimera_file(successful_binders_OPTDIV_contact_tf_matrix, 'contact_freq_from_csv_successful_binders_OPTIMIZED_DIVERSIFIED.txt') |
| 124 | + |
| 125 | +contact_tf_matrix_to_chimera_file(nonbinders_OPTDIV_contact_tf_matrix, 'contact_freq_from_csv_nonbinders_OPTIMIZED_DIVERSIFIED.txt') |
| 126 | + |
| 127 | +contact_tf_matrix_to_chimera_file(successful_binders_DENOVOHAL_contact_tf_matrix, 'contact_freq_from_csv_successful_binders_DENOVO_HALLUCINATION.txt') |
| 128 | + |
| 129 | +contact_tf_matrix_to_chimera_file(nonbinders_DENOVOHAL_contact_tf_matrix, 'contact_freq_from_csv_nonbinders_DENOVO_HALLUCINATION.txt') |
| 130 | + |
| 131 | +contact_tf_matrix_to_chimera_file(all_expressed_OPTDIV_contact_tf_matrix, 'contact_freq_from_csv_all_expressed_OPTIMIZED_DIVERSIFIED.txt') |
| 132 | + |
| 133 | +contact_tf_matrix_to_chimera_file(all_expressed_DENOVOHAL_contact_tf_matrix, 'contact_freq_from_csv_all_expressed_DENOVO_HALLUCINATION.txt') |
| 134 | + |
| 135 | + |
| 136 | + |
| 137 | +#################### Contact freq difference (binders - non-binders): |
| 138 | + |
| 139 | + |
| 140 | +def parse_Chimera_file(chimerafile): |
| 141 | + with open(chimerafile, 'r') as cfile: |
| 142 | + datalines = [line for line in cfile] |
| 143 | + datalines = datalines[11:] |
| 144 | + res = [float(line.split()[0].strip(':')) for line in datalines] |
| 145 | + cf = [float(line.split()[1].strip()) for line in datalines] |
| 146 | + return res, cf |
| 147 | + |
| 148 | + |
| 149 | +def write_diff_file(chimerafile1, chimerafile2, output_chimera_attribute_file): |
| 150 | + reslist, cf1 = parse_Chimera_file(chimerafile1) |
| 151 | + _, cf2 = parse_Chimera_file(chimerafile2) |
| 152 | + difflist = [(cf1[i] - cf2[i]) for i in range(len(cf1))] |
| 153 | + header_lines = ['#\n', '# Binder contact frequency difference to map onto EGFR\n', '#\n', '# From Adaptyv Bio Protein Design Competition (all_submissions.csv)\n', '#\n', '# Use this file to assign the attribute in Chimera with the\n', '# Define Attribute tool or the command defattr.\n', '#\n', 'attribute: contactfreq\n', 'match mode: 1-to-1\n', 'recipient: residues\n'] |
| 154 | + data_lines = [f' :{int(reslist[i])} {difflist[i]}\n' for i in range(len(difflist))] |
| 155 | + with open(output_chimera_attribute_file, 'w') as outfile: |
| 156 | + for line in header_lines: |
| 157 | + outfile.write(line) |
| 158 | + for line in data_lines: |
| 159 | + outfile.write(line) |
| 160 | + |
| 161 | + |
| 162 | +write_diff_file('contact_freq_from_csv_successful_binders_both_rounds.txt', 'contact_freq_from_csv_nonbinders_both_rounds.txt', 'contact_freq_diff_round1and2_binders_minus_nonbinders_from_csv.txt') |
| 163 | + |
| 164 | +write_diff_file('contact_freq_from_csv_successful_binders_OPTIMIZED_DIVERSIFIED.txt', 'contact_freq_from_csv_nonbinders_OPTIMIZED_DIVERSIFIED.txt', 'contact_freq_diff_from_csv_OPTIMIZED_DIVERSIFIED_binders_minus_nonbinders.txt') |
| 165 | + |
| 166 | +write_diff_file('contact_freq_from_csv_successful_binders_DENOVO_HALLUCINATION.txt', 'contact_freq_from_csv_nonbinders_DENOVO_HALLUCINATION.txt', 'contact_freq_diff_from_csv_DENOVO_HALLUCINATION_binders_minus_nonbinders.txt') |
| 167 | + |
| 168 | +#To see which contacts are enriched in optimized/diversified designs relative to de novo/hallucinated designs, among those where binding success/failure is known so we can use this to interpret the binders - non-binders plot |
| 169 | +write_diff_file('contact_freq_from_csv_all_expressed_OPTIMIZED_DIVERSIFIED.txt', 'contact_freq_from_csv_all_expressed_DENOVO_HALLUCINATION.txt', 'contact_freq_diff_from_csv_all_expressed_OPTDIV_minus_DENOVOHAL.txt') |
| 170 | + |
| 171 | + |
| 172 | +res, cf_diff_csv = parse_Chimera_file('contact_freq_diff_round1and2_binders_minus_nonbinders_from_csv.txt') |
| 173 | + |
| 174 | +_, cf_diff_csv_optdiv = parse_Chimera_file('contact_freq_diff_from_csv_OPTIMIZED_DIVERSIFIED_binders_minus_nonbinders.txt') |
| 175 | + |
| 176 | +_, cf_diff_csv_denovohal = parse_Chimera_file('contact_freq_diff_from_csv_DENOVO_HALLUCINATION_binders_minus_nonbinders.txt') |
| 177 | + |
| 178 | +_, cf_diff_csv_optdiv_vs_denovohal = parse_Chimera_file('contact_freq_diff_from_csv_all_expressed_OPTDIV_minus_DENOVOHAL.txt') |
| 179 | + |
| 180 | + |
| 181 | +fig, ax = plt.subplots(figsize=(9,3)) |
| 182 | +ax.scatter(res, cf_diff_csv_denovohal, marker = 'o', s = 5.0, color = 'black') |
| 183 | +ax.axvspan(0.5, 165.5, facecolor='#ebebeb', edgecolor = '#ffffff00', zorder = -10) |
| 184 | +ax.axvspan(310.5, 480.5, facecolor='#ebebeb', edgecolor = '#ffffff00', zorder = -10) |
| 185 | +ax.set_title('Contact Frequency Difference (Binders - Non-Binders), De Novo/Hallucination', fontweight='bold') |
| 186 | +ax.set_xlabel('Residue') |
| 187 | +ax.set_ylabel('Difference') |
| 188 | +#ax.set_ylim(l, u) |
| 189 | +plt.subplots_adjust(bottom=0.15) |
| 190 | +plt.savefig('contact_freq_diff_plot_round1and2_DENOVO_HALLUCINATION_binders_minus_nonbinders_from_csv_no_epitope.png', format='png', dpi=600) |
| 191 | + |
| 192 | +l, u = plt.ylim() |
| 193 | + |
| 194 | + |
| 195 | +fig, ax = plt.subplots(figsize=(9,3)) |
| 196 | +ax.scatter(res, cf_diff_csv_optdiv, marker = 'o', s = 5.0, color = 'black') |
| 197 | +ax.axvspan(0.5, 165.5, facecolor='#ebebeb', edgecolor = '#ffffff00', zorder = -10) |
| 198 | +ax.axvspan(310.5, 480.5, facecolor='#ebebeb', edgecolor = '#ffffff00', zorder = -10) |
| 199 | +ax.set_title('Contact Frequency Difference (Binders - Non-Binders), Optimized/Diversified', fontweight='bold') |
| 200 | +ax.set_xlabel('Residue') |
| 201 | +ax.set_ylabel('Difference') |
| 202 | +ax.set_ylim(l, u) |
| 203 | +plt.subplots_adjust(bottom=0.15) |
| 204 | +plt.savefig('contact_freq_diff_plot_round1and2_OPTIMIZED_DIVERSIFIED_binders_minus_nonbinders_from_csv_no_epitope.png', format='png', dpi=600) |
| 205 | + |
| 206 | + |
| 207 | +fig, ax = plt.subplots(figsize=(9,3)) |
| 208 | +ax.scatter(res, cf_diff_csv, marker = 'o', s = 5.0, color = 'black') |
| 209 | +ax.axvspan(0.5, 165.5, facecolor='#ebebeb', edgecolor = '#ffffff00', zorder = -10) |
| 210 | +ax.axvspan(310.5, 480.5, facecolor='#ebebeb', edgecolor = '#ffffff00', zorder = -10) |
| 211 | +ax.set_title('Contact Frequency Difference (Binders - Non-Binders), All Methods', fontweight='bold') |
| 212 | +ax.set_xlabel('Residue') |
| 213 | +ax.set_ylabel('Difference') |
| 214 | +ax.set_ylim(l, u) |
| 215 | +plt.subplots_adjust(bottom=0.15) |
| 216 | +plt.savefig('contact_freq_diff_plot_round1and2_binders_minus_nonbinders_from_csv_no_epitope_ylim_matching_method_comparisons.png', format='png', dpi=600) |
| 217 | + |
| 218 | + |
| 219 | +fig, ax = plt.subplots(figsize=(9,3)) |
| 220 | +ax.scatter(res, cf_diff_csv_optdiv_vs_denovohal, marker = 'o', s = 5.0, color = 'black') |
| 221 | +ax.axvspan(0.5, 165.5, facecolor='#ebebeb', edgecolor = '#ffffff00', zorder = -10) |
| 222 | +ax.axvspan(310.5, 480.5, facecolor='#ebebeb', edgecolor = '#ffffff00', zorder = -10) |
| 223 | +ax.set_title('Contact Frequency Difference (Optimized/Diversified - De Novo/Hallucination)', fontweight='bold') |
| 224 | +ax.set_xlabel('Residue') |
| 225 | +ax.set_ylabel('Difference') |
| 226 | +ax.set_ylim(l, u) |
| 227 | +plt.subplots_adjust(bottom=0.15) |
| 228 | +plt.savefig('contact_freq_diff_plot_round1and2_OPTDIV_minus_DENOVOHAL_all_expressed_from_csv_no_epitope.png', format='png', dpi=600) |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | + |
0 commit comments