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  * Generation of an expected frequency table from an observed frequency 
 99    matrix. 
100  * Calculation of linear correlation coefficient between two matrices. 
101  * Calculation of relative entropy is now done using the 
102    _make_relative_entropy method and is stored in the member 
103    self.relative_entropy 
104  * Calculation of entropy is now done using the _make_entropy method and 
105    is stored in the member self.entropy. 
106  * Jensen-Shannon distance between the distributions from which the 
107    matrices are derived. This is a distance function based on the 
108    distribution's entropies. 
109  """ 
110   
111   
112  from __future__ import print_function 
113   
114  import re 
115  import sys 
116  import copy 
117  import math 
118  import warnings 
119   
120  # BioPython imports 
121  import Bio 
122  from Bio import Alphabet 
123  from Bio.SubsMat import FreqTable 
124   
125  __docformat__ = "restructuredtext en" 
126   
127  log = math.log 
128  # Matrix types 
129  NOTYPE = 0 
130  ACCREP = 1 
131  OBSFREQ = 2 
132  SUBS = 3 
133  EXPFREQ = 4 
134  LO = 5 
135  EPSILON = 0.00000000000001 
136   
137   
138 -class SeqMat(dict):
139 """A Generic sequence matrix class 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 - def _alphabet_from_matrix(self):
145 ab_dict = {} 146 s = '' 147 for i in self: 148 ab_dict[i[0]] = 1 149 ab_dict[i[1]] = 1 150 for i in sorted(ab_dict): 151 s += i 152 self.alphabet.letters = s
153
154 - def __init__(self, data=None, alphabet=None, mat_name='', build_later=0):
155 # User may supply: 156 # data: matrix itself 157 # mat_name: its name. See below. 158 # alphabet: an instance of Bio.Alphabet, or a subclass. If not 159 # supplied, constructor builds its own from that matrix. 160 # build_later: skip the matrix size assertion. User will build the 161 # matrix after creating the instance. Constructor builds a half matrix 162 # filled with zeroes. 163 164 assert isinstance(mat_name, str) 165 166 # "data" may be: 167 # 1) None --> then self.data is an empty dictionary 168 # 2) type({}) --> then self takes the items in data 169 # 3) An instance of SeqMat 170 # This whole creation-during-execution is done to avoid changing 171 # default values, the way Python does because default values are 172 # created when the function is defined, not when it is created. 173 if data: 174 try: 175 self.update(data) 176 except ValueError: 177 raise ValueError("Failed to store data in a dictionary") 178 if alphabet is None: 179 alphabet = Alphabet.Alphabet() 180 assert Alphabet.generic_alphabet.contains(alphabet) 181 self.alphabet = alphabet 182 183 # If passed alphabet is empty, use the letters in the matrix itself 184 if not self.alphabet.letters: 185 self._alphabet_from_matrix() 186 # Assert matrix size: half or full 187 if not build_later: 188 N = len(self.alphabet.letters) 189 assert len(self) == N**2 or len(self) == N*(N+1)/2 190 self.ab_list = list(self.alphabet.letters) 191 self.ab_list.sort() 192 # Names: a string like "BLOSUM62" or "PAM250" 193 self.mat_name = mat_name 194 if build_later: 195 self._init_zero() 196 else: 197 # Convert full to half 198 self._full_to_half() 199 self._correct_matrix() 200 self.sum_letters = {} 201 self.relative_entropy = 0
202
203 - def _correct_matrix(self):
204 for key in self: 205 if key[0] > key[1]: 206 self[(key[1], key[0])] = self[key] 207 del self[key]
208
209 - def _full_to_half(self):
210 """ 211 Convert a full-matrix to a half-matrix 212 """ 213 # For instance: two entries ('A','C'):13 and ('C','A'):20 will be summed 214 # into ('A','C'): 33 and the index ('C','A') will be deleted 215 # alphabet.letters:('A','A') and ('C','C') will remain the same. 216 217 N = len(self.alphabet.letters) 218 # Do nothing if this is already a half-matrix 219 if len(self) == N*(N+1)/2: 220 return 221 for i in self.ab_list: 222 for j in self.ab_list[:self.ab_list.index(i)+1]: 223 if i != j: 224 self[j, i] = self[j, i] + self[i, j] 225 del self[i, j]
226
227 - def _init_zero(self):
228 for i in self.ab_list: 229 for j in self.ab_list[:self.ab_list.index(i)+1]: 230 self[j, i] = 0.
231
232 - def make_entropy(self):
233 self.entropy = 0 234 for i in self: 235 if self[i] > EPSILON: 236 self.entropy += self[i]*log(self[i])/log(2) 237 self.entropy = -self.entropy
238
239 - def sum(self):
240 result = {} 241 for letter in self.alphabet.letters: 242 result[letter] = 0.0 243 for pair, value in self.items(): 244 i1, i2 = pair 245 if i1 == i2: 246 result[i1] += value 247 else: 248 result[i1] += value / 2 249 result[i2] += value / 2 250 return result
251
252 - def print_full_mat(self, f=None, format="%4d", topformat="%4s", 253 alphabet=None, factor=1, non_sym=None):
254 f = f or sys.stdout 255 # create a temporary dictionary, which holds the full matrix for 256 # printing 257 assert non_sym is None or isinstance(non_sym, float) or \ 258 isinstance(non_sym, int) 259 full_mat = copy.copy(self) 260 for i in self: 261 if i[0] != i[1]: 262 full_mat[(i[1], i[0])] = full_mat[i] 263 if not alphabet: 264 alphabet = self.ab_list 265 topline = '' 266 for i in alphabet: 267 topline = topline + topformat % i 268 topline = topline + '\n' 269 f.write(topline) 270 for i in alphabet: 271 outline = i 272 for j in alphabet: 273 if alphabet.index(j) > alphabet.index(i) and non_sym is not None: 274 val = non_sym 275 else: 276 val = full_mat[i, j] 277 val *= factor 278 if val <= -999: 279 cur_str = ' ND' 280 else: 281 cur_str = format % val 282 283 outline = outline+cur_str 284 outline = outline + '\n' 285 f.write(outline)
286
287 - def print_mat(self, f=None, format="%4d", bottomformat="%4s", 288 alphabet=None, factor=1):
289 """Print a nice half-matrix. f=sys.stdout to see on the screen 290 User may pass own alphabet, which should contain all letters in the 291 alphabet of the matrix, but may be in a different order. This 292 order will be the order of the letters on the axes""" 293 294 f = f or sys.stdout 295 if not alphabet: 296 alphabet = self.ab_list 297 bottomline = '' 298 for i in alphabet: 299 bottomline = bottomline + bottomformat % i 300 bottomline = bottomline + '\n' 301 for i in alphabet: 302 outline = i 303 for j in alphabet[:alphabet.index(i)+1]: 304 try: 305 val = self[j, i] 306 except KeyError: 307 val = self[i, j] 308 val *= factor 309 if val == -999: 310 cur_str = ' ND' 311 else: 312 cur_str = format % val 313 314 outline = outline + cur_str 315 outline = outline + '\n' 316 f.write(outline) 317 f.write(bottomline)
318
319 - def __str__(self):
320 """Print a nice half-matrix.""" 321 output = "" 322 alphabet = self.ab_list 323 n = len(alphabet) 324 for i in range(n): 325 c1 = alphabet[i] 326 output += c1 327 for j in range(i+1): 328 c2 = alphabet[j] 329 try: 330 val = self[c2, c1] 331 except KeyError: 332 val = self[c1, c2] 333 if val == -999: 334 output += ' ND' 335 else: 336 output += "%4d" % val 337 output += '\n' 338 output += '%4s' * n % tuple(alphabet) + "\n" 339 return output
340
341 - def __sub__(self, other):
342 """ returns a number which is the subtraction product of the two matrices""" 343 mat_diff = 0 344 for i in self: 345 mat_diff += (self[i] - other[i]) 346 return mat_diff
347
348 - def __mul__(self, other):
349 """ returns a matrix for which each entry is the multiplication product of the 350 two matrices passed""" 351 new_mat = copy.copy(self) 352 for i in self: 353 new_mat[i] *= other[i] 354 return new_mat
355
356 - def __add__(self, other):
357 new_mat = copy.copy(self) 358 for i in self: 359 new_mat[i] += other[i] 360 return new_mat
361 362
363 -class AcceptedReplacementsMatrix(SeqMat):
364 """Accepted replacements matrix"""
365 366
367 -class ObservedFrequencyMatrix(SeqMat):
368 """Observed frequency matrix"""
369 370
371 -class ExpectedFrequencyMatrix(SeqMat):
372 """Expected frequency matrix"""
373 374
375 -class SubstitutionMatrix(SeqMat):
376 """Substitution matrix""" 377
378 - def calculate_relative_entropy(self, obs_freq_mat):
379 """Calculate and return the relative entropy with respect to an 380 observed frequency matrix""" 381 relative_entropy = 0. 382 for key, value in self.items(): 383 if value > EPSILON: 384 relative_entropy += obs_freq_mat[key] * log(value) 385 relative_entropy /= log(2) 386 return relative_entropy
387 388
389 -class LogOddsMatrix(SeqMat):
390 """Log odds matrix""" 391
392 - def calculate_relative_entropy(self, obs_freq_mat):
393 """Calculate and return the relative entropy with respect to an 394 observed frequency matrix""" 395 relative_entropy = 0. 396 for key, value in self.items(): 397 relative_entropy += obs_freq_mat[key] * value / log(2) 398 return relative_entropy
399 400
401 -def _build_obs_freq_mat(acc_rep_mat):
402 """ 403 build_obs_freq_mat(acc_rep_mat): 404 Build the observed frequency matrix, from an accepted replacements matrix 405 The acc_rep_mat matrix should be generated by the user. 406 """ 407 # Note: acc_rep_mat should already be a half_matrix!! 408 total = float(sum(acc_rep_mat.values())) 409 obs_freq_mat = ObservedFrequencyMatrix(alphabet=acc_rep_mat.alphabet, 410 build_later=1) 411 for i in acc_rep_mat: 412 obs_freq_mat[i] = acc_rep_mat[i] / total 413 return obs_freq_mat
414 415
416 -def _exp_freq_table_from_obs_freq(obs_freq_mat):
417 exp_freq_table = {} 418 for i in obs_freq_mat.alphabet.letters: 419 exp_freq_table[i] = 0. 420 for i in obs_freq_mat: 421 if i[0] == i[1]: 422 exp_freq_table[i[0]] += obs_freq_mat[i] 423 else: 424 exp_freq_table[i[0]] += obs_freq_mat[i] / 2. 425 exp_freq_table[i[1]] += obs_freq_mat[i] / 2. 426 return FreqTable.FreqTable(exp_freq_table, FreqTable.FREQ)
427 428
429 -def _build_exp_freq_mat(exp_freq_table):
430 """Build an expected frequency matrix 431 exp_freq_table: should be a FreqTable instance 432 """ 433 exp_freq_mat = ExpectedFrequencyMatrix(alphabet=exp_freq_table.alphabet, 434 build_later=1) 435 for i in exp_freq_mat: 436 if i[0] == i[1]: 437 exp_freq_mat[i] = exp_freq_table[i[0]]**2 438 else: 439 exp_freq_mat[i] = 2.0*exp_freq_table[i[0]]*exp_freq_table[i[1]] 440 return exp_freq_mat
441 442 443 # 444 # Build the substitution matrix 445 #
446 -def _build_subs_mat(obs_freq_mat, exp_freq_mat):
447 """ Build the substitution matrix """ 448 if obs_freq_mat.ab_list != exp_freq_mat.ab_list: 449 raise ValueError("Alphabet mismatch in passed matrices") 450 subs_mat = SubstitutionMatrix(obs_freq_mat) 451 for i in obs_freq_mat: 452 subs_mat[i] = obs_freq_mat[i]/exp_freq_mat[i] 453 return subs_mat
454 455 456 # 457 # Build a log-odds matrix 458 #
459 -def _build_log_odds_mat(subs_mat, logbase=2, factor=10.0, round_digit=0, keep_nd=0):
460 """_build_log_odds_mat(subs_mat,logbase=10,factor=10.0,round_digit=1): 461 Build a log-odds matrix 462 logbase=2: base of logarithm used to build (default 2) 463 factor=10.: a factor by which each matrix entry is multiplied 464 round_digit: roundoff place after decimal point 465 keep_nd: if true, keeps the -999 value for non-determined values (for which there 466 are no substitutions in the frequency substitutions matrix). If false, plants the 467 minimum log-odds value of the matrix in entries containing -999 468 """ 469 lo_mat = LogOddsMatrix(subs_mat) 470 for key, value in subs_mat.items(): 471 if value < EPSILON: 472 lo_mat[key] = -999 473 else: 474 lo_mat[key] = round(factor*log(value)/log(logbase), round_digit) 475 mat_min = min(lo_mat.values()) 476 if not keep_nd: 477 for i in lo_mat: 478 if lo_mat[i] <= -999: 479 lo_mat[i] = mat_min 480 return lo_mat
481 482 483 # 484 # External function. User provides an accepted replacement matrix, and, 485 # optionally the following: expected frequency table, log base, mult. factor, 486 # and rounding factor. Generates a log-odds matrix, calling internal SubsMat 487 # functions. 488 #
489 -def make_log_odds_matrix(acc_rep_mat, exp_freq_table=None, logbase=2, 490 factor=1., round_digit=9, keep_nd=0):
491 obs_freq_mat = _build_obs_freq_mat(acc_rep_mat) 492 if not exp_freq_table: 493 exp_freq_table = _exp_freq_table_from_obs_freq(obs_freq_mat) 494 exp_freq_mat = _build_exp_freq_mat(exp_freq_table) 495 subs_mat = _build_subs_mat(obs_freq_mat, exp_freq_mat) 496 lo_mat = _build_log_odds_mat(subs_mat, logbase, factor, round_digit, keep_nd) 497 return lo_mat
498 499
500 -def observed_frequency_to_substitution_matrix(obs_freq_mat):
501 exp_freq_table = _exp_freq_table_from_obs_freq(obs_freq_mat) 502 exp_freq_mat = _build_exp_freq_mat(exp_freq_table) 503 subs_mat = _build_subs_mat(obs_freq_mat, exp_freq_mat) 504 return subs_mat
505 506
507 -def read_text_matrix(data_file):
508 matrix = {} 509 tmp = data_file.read().split("\n") 510 table=[] 511 for i in tmp: 512 table.append(i.split()) 513 # remove records beginning with ``#'' 514 for rec in table[:]: 515 if (rec.count('#') > 0): 516 table.remove(rec) 517 518 # remove null lists 519 while (table.count([]) > 0): 520 table.remove([]) 521 # build a dictionary 522 alphabet = table[0] 523 j = 0 524 for rec in table[1:]: 525 # print(j) 526 row = alphabet[j] 527 # row = rec[0] 528 if re.compile('[A-z\*]').match(rec[0]): 529 first_col = 1 530 else: 531 first_col = 0 532 i = 0 533 for field in rec[first_col:]: 534 col = alphabet[i] 535 matrix[(row, col)] = float(field) 536 i += 1 537 j += 1 538 # delete entries with an asterisk 539 for i in matrix: 540 if '*' in i: 541 del(matrix[i]) 542 ret_mat = SeqMat(matrix) 543 return ret_mat
544 545 diagNO = 1 546 diagONLY = 2 547 diagALL = 3 548 549
550 -def two_mat_relative_entropy(mat_1, mat_2, logbase=2, diag=diagALL):
551 rel_ent = 0. 552 key_list_1 = sorted(mat_1) 553 key_list_2 = sorted(mat_2) 554 key_list = [] 555 sum_ent_1 = 0. 556 sum_ent_2 = 0. 557 for i in key_list_1: 558 if i in key_list_2: 559 key_list.append(i) 560 if len(key_list_1) != len(key_list_2): 561 sys.stderr.write("Warning: first matrix has more entries than the second\n") 562 if key_list_1 != key_list_2: 563 sys.stderr.write("Warning: indices not the same between matrices\n") 564 for key in key_list: 565 if diag == diagNO and key[0] == key[1]: 566 continue 567 if diag == diagONLY and key[0] != key[1]: 568 continue 569 if mat_1[key] > EPSILON and mat_2[key] > EPSILON: 570 sum_ent_1 += mat_1[key] 571 sum_ent_2 += mat_2[key] 572 573 for key in key_list: 574 if diag == diagNO and key[0] == key[1]: 575 continue 576 if diag == diagONLY and key[0] != key[1]: 577 continue 578 if mat_1[key] > EPSILON and mat_2[key] > EPSILON: 579 val_1 = mat_1[key] / sum_ent_1 580 val_2 = mat_2[key] / sum_ent_2 581 # rel_ent += mat_1[key] * log(mat_1[key]/mat_2[key])/log(logbase) 582 rel_ent += val_1 * log(val_1/val_2)/log(logbase) 583 return rel_ent
584 585 586 # Gives the linear correlation coefficient between two matrices
587 -def two_mat_correlation(mat_1, mat_2):
588 try: 589 import numpy 590 except ImportError: 591 raise ImportError("Please install Numerical Python (numpy) if you want to use this function") 592 values = [] 593 assert mat_1.ab_list == mat_2.ab_list 594 for ab_pair in mat_1: 595 try: 596 values.append((mat_1[ab_pair], mat_2[ab_pair])) 597 except KeyError: 598 raise ValueError("%s is not a common key" % ab_pair) 599 correlation_matrix = numpy.corrcoef(values, rowvar=0) 600 correlation = correlation_matrix[0, 1] 601 return correlation
602 603 604 # Jensen-Shannon Distance 605 # Need to input observed frequency matrices
606 -def two_mat_DJS(mat_1, mat_2, pi_1=0.5, pi_2=0.5):
607 assert mat_1.ab_list == mat_2.ab_list 608 assert pi_1 > 0 and pi_2 > 0 and pi_1< 1 and pi_2 <1 609 assert not (pi_1 + pi_2 - 1.0 > EPSILON) 610 sum_mat = SeqMat(build_later=1) 611 sum_mat.ab_list = mat_1.ab_list 612 for i in mat_1: 613 sum_mat[i] = pi_1 * mat_1[i] + pi_2 * mat_2[i] 614 sum_mat.make_entropy() 615 mat_1.make_entropy() 616 mat_2.make_entropy() 617 # print(mat_1.entropy, mat_2.entropy) 618 dJS = sum_mat.entropy - pi_1 * mat_1.entropy - pi_2 * mat_2.entropy 619 return dJS
620 621 """ 622 This isn't working yet. Boo hoo! 623 def two_mat_print(mat_1, mat_2, f=None, alphabet=None, factor_1=1, factor_2=1, 624 format="%4d", bottomformat="%4s", topformat="%4s", 625 topindent=7*" ", bottomindent=1*" "): 626 f = f or sys.stdout 627 if not alphabet: 628 assert mat_1.ab_list == mat_2.ab_list 629 alphabet = mat_1.ab_list 630 len_alphabet = len(alphabet) 631 print_mat = {} 632 topline = topindent 633 bottomline = bottomindent 634 for i in alphabet: 635 bottomline += bottomformat % i 636 topline += topformat % alphabet[len_alphabet-alphabet.index(i)-1] 637 topline += '\n' 638 bottomline += '\n' 639 f.write(topline) 640 for i in alphabet: 641 for j in alphabet: 642 print_mat[i, j] = -999 643 diag_1 = {} 644 diag_2 = {} 645 for i in alphabet: 646 for j in alphabet[:alphabet.index(i)+1]: 647 if i == j: 648 diag_1[i] = mat_1[(i, i)] 649 diag_2[i] = mat_2[(alphabet[len_alphabet-alphabet.index(i)-1], 650 alphabet[len_alphabet-alphabet.index(i)-1])] 651 else: 652 if i > j: 653 key = (j, i) 654 else: 655 key = (i, j) 656 mat_2_key = [alphabet[len_alphabet-alphabet.index(key[0])-1], 657 alphabet[len_alphabet-alphabet.index(key[1])-1]] 658 # print(mat_2_key) 659 mat_2_key.sort() 660 mat_2_key = tuple(mat_2_key) 661 # print("%s||%s" % (key, mat_2_key) 662 print_mat[key] = mat_2[mat_2_key] 663 print_mat[(key[1], key[0])] = mat_1[key] 664 for i in alphabet: 665 outline = i 666 for j in alphabet: 667 if i == j: 668 if diag_1[i] == -999: 669 val_1 = ' ND' 670 else: 671 val_1 = format % (diag_1[i]*factor_1) 672 if diag_2[i] == -999: 673 val_2 = ' ND' 674 else: 675 val_2 = format % (diag_2[i]*factor_2) 676 cur_str = val_1 + " " + val_2 677 else: 678 if print_mat[(i, j)] == -999: 679 val = ' ND' 680 elif alphabet.index(i) > alphabet.index(j): 681 val = format % (print_mat[(i, j)]*factor_1) 682 else: 683 val = format % (print_mat[(i, j)]*factor_2) 684 cur_str = val 685 outline += cur_str 686 outline += bottomformat % (alphabet[len_alphabet-alphabet.index(i)-1] + 687 '\n') 688 f.write(outline) 689 f.write(bottomline) 690 """ 691