Package Bio :: Package SubsMat
[hide private]
[frames] | no frames]

Source Code for Package Bio.SubsMat

  1  # Copyright 2000-2009 by Iddo Friedberg.  All rights reserved. 
  2  # This code is part of the Biopython distribution and governed by its 
  3  # license.  Please see the LICENSE file that should have been included 
  4  # as part of this package. 
  5  # 
  6  # Iddo Friedberg idoerg@cc.huji.ac.il 
  7   
  8  """Substitution matrices, log odds matrices, and operations on them. 
  9   
 10  General: 
 11  -------- 
 12   
 13  This module provides a class and a few routines for generating 
 14  substitution matrices, similar ot BLOSUM or PAM matrices, but based on 
 15  user-provided data. 
 16  The class used for these matrices is SeqMat 
 17   
 18  Matrices are implemented as a dictionary. Each index contains a 2-tuple, 
 19  which are the two residue/nucleotide types replaced. The value differs 
 20  according to the matrix's purpose: e.g in a log-odds frequency matrix, the 
 21  value would be log(Pij/(Pi*Pj)) where: 
 22  Pij: frequency of substitution of letter (residue/nucleotide) i by j 
 23  Pi, Pj: expected frequencies of i and j, respectively. 
 24   
 25  Usage: 
 26  ------ 
 27  The following section is laid out in the order by which most people wish 
 28  to generate a log-odds matrix. Of course, interim matrices can be 
 29  generated and investigated. Most people just want a log-odds matrix, 
 30  that's all. 
 31   
 32  Generating an Accepted Replacement Matrix: 
 33  ------------------------------------------ 
 34  Initially, you should generate an accepted replacement matrix (ARM) 
 35  from your data. The values in ARM are the _counted_ number of 
 36  replacements according to your data. The data could be a set of pairs 
 37  or multiple alignments. So for instance if Alanine was replaced by 
 38  Cysteine 10 times, and Cysteine by Alanine 12 times, the corresponding 
 39  ARM entries would be: 
 40  ['A','C']: 10, 
 41  ['C','A'] 12 
 42  As order doesn't matter, user can already provide only one entry: 
 43  ['A','C']: 22 
 44  A SeqMat instance may be initialized with either a full (first 
 45  method of counting: 10, 12) or half (the latter method, 22) matrix. A 
 46  Full protein alphabet matrix would be of the size 20x20 = 400. A Half 
 47  matrix of that alphabet would be 20x20/2 + 20/2 = 210. That is because 
 48  same-letter entries don't change. (The matrix diagonal). Given an 
 49  alphabet size of N: 
 50  Full matrix size:N*N 
 51  Half matrix size: N(N+1)/2 
 52   
 53  If you provide a full matrix, the constructor will create a half-matrix 
 54  automatically. 
 55  If you provide a half-matrix, make sure of a (low, high) sorted order in 
 56  the keys: there should only be 
 57  a ('A','C') not a ('C','A'). 
 58   
 59  Internal functions: 
 60   
 61  Generating the observed frequency matrix (OFM): 
 62  ----------------------------------------------- 
 63  Use: OFM = _build_obs_freq_mat(ARM) 
 64  The OFM is generated from the ARM, only instead of replacement counts, it 
 65  contains replacement frequencies. 
 66   
 67  Generating an expected frequency matrix (EFM): 
 68  ---------------------------------------------- 
 69  Use: EFM = _build_exp_freq_mat(OFM,exp_freq_table) 
 70  exp_freq_table: should be a freqTableC instantiation. See freqTable.py for 
 71  detailed information. Briefly, the expected frequency table has the 
 72  frequencies of appearance for each member of the alphabet 
 73   
 74  Generating a substitution frequency matrix (SFM): 
 75  ------------------------------------------------- 
 76  Use: SFM = _build_subs_mat(OFM,EFM) 
 77  Accepts an OFM, EFM. Provides the division product of the corresponding 
 78  values. 
 79   
 80  Generating a log-odds matrix (LOM): 
 81  ----------------------------------- 
 82  Use: LOM=_build_log_odds_mat(SFM[,logbase=10,factor=10.0,roundit=1]) 
 83  Accepts an SFM. logbase: base of the logarithm used to generate the 
 84  log-odds values. factor: factor used to multiply the log-odds values. 
 85  roundit: default - true. Whether to round the values. 
 86  Each entry is generated by log(LOM[key])*factor 
 87  And rounded if required. 
 88   
 89  External: 
 90  --------- 
 91  In most cases, users will want to generate a log-odds matrix only, without 
 92  explicitly calling the OFM --> EFM --> SFM stages. The function 
 93  build_log_odds_matrix does that. User provides an ARM and an expected 
 94  frequency table. The function returns the log-odds matrix. 
 95   
 96  Methods for subtraction, addition and multiplication of matrices: 
 97  ----------------------------------------------------------------- 
 98   
 99  * Generation of an expected frequency table from an observed frequency 
100    matrix. 
101  * Calculation of linear correlation coefficient between two matrices. 
102  * Calculation of relative entropy is now done using the 
103    _make_relative_entropy method and is stored in the member 
104    self.relative_entropy 
105  * Calculation of entropy is now done using the _make_entropy method and 
106    is stored in the member self.entropy. 
107  * Jensen-Shannon distance between the distributions from which the 
108    matrices are derived. This is a distance function based on the 
109    distribution's entropies. 
110   
111  """ 
112   
113   
114  from __future__ import print_function 
115   
116  import re 
117  import sys 
118  import copy 
119  import math 
120   
121  # BioPython imports 
122  from Bio import Alphabet 
123  from Bio.SubsMat import FreqTable 
124   
125   
126  log = math.log 
127  # Matrix types 
128  NOTYPE = 0 
129  ACCREP = 1 
130  OBSFREQ = 2 
131  SUBS = 3 
132  EXPFREQ = 4 
133  LO = 5 
134  EPSILON = 0.00000000000001 
135   
136   
137 -class SeqMat(dict):
138 """A Generic sequence matrix class. 139 140 The key is a 2-tuple containing the letter indices of the matrix. Those 141 should be sorted in the tuple (low, high). Because each matrix is dealt 142 with as a half-matrix. 143 """ 144
145 - def _alphabet_from_matrix(self):
146 """Set alphabet letters from the matrix entries (PRIVATE).""" 147 ab_dict = {} 148 s = '' 149 for i in self: 150 ab_dict[i[0]] = 1 151 ab_dict[i[1]] = 1 152 for i in sorted(ab_dict): 153 s += i 154 self.alphabet.letters = s
155
156 - def __init__(self, data=None, alphabet=None, mat_name='', build_later=0):
157 """Initialize. 158 159 User may supply: 160 161 - data: matrix itself 162 - mat_name: its name. See below. 163 - alphabet: an instance of Bio.Alphabet, or a subclass. If not 164 supplied, constructor builds its own from that matrix. 165 - build_later: skip the matrix size assertion. User will build the 166 matrix after creating the instance. Constructor builds a half matrix 167 filled with zeroes. 168 169 """ 170 assert isinstance(mat_name, str) 171 # "data" may be: 172 # 1) None --> then self.data is an empty dictionary 173 # 2) type({}) --> then self takes the items in data 174 # 3) An instance of SeqMat 175 # This whole creation-during-execution is done to avoid changing 176 # default values, the way Python does because default values are 177 # created when the function is defined, not when it is created. 178 if data: 179 try: 180 self.update(data) 181 except ValueError: 182 raise ValueError("Failed to store data in a dictionary") 183 if alphabet is None: 184 alphabet = Alphabet.Alphabet() 185 assert Alphabet.generic_alphabet.contains(alphabet) 186 self.alphabet = alphabet 187 188 # If passed alphabet is empty, use the letters in the matrix itself 189 if not self.alphabet.letters: 190 self._alphabet_from_matrix() 191 # Assert matrix size: half or full 192 if not build_later: 193 N = len(self.alphabet.letters) 194 assert len(self) == N ** 2 or len(self) == N * (N + 1) / 2 195 self.ab_list = list(self.alphabet.letters) 196 self.ab_list.sort() 197 # Names: a string like "BLOSUM62" or "PAM250" 198 self.mat_name = mat_name 199 if build_later: 200 self._init_zero() 201 else: 202 # Convert full to half 203 self._full_to_half() 204 self._correct_matrix() 205 self.sum_letters = {} 206 self.relative_entropy = 0
207
208 - def _correct_matrix(self):
209 """Sort key tuples (PRIVATE).""" 210 for key in self: 211 if key[0] > key[1]: 212 self[(key[1], key[0])] = self[key] 213 del self[key]
214
215 - def _full_to_half(self):
216 """Convert a full-matrix to a half-matrix.""" 217 # For instance: two entries ('A','C'):13 and ('C','A'):20 will be summed 218 # into ('A','C'): 33 and the index ('C','A') will be deleted 219 # alphabet.letters:('A','A') and ('C','C') will remain the same. 220 221 N = len(self.alphabet.letters) 222 # Do nothing if this is already a half-matrix 223 if len(self) == N * (N + 1) / 2: 224 return 225 for i in self.ab_list: 226 for j in self.ab_list[:self.ab_list.index(i) + 1]: 227 if i != j: 228 self[j, i] = self[j, i] + self[i, j] 229 del self[i, j]
230
231 - def _init_zero(self):
232 """Initialize the ab_list values to zero (PRIVATE).""" 233 for i in self.ab_list: 234 for j in self.ab_list[:self.ab_list.index(i) + 1]: 235 self[j, i] = 0.
236
237 - def make_entropy(self):
238 """Calculate and set the entropy attribute.""" 239 self.entropy = 0 240 for i in self: 241 if self[i] > EPSILON: 242 self.entropy += self[i] * log(self[i]) / log(2) 243 self.entropy = -self.entropy
244
245 - def sum(self):
246 """Return sum of the results.""" 247 result = {} 248 for letter in self.alphabet.letters: 249 result[letter] = 0.0 250 for pair, value in self.items(): 251 i1, i2 = pair 252 if i1 == i2: 253 result[i1] += value 254 else: 255 result[i1] += value / 2 256 result[i2] += value / 2 257 return result
258
259 - def print_full_mat(self, f=None, format="%4d", topformat="%4s", 260 alphabet=None, factor=1, non_sym=None):
261 """Print the full matrix to the file handle f or stdout.""" 262 f = f or sys.stdout 263 # create a temporary dictionary, which holds the full matrix for 264 # printing 265 assert non_sym is None or isinstance(non_sym, float) or \ 266 isinstance(non_sym, int) 267 full_mat = copy.copy(self) 268 for i in self: 269 if i[0] != i[1]: 270 full_mat[(i[1], i[0])] = full_mat[i] 271 if not alphabet: 272 alphabet = self.ab_list 273 topline = '' 274 for i in alphabet: 275 topline = topline + topformat % i 276 topline = topline + '\n' 277 f.write(topline) 278 for i in alphabet: 279 outline = i 280 for j in alphabet: 281 if alphabet.index(j) > alphabet.index(i) and non_sym is not None: 282 val = non_sym 283 else: 284 val = full_mat[i, j] 285 val *= factor 286 if val <= -999: 287 cur_str = ' ND' 288 else: 289 cur_str = format % val 290 291 outline = outline + cur_str 292 outline = outline + '\n' 293 f.write(outline)
294
295 - def print_mat(self, f=None, format="%4d", bottomformat="%4s", 296 alphabet=None, factor=1):
297 """Print a nice half-matrix. 298 299 f=sys.stdout to see on the screen. 300 301 User may pass own alphabet, which should contain all letters in the 302 alphabet of the matrix, but may be in a different order. This 303 order will be the order of the letters on the axes. 304 """ 305 f = f or sys.stdout 306 if not alphabet: 307 alphabet = self.ab_list 308 bottomline = '' 309 for i in alphabet: 310 bottomline = bottomline + bottomformat % i 311 bottomline = bottomline + '\n' 312 for i in alphabet: 313 outline = i 314 for j in alphabet[:alphabet.index(i) + 1]: 315 try: 316 val = self[j, i] 317 except KeyError: 318 val = self[i, j] 319 val *= factor 320 if val == -999: 321 cur_str = ' ND' 322 else: 323 cur_str = format % val 324 325 outline = outline + cur_str 326 outline = outline + '\n' 327 f.write(outline) 328 f.write(bottomline)
329
330 - def __str__(self):
331 """Print a nice half-matrix.""" 332 output = "" 333 alphabet = self.ab_list 334 n = len(alphabet) 335 for i in range(n): 336 c1 = alphabet[i] 337 output += c1 338 for j in range(i + 1): 339 c2 = alphabet[j] 340 try: 341 val = self[c2, c1] 342 except KeyError: 343 val = self[c1, c2] 344 if val == -999: 345 output += ' ND' 346 else: 347 output += "%4d" % val 348 output += '\n' 349 output += '%4s' * n % tuple(alphabet) + "\n" 350 return output
351
352 - def __sub__(self, other):
353 """Return integer subtraction product of the two matrices.""" 354 mat_diff = 0 355 for i in self: 356 mat_diff += (self[i] - other[i]) 357 return mat_diff
358
359 - def __mul__(self, other):
360 """Matrix multiplication. 361 362 Returns a matrix for which each entry is the multiplication product of 363 the two matrices passed. 364 """ 365 new_mat = copy.copy(self) 366 for i in self: 367 new_mat[i] *= other[i] 368 return new_mat
369
370 - def __add__(self, other):
371 """Matrix addition.""" 372 new_mat = copy.copy(self) 373 for i in self: 374 new_mat[i] += other[i] 375 return new_mat
376 377
378 -class AcceptedReplacementsMatrix(SeqMat):
379 """Accepted replacements matrix."""
380 381
382 -class ObservedFrequencyMatrix(SeqMat):
383 """Observed frequency matrix."""
384 385
386 -class ExpectedFrequencyMatrix(SeqMat):
387 """Expected frequency matrix."""
388 389
390 -class SubstitutionMatrix(SeqMat):
391 """Substitution matrix.""" 392
393 - def calculate_relative_entropy(self, obs_freq_mat):
394 """Calculate and return relative entropy w.r.t. observed frequency matrix.""" 395 relative_entropy = 0. 396 for key, value in self.items(): 397 if value > EPSILON: 398 relative_entropy += obs_freq_mat[key] * log(value) 399 relative_entropy /= log(2) 400 return relative_entropy
401 402
403 -class LogOddsMatrix(SeqMat):
404 """Log odds matrix.""" 405
406 - def calculate_relative_entropy(self, obs_freq_mat):
407 """Calculate and return relative entropy w.r.t. observed frequency matrix.""" 408 relative_entropy = 0. 409 for key, value in self.items(): 410 relative_entropy += obs_freq_mat[key] * value / log(2) 411 return relative_entropy
412 413
414 -def _build_obs_freq_mat(acc_rep_mat):
415 """Build observed frequency matrix (PRIVATE). 416 417 Build the observed frequency matrix. from an accepted replacements matrix. 418 The acc_rep_mat matrix should be generated by the user. 419 """ 420 # Note: acc_rep_mat should already be a half_matrix!! 421 total = float(sum(acc_rep_mat.values())) 422 obs_freq_mat = ObservedFrequencyMatrix(alphabet=acc_rep_mat.alphabet, 423 build_later=1) 424 for i in acc_rep_mat: 425 obs_freq_mat[i] = acc_rep_mat[i] / total 426 return obs_freq_mat
427 428
429 -def _exp_freq_table_from_obs_freq(obs_freq_mat):
430 """Build expected frequence table from observed frequences (PRIVATE).""" 431 exp_freq_table = {} 432 for i in obs_freq_mat.alphabet.letters: 433 exp_freq_table[i] = 0. 434 for i in obs_freq_mat: 435 if i[0] == i[1]: 436 exp_freq_table[i[0]] += obs_freq_mat[i] 437 else: 438 exp_freq_table[i[0]] += obs_freq_mat[i] / 2. 439 exp_freq_table[i[1]] += obs_freq_mat[i] / 2. 440 return FreqTable.FreqTable(exp_freq_table, FreqTable.FREQ)
441 442
443 -def _build_exp_freq_mat(exp_freq_table):
444 """Build an expected frequency matrix (PRIVATE). 445 446 exp_freq_table: should be a FreqTable instance 447 """ 448 exp_freq_mat = ExpectedFrequencyMatrix(alphabet=exp_freq_table.alphabet, 449 build_later=1) 450 for i in exp_freq_mat: 451 if i[0] == i[1]: 452 exp_freq_mat[i] = exp_freq_table[i[0]] ** 2 453 else: 454 exp_freq_mat[i] = 2.0 * exp_freq_table[i[0]] * exp_freq_table[i[1]] 455 return exp_freq_mat
456 457 458 # 459 # Build the substitution matrix 460 #
461 -def _build_subs_mat(obs_freq_mat, exp_freq_mat):
462 """Build the substitution matrix OPRIVATE).""" 463 if obs_freq_mat.ab_list != exp_freq_mat.ab_list: 464 raise ValueError("Alphabet mismatch in passed matrices") 465 subs_mat = SubstitutionMatrix(obs_freq_mat) 466 for i in obs_freq_mat: 467 subs_mat[i] = obs_freq_mat[i] / exp_freq_mat[i] 468 return subs_mat
469 470 471 # 472 # Build a log-odds matrix 473 #
474 -def _build_log_odds_mat(subs_mat, logbase=2, factor=10.0, round_digit=0, keep_nd=0):
475 """Build a log-odds matrix (PRIVATE). 476 477 - logbase=2: base of logarithm used to build (default 2) 478 - factor=10.: a factor by which each matrix entry is multiplied 479 - round_digit: roundoff place after decimal point 480 - keep_nd: if true, keeps the -999 value for non-determined values (for which 481 there are no substitutions in the frequency substitutions matrix). If false, 482 plants the minimum log-odds value of the matrix in entries containing -999. 483 484 """ 485 lo_mat = LogOddsMatrix(subs_mat) 486 for key, value in subs_mat.items(): 487 if value < EPSILON: 488 lo_mat[key] = -999 489 else: 490 lo_mat[key] = round(factor * log(value) / log(logbase), round_digit) 491 mat_min = min(lo_mat.values()) 492 if not keep_nd: 493 for i in lo_mat: 494 if lo_mat[i] <= -999: 495 lo_mat[i] = mat_min 496 return lo_mat
497 498 499 # 500 # External function. User provides an accepted replacement matrix, and, 501 # optionally the following: expected frequency table, log base, mult. factor, 502 # and rounding factor. Generates a log-odds matrix, calling internal SubsMat 503 # functions. 504 #
505 -def make_log_odds_matrix(acc_rep_mat, exp_freq_table=None, logbase=2, 506 factor=1., round_digit=9, keep_nd=0):
507 """Make log-odds matrix.""" 508 obs_freq_mat = _build_obs_freq_mat(acc_rep_mat) 509 if not exp_freq_table: 510 exp_freq_table = _exp_freq_table_from_obs_freq(obs_freq_mat) 511 exp_freq_mat = _build_exp_freq_mat(exp_freq_table) 512 subs_mat = _build_subs_mat(obs_freq_mat, exp_freq_mat) 513 lo_mat = _build_log_odds_mat(subs_mat, logbase, factor, round_digit, keep_nd) 514 return lo_mat
515 516
517 -def observed_frequency_to_substitution_matrix(obs_freq_mat):
518 """Convert observed frequency table into substitution matrix.""" 519 exp_freq_table = _exp_freq_table_from_obs_freq(obs_freq_mat) 520 exp_freq_mat = _build_exp_freq_mat(exp_freq_table) 521 subs_mat = _build_subs_mat(obs_freq_mat, exp_freq_mat) 522 return subs_mat
523 524
525 -def read_text_matrix(data_file):
526 """Read a matrix from a text file.""" 527 matrix = {} 528 tmp = data_file.read().split("\n") 529 table = [] 530 for i in tmp: 531 table.append(i.split()) 532 # remove records beginning with ``#'' 533 for rec in table[:]: 534 if (rec.count('#') > 0): 535 table.remove(rec) 536 537 # remove null lists 538 while (table.count([]) > 0): 539 table.remove([]) 540 # build a dictionary 541 alphabet = table[0] 542 j = 0 543 for rec in table[1:]: 544 # print(j) 545 row = alphabet[j] 546 # row = rec[0] 547 if re.compile('[A-z\*]').match(rec[0]): 548 first_col = 1 549 else: 550 first_col = 0 551 i = 0 552 for field in rec[first_col:]: 553 col = alphabet[i] 554 matrix[(row, col)] = float(field) 555 i += 1 556 j += 1 557 # delete entries with an asterisk 558 for i in matrix: 559 if '*' in i: 560 del(matrix[i]) 561 ret_mat = SeqMat(matrix) 562 return ret_mat
563 564 565 diagNO = 1 566 diagONLY = 2 567 diagALL = 3 568 569
570 -def two_mat_relative_entropy(mat_1, mat_2, logbase=2, diag=diagALL):
571 """Return relative entropy of two matrices.""" 572 rel_ent = 0. 573 key_list_1 = sorted(mat_1) 574 key_list_2 = sorted(mat_2) 575 key_list = [] 576 sum_ent_1 = 0. 577 sum_ent_2 = 0. 578 for i in key_list_1: 579 if i in key_list_2: 580 key_list.append(i) 581 if len(key_list_1) != len(key_list_2): 582 sys.stderr.write("Warning: first matrix has more entries than the second\n") 583 if key_list_1 != key_list_2: 584 sys.stderr.write("Warning: indices not the same between matrices\n") 585 for key in key_list: 586 if diag == diagNO and key[0] == key[1]: 587 continue 588 if diag == diagONLY and key[0] != key[1]: 589 continue 590 if mat_1[key] > EPSILON and mat_2[key] > EPSILON: 591 sum_ent_1 += mat_1[key] 592 sum_ent_2 += mat_2[key] 593 594 for key in key_list: 595 if diag == diagNO and key[0] == key[1]: 596 continue 597 if diag == diagONLY and key[0] != key[1]: 598 continue 599 if mat_1[key] > EPSILON and mat_2[key] > EPSILON: 600 val_1 = mat_1[key] / sum_ent_1 601 val_2 = mat_2[key] / sum_ent_2 602 # rel_ent += mat_1[key] * log(mat_1[key]/mat_2[key])/log(logbase) 603 rel_ent += val_1 * log(val_1 / val_2) / log(logbase) 604 return rel_ent
605 606
607 -def two_mat_correlation(mat_1, mat_2):
608 """Return linear correlation coefficient between two matrices.""" 609 try: 610 import numpy 611 except ImportError: 612 raise ImportError("Please install Numerical Python (numpy) if you want to use this function") 613 values = [] 614 assert mat_1.ab_list == mat_2.ab_list 615 for ab_pair in mat_1: 616 try: 617 values.append((mat_1[ab_pair], mat_2[ab_pair])) 618 except KeyError: 619 raise ValueError("%s is not a common key" % ab_pair) 620 correlation_matrix = numpy.corrcoef(values, rowvar=0) 621 correlation = correlation_matrix[0, 1] 622 return correlation
623 624
625 -def two_mat_DJS(mat_1, mat_2, pi_1=0.5, pi_2=0.5):
626 """Return Jensen-Shannon Distance between two observed frequence matrices.""" 627 assert mat_1.ab_list == mat_2.ab_list 628 assert pi_1 > 0 and pi_2 > 0 and pi_1 < 1 and pi_2 < 1 629 assert not (pi_1 + pi_2 - 1.0 > EPSILON) 630 sum_mat = SeqMat(build_later=1) 631 sum_mat.ab_list = mat_1.ab_list 632 for i in mat_1: 633 sum_mat[i] = pi_1 * mat_1[i] + pi_2 * mat_2[i] 634 sum_mat.make_entropy() 635 mat_1.make_entropy() 636 mat_2.make_entropy() 637 # print(mat_1.entropy, mat_2.entropy) 638 dJS = sum_mat.entropy - pi_1 * mat_1.entropy - pi_2 * mat_2.entropy 639 return dJS
640 641 642 """ 643 This isn't working yet. Boo hoo! 644 def two_mat_print(mat_1, mat_2, f=None, alphabet=None, factor_1=1, factor_2=1, 645 format="%4d", bottomformat="%4s", topformat="%4s", 646 topindent=7*" ", bottomindent=1*" "): 647 f = f or sys.stdout 648 if not alphabet: 649 assert mat_1.ab_list == mat_2.ab_list 650 alphabet = mat_1.ab_list 651 len_alphabet = len(alphabet) 652 print_mat = {} 653 topline = topindent 654 bottomline = bottomindent 655 for i in alphabet: 656 bottomline += bottomformat % i 657 topline += topformat % alphabet[len_alphabet-alphabet.index(i)-1] 658 topline += '\n' 659 bottomline += '\n' 660 f.write(topline) 661 for i in alphabet: 662 for j in alphabet: 663 print_mat[i, j] = -999 664 diag_1 = {} 665 diag_2 = {} 666 for i in alphabet: 667 for j in alphabet[:alphabet.index(i)+1]: 668 if i == j: 669 diag_1[i] = mat_1[(i, i)] 670 diag_2[i] = mat_2[(alphabet[len_alphabet-alphabet.index(i)-1], 671 alphabet[len_alphabet-alphabet.index(i)-1])] 672 else: 673 if i > j: 674 key = (j, i) 675 else: 676 key = (i, j) 677 mat_2_key = [alphabet[len_alphabet-alphabet.index(key[0])-1], 678 alphabet[len_alphabet-alphabet.index(key[1])-1]] 679 # print(mat_2_key) 680 mat_2_key.sort() 681 mat_2_key = tuple(mat_2_key) 682 # print("%s||%s" % (key, mat_2_key) 683 print_mat[key] = mat_2[mat_2_key] 684 print_mat[(key[1], key[0])] = mat_1[key] 685 for i in alphabet: 686 outline = i 687 for j in alphabet: 688 if i == j: 689 if diag_1[i] == -999: 690 val_1 = ' ND' 691 else: 692 val_1 = format % (diag_1[i]*factor_1) 693 if diag_2[i] == -999: 694 val_2 = ' ND' 695 else: 696 val_2 = format % (diag_2[i]*factor_2) 697 cur_str = val_1 + " " + val_2 698 else: 699 if print_mat[(i, j)] == -999: 700 val = ' ND' 701 elif alphabet.index(i) > alphabet.index(j): 702 val = format % (print_mat[(i, j)]*factor_1) 703 else: 704 val = format % (print_mat[(i, j)]*factor_2) 705 cur_str = val 706 outline += cur_str 707 outline += bottomformat % (alphabet[len_alphabet-alphabet.index(i)-1] + 708 '\n') 709 f.write(outline) 710 f.write(bottomline) 711 """ 712