File size: 10,158 Bytes
4b5b766 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | """
Representing the output of the program.
"""
import numpy
import matplotlib.pyplot as plt
def get_temperature_label(predictions, temperature_ranges, left_hand=True):
"""
Process the raw output of the inference model to get temperature range
labels.
predictions - LIST that contains predictions for each temperature range
temperature_ranges - LIST with temperature ranges' labels
left_hand - BOOLEAN that indicates to find the left-hand
(True) or right-hand (False) limit
returns STRING that is the label of the limiting temperature range
"""
if(left_hand):
for j, pred in enumerate(predictions):
if(float(pred) < 0.5):
return temperature_ranges[j]
elif(float(pred) >= 0.5 and j != len(predictions)-1):
continue
else:
return temperature_ranges[-1]
else:
for j, pred in enumerate(predictions[::-1]):
if(float(pred) >= 0.5):
return temperature_ranges[len(predictions)-j]
elif(float(pred) < 0.5 and j != len(predictions)-1):
continue
else:
return temperature_ranges[0]
def detect_clash(predictions, left_hand=True):
"""
Detecting the conflicting predictions of the ensemble.
predictions - LIST that contains predictions for each temperature range
left_hand - BOOLEAN that indicates to find the clash from left-hand
(True) or right-hand (False)
returns STRING '-' if clash was not detected, '*' if it was
"""
if(left_hand):
for j, pred in enumerate(predictions):
if(j and round(float(predictions[j-1])) <
round(float(predictions[j]))):
return "*"
elif(j and round(float(predictions[j-1])) >=
round(float(predictions[j])) and j != len(predictions)-1):
continue
elif(j and round(float(predictions[j-1])) >=
round(float(predictions[j])) and j == len(predictions)-1):
return "-"
elif(len(predictions) == 1):
return "-"
else:
for j, pred in enumerate(predictions[::-1]):
if(j != len(predictions)-1 and round(float(predictions[j-1])) <
round(float(predictions[j]))):
return "*"
elif(j != len(predictions)-1 and round(float(predictions[j-1])) >=
round(float(predictions[j])) and j != len(predictions)-2):
continue
elif(j != len(predictions)-1 and round(float(predictions[j-1])) >=
round(float(predictions[j])) and j == len(predictions)-2):
return "-"
elif(len(predictions) == 1):
return "-"
def print_inferences_header(file_handle, thresholds,
print_thermophilicity=False):
"""
Print inferences table header.
file_handle - FILE to which the results will be printed
thresholds - LIST of thresholds that are used
print_thermophilicity - BOOLEAN that determines whether to print the
thermophilicity column
"""
predictions_columns_names = ""
for threshold in thresholds:
predictions_columns_names += f"t{threshold}_binary\tt{threshold}_raw\t"
header = f"protein_id\tposition\tsequence\tlength\t{predictions_columns_names}"+\
f"left_hand_label\tright_hand_label\tclash"
if(print_thermophilicity): header += "\tthermophilicity"
print(header, file=file_handle)
def print_inferences(averaged_inferences, binary_inferences, original_headers,
labels, clashes, thermophilicity_labels, file_handle, sequences=None,
run_mode='mean', print_thermophilicity=False):
"""
Print results.
averaged_inferences - LIST of DICT that keeps each sequence's mean inferences
binary_inferences - LIST of DICT that keeps each sequence's binary inferences
original_headers - DICT of original sequences' headers for printing
labels - LIST of DICT that keeps each sequence's left-hand and right-hand
temperature prediction labels
clashes - LIST of DICT that keeps each sequence's clash labels
thermophilicity_labels - DICT with possible thermophilicity labels
sequences - LIST of DICT that keeps sequence ids as keys and sequences as values
file_handle - FILE to which the results will be printed
run_mode - STRING that determines which run mode is executed:
'mean', 'per-res', 'per-segment'
print_thermophilicity - BOOLEAN that determines to print the
thermophilicity column
"""
if(sequences is None): return
for proc_header in averaged_inferences.keys():
merged_inferences = []
for i, inf in enumerate(binary_inferences[proc_header]):
merged_inferences.append("%d" % binary_inferences[proc_header][i])
merged_inferences.append("%.3e" % averaged_inferences[proc_header][i])
# Setting the default values for run_mode 'mean'
if(run_mode == "mean"):
out_header = original_headers[proc_header]
position = '-'
elif(run_mode == "per-segment"):
out_header = original_headers["_".join(proc_header.split("_")[0:-1])]
pos_range = proc_header.split("_")[-1].split("-")
range_length = int(pos_range[1])-int(pos_range[0])
# Calculating the position (numerated from 1)
position = str(int(pos_range[0])+int(range_length/2)+1)
elif(run_mode == "per-res"):
out_header = original_headers["_".join(proc_header.split("_")[0:-1])]
position = str(int(proc_header.split("_")[-1])+1)
output_line = "%s\t%s\t%s\t%d\t%s\t%s\t%s" % (out_header, position,
sequences[proc_header],
len(sequences[proc_header]), "\t".join(merged_inferences),
"\t".join(labels[proc_header]), clashes[proc_header][0])
# Choosing the thermophilicity label
if(print_thermophilicity):
thermophilicity = "undetermined"
if(labels[proc_header][0] == labels[proc_header][1]):
for t in list(thermophilicity_labels.keys()):
if(labels[proc_header][0] in thermophilicity_labels[t]):
thermophilicity = t
break
output_line += f"\t{thermophilicity}"
print(output_line, file=file_handle)
def plot_per_res_inferences(averaged_inferences, thresholds, plot_dir,
smoothen=True, window_size=21, x_label="residue index",
title="Per-residue predictions"):
"""
Plotting per-residue inferences.
averaged_inferences - DICT that keeps each sequence's inferences
(averaged of all threshold models))
thresholds - LIST with binary models' temperature thresholds
plot_dir - STRING that determines the directory where plots should
be saved
smoothen - BOOL indicates to plot smoothened curve
"""
WINDOW_SIZE = window_size
original_seq_ids = set()
for seq_id in averaged_inferences.keys():
original_seq_ids.add("_".join(seq_id.split("_")[0:-1]))
original_seq_ids = list(original_seq_ids)
offset = 0
for or_seq_id in sorted(original_seq_ids):
x_values = []
y_values = []
# Python3.7+: DICT has the keys sorted by the insertion order
for i, seq_id in enumerate(list(averaged_inferences.keys())):
if(or_seq_id == "_".join(seq_id.split("_")[0:-1])):
x_values.append(i-offset)
y_values.append(averaged_inferences[seq_id])
y_values = numpy.array(y_values).T
for i, threshold in enumerate(thresholds):
plt.figure(f"t{threshold} models' per-residue inferences for {seq_id}")
color = "lightgrey" if(smoothen) else "navy"
plt.plot(x_values, y_values[i], linewidth=1, color=color)
plt.xlabel(x_label)
plt.ylabel("prediction")
plt.title(f"{title} of {or_seq_id} using threshold {threshold}", wrap=True)
plt.ylim(bottom=0, top=1)
j = 0
y_smoothened_values = []
if(smoothen):
while j < len(y_values[i])-WINDOW_SIZE+1:
window_average = round(numpy.sum(
y_values[i][j:j+WINDOW_SIZE])/WINDOW_SIZE, 2)
y_smoothened_values.append(window_average)
j += 1
plt.plot(x_values[int(WINDOW_SIZE/2):-int(WINDOW_SIZE/2)],
y_smoothened_values, linewidth=1, color="navy")
plt.savefig(f"{plot_dir}/{or_seq_id}_per_residue_plot_t{threshold}.svg", format="svg")
offset += len(x_values)
def plot_inferences(per_res_out, per_segment_out, averaged_inferences, thresholds, plot_dir,
window_size, segment_size, smoothen):
"""
Deciding and calling, which inferences to plot.
per_res_out - STRING or None to determine whether per-residue predictions
are required
per_segment_out - STRING or None to determine whether per-segment
predictions are required
averaged_inferences - DICT that keeps each sequence's inferences
(averaged of all threshold models))
thresholds - LIST with binary models' temperature thresholds
plot_dir - STRING that determines the directory where plots should
be saved
window_size - INT of the window size for curve smoothening
segment_size - INT of the segment size of combined residues
smoothen - BOOL indicates to plot smoothened curve
"""
if(plot_dir is None): return
if(per_res_out):
plot_per_res_inferences(averaged_inferences, thresholds,
plot_dir, window_size=window_size)
if(per_segment_out):
plot_per_res_inferences(averaged_inferences, thresholds,
plot_dir, smoothen=smoothen,
window_size=window_size,
x_label=f"segment (k={segment_size}) index",
title="Per-segment predictions")
|