)x4hI3tox7Drm517kCS~(BOX&C
z+IdI#ymFt?4-zl0A6`~Y`oT0pC{SuMq9yDGLIzwrwjd&)?uH_KrW|T^nUJK7X0x)|
z>G;a3HC^+k!_a#^jw_7Ka~!5}JiK@Ug&{D#fZ8abKBjU-yy!z9KjFS&@F0=yNxteV
z1Sk>NoC%)364BYhMCbr7hF>fPaBYYrB`0UTD8Z&<752a34k?#?=^=j7n
z?3Hs8YG#pt<5dONkYKbTYCn)Ws9AlLGzc?ia)#buh=qrPjdREhc-}zyd^X6dCI-y2
zR6SBzhEwLXxRb1I<0+zVChLfy^b2F~(Gg6KD^K`pqdoMW=3Z2hmXZK
z%ZX&EFyMK9@W{ZPKyfVaqpewev4VkVmTkW
zc?`yqTQLTW4tbIf<340yz>?KD=fs8Xe$@dwEo#1zujlv{&HTd4CfWt$OUDbEj}mK
zU_D|37=4^?!+*>L_VL~0Etq64@v2=P%QApr1$Sx-ZsvX+hK6Ug;v%U`A&k0(Qc3UK
zcsbbknd4W>y)=j>5$U~YkzV8fUEEyY5Ii?evS$uNtTW}=+rDKtHExXFzu)k>oK%+<
zD{-fl@w92jfkGC?dVMOU3r(Lsp_~95TO+#D>{L^W1r4#X*u(4CtIAnaNUL0F#7T-@
z=PzI^BPDg6Mev^owCrWi;(4-!r@}wwuh-7g7!NgIp<2^7pVg*?H
zb%EzfQhxzq%1f2z;9c;|5LXJ5TDXu8sz23m~joPJH7p;{0|@)mj)p7-101-uuR6EGm^GjVqN)+LX+z3yjV+W%W<{
zI?ZFT$;kf41Sj+s8H3o$~M
zttc5fMm2>WknDN4cD??a+NKEXuh$Jw>{{?QXxhc$Pv42d6}Gp7RA32y<$N#LrnK?w
zOXd->wsMc}-c|8;NrpCe|9CX~2{T{S<_3&;IOoH9-_e`TDX}l#)N?>g%NZQ|;x|Rc
zDEtqa-j{EM(PcmJoL)9~t)W({JKtZ$E6QC|V$ojM$XWEy-}B0~3r9`+@~E#b!+zI2+3IR)QRaMh1tS%u~?WYOis^Ef2DAsaI`R9$cGAu4X&;>0mw;6
zRdyTonsQwdvmAKe-CJSOD<-uDMX`p>Vjm3JH-bi^`?C{6@~8aQj?anpEMk2)w}4hB
PUOhGU!raeYp&0xxc8M(`
diff --git a/scTCRpy/parseTCR.py b/scTCRpy/parseTCR.py
deleted file mode 100644
index 3c1b0b5e4..000000000
--- a/scTCRpy/parseTCR.py
+++ /dev/null
@@ -1,314 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-import json
-
-from utils import stampTime, tabReader, namedMatrix
-
-def __main__():
- print 'This module is not intended for direct command line usage. Currently supports import to Python only.'
- #A table maker function could be added in the future so that parse data could be saved and passed to R
- moduleTest()
- return
-
-def moduleTest():
- print 'Testing module by parsing test TCR data'
- prefix, name = 'S1_', 'Control'
- consensusFile = 'testdata/pbmc_t_consensus_annotations.json'
- contigTabFile = 'testdata/pbmc_t_filtered_contig_annotations.csv'
- tcr = scTCR(verbose=True)
- tcr.addSampleTCR(contigTabFile, consensusFile, prefix, name)
- print 'Number of cells:', len(tcr.cellTable)
- print 'Cell keys:', tcr.cellTable.keys()[:5]
- print 'A cell example:'
- print tcr.cellTable[tcr.cellTable.keys()[0]]
- print 'Consensus keys:', tcr.consensusTable.keys()[:5]
- print 'A consensus example:'
- print tcr.consensusTable[tcr.consensusTable.keys()[0]]
- print 'Clonotype keys:', tcr.clonotypeTable.keys()[:5]
- print 'A clonotype example:'
- print tcr.clonotypeTable[tcr.clonotypeTable.keys()[0]]
- return
-
-defaultCellGroups = {
- 'samples': {},
- 'chain pairing': {
- 'Single pair': [],
- 'Double alpha': [],
- 'Double beta': [],
- 'Double orphan alpha': [],
- 'Double orphan beta': [],
- 'Orphan alpha': [],
- 'Orphan beta': [],
- 'Full doublet': []
- },
- 'TRA V segment usage': {},
- 'TRA D segment usage': {},
- 'TRA J segment usage': {},
- 'TRB V segment usage': {},
- 'TRB D segment usage': {},
- 'TRB J segment usage': {},
- 'major clonotypes': {}
- }
-
-class scTCR:
- def __init__(self, contigTable=None, barcodeRe={}, cellTable={}, consensusTable={}, clonotypeTable={}, clonaliasTable=[{}, {}], cdrTable={}, cellGroups=None, criticalClonotypeSize=4, verbose=False):
- self.barcodeRe=barcodeRe
- self.cellTable=cellTable
- if contigTable == None:
- self.contigTable = namedMatrix(unique=False)
- else:
- self.contigTable=contigTable
- if cellGroups == None:
- self.cellGroups = defaultCellGroups.copy()
- else:
- self.contigTable=contigTable
- self.consensusTable=consensusTable
- self.clonotypeTable=clonotypeTable
- self.clonaliasTable=clonaliasTable
- self.cdrTable=cdrTable
- self.cellGroups=cellGroups
- self.criticalClonotypeSize=criticalClonotypeSize
- self.verbose=verbose
- return
-
- def addSampleTCR(self, contigTabFile, consensusFile, prefix, sname, barcodeRe=None):
- if barcodeRe != None:
- self.barcodeRe = barcodeRe
- self.contigTable, self.barcodeRe, self.cellTable, self.clonotypeTable, self.clonaliasTable, self.cdrTable, self.cellGroups = self.clonotypeFromContigs(contigTabFile, prefix, sname, contigTable=self.contigTable, barcodeRe=self.barcodeRe, cellTable=self.cellTable, clonotypeTable=self.clonotypeTable, clonaliasTable=self.clonaliasTable, cdrTable=self.cdrTable, cellGroups=self.cellGroups)
- self.consensusTable, self.parseConsensus(consensusFile, prefix, self.consensusTable)
- if self.verbose:
- stampTime('TCR data of a new sample with prefix ' + prefix + ' added.')
- return
-
- def clonotypeFromContigs(self, fn, prefix, sname, contigTable=None, barcodeRe={}, cellTable={}, clonotypeTable={}, clonaliasTable=[{}, {}], cdrTable={}, cellGroups=None):
- if cellGroups == None:
- cellGroups = defaultCellGroups.copy()
-
- def lineParse(data, line, lineNum, firstline, includend, test_only=False):
- if test_only:
- return locals()
- if firstline:
- firstline = False
- header = line[1:]
- data.setColNames(line[1:])
- else:
- key = prefix+line[0]
- line = line[1:]
- readcol = data.colnames['reads']
- reads = line[readcol]
- try:
- reads = int(reads)
- except:
- pass
- line[readcol] = reads
- cdr3 = line[data.colnames['cdr3']]
- if cdr3 == 'None':
- cdr3 = ''
- cdr3 = cdr3.replace('*', 'X')
- line[data.colnames['cdr3']] = cdr3
- cdr3_nt = line[data.colnames['cdr3_nt']]
- if cdr3_nt == 'None':
- cdr3_nt = ''
- line[data.colnames['cdr3_nt']] = cdr3_nt
- dat = data.matrixRow(key, line, data)
- data.add(dat)
- return data, firstline, includend
-
- contigTable = tabReader(fn, data=contigTable, tabformatter=lambda x: x, lineformatter=lineParse)
- bySample = cellGroups['samples']
- bySample[sname] = []
- bySample = bySample[sname]
- byChain = cellGroups['chain pairing']
- bySegment = {
- 'TRAV': cellGroups['TRA V segment usage'],
- 'TRAD': cellGroups['TRA D segment usage'],
- 'TRAJ': cellGroups['TRA J segment usage'],
- 'TRBV': cellGroups['TRB V segment usage'],
- 'TRBD': cellGroups['TRB D segment usage'],
- 'TRBJ': cellGroups['TRB J segment usage']
- }
- n = 0
- for m, cell, rowdata in contigTable:
- bc = cell.split(prefix)
- if len(bc) == 2:
- bc = bc[1]
- if cell not in barcodeRe:
- barcodeRe[cell] = []
- barcodeRe[cell].append(bc)
- bySample.append(cell)
- for g in ['v_gene', 'd_gene', 'j_gene', 'c_gene']:
- e = rowdata[g]
- for s in e:
- if s[:4] in bySegment:
- seg = bySegment[s[:4]]
- if s not in seg:
- seg[s] = []
- bySegment[s[:4]][s].append(cell)
- numcellchains, cellchains = len(e), {'TRA': ['', 0, '', ''], 'TRB': ['', 0, '', ''], '_TRA': ['', 0, '', ''], '_TRB': ['', 0, '', '']}
- n += numcellchains
- for i in range(0, numcellchains):
- cdr3 = rowdata['cdr3'][i]
- cdr3_nt = rowdata['cdr3_nt'][i]
- chain = rowdata['chain'][i]
- reads = rowdata['reads'][i]
- cons = prefix+rowdata['raw_consensus_id'][i]
- if chain in ['TRA', 'TRB']:
- if cellchains[chain][0] == '':
- cellchains[chain] = [cdr3, reads, cdr3_nt, cons]
- else:
- if reads > cellchains[chain][1] :
- if cdr3 == '':
- if cellchains['_'+chain] == '' and reads > cellchains['_'+chain][1]:
- cellchains['_'+chain] = [cdr3, reads, cdr3_nt, cons]
- else:
- cellchains['_'+chain] = cellchains[chain][:]
- cellchains[chain] = [cdr3, reads, cdr3_nt, cons]
- else:
- cellchains['_'+chain] = [cdr3, reads, cdr3_nt, cons]
- if cellchains['TRA'][0] == '':
- if cellchains['TRB'][0] == '':
- pass
- else:
- if cellchains['_TRB'][0] == '':
- byChain['Orphan beta'].append(cell)
- else:
- byChain['Double orphan beta'].append(cell)
- else:
- if cellchains['TRB'][0] == '':
- if cellchains['_TRA'][0] == '':
- byChain['Orphan alpha'].append(cell)
- else:
- byChain['Double orphan alpha'].append(cell)
- else:
- if cellchains['_TRB'][0] == '':
- if cellchains['_TRA'][0] == '':
- byChain['Single pair'].append(cell)
- else:
- byChain['Double alpha'].append(cell)
- else:
- if cellchains['_TRA'][0] == '':
- byChain['Double beta'].append(cell)
- else:
- byChain['Full doublet'].append(cell)
- cloneID = '|'.join([cellchains[x][0] for x in ['TRA', 'TRB', '_TRA', '_TRB']])
- if cloneID in clonaliasTable[0]:
- clonotype = clonaliasTable[0][cloneID]
- else:
- clonotype = 'ct_'+cell
- clonaliasTable[0][cloneID] = clonotype
- clonotypeTable[clonotype] = {
- 'cells': [],
- 'cdrSym': cloneID,
- 'alias': '',
- 'chains': {
- 'TRA': {
- 'primary_cdr3_aa': cellchains['TRA'][0],
- 'primary_cdr3_nt': cellchains['TRA'][2],
- 'primary_consensus': cellchains['TRA'][3],
- 'secondary_cdr3_aa': cellchains['_TRA'][0],
- 'secondary_cdr3_nt': cellchains['_TRA'][2],
- 'secondary_consensus': cellchains['_TRA'][3]
- },
- 'TRB': {
- 'primary_cdr3_aa': cellchains['TRB'][0],
- 'primary_cdr3_nt': cellchains['TRB'][2],
- 'primary_consensus': cellchains['TRB'][3],
- 'secondary_cdr3_aa': cellchains['_TRB'][0],
- 'secondary_cdr3_nt': cellchains['_TRB'][2],
- 'secondary_consensus': cellchains['_TRB'][3]
- }
- }
- }
- clonotypeTable[clonotype]['cells'].append(cell)
- for i in range(0, numcellchains):
- cdr = rowdata['cdr3'][i]
- inalfa, inbeta = 0, 0
- chain = rowdata['chain'][i]
- if chain == 'TRA':
- inalfa += 1
- if chain == 'TRB':
- inbeta += 1
- if cdr not in cdrTable:
- cdrTable[cdr] = {'nt_seq': [rowdata['cdr3_nt'][i]], 'cells': [cell], 'clonotypes': [clonotype]}
- else:
- cdrTable[cdr]['nt_seq'].append(rowdata['cdr3_nt'][i])
- cdrTable[cdr]['cells'].append(cell)
- cdrTable[cdr]['clonotypes'].append(clonotype)
- cellTable[cell] = {'clonotype': clonotype, 'chain_epression': {'TRA': cellchains['TRA'][1], 'TRB': cellchains['TRB'][1], '_TRA': cellchains['_TRA'][1], '_TRB': cellchains['_TRB'][1]}}
- numPairTcells = len(set(bySample)&set(cellGroups['chain pairing']['Single pair']))
- if self.verbose:
- stampTime('TCR sequences of ' + str(n) + ' contigs of ' + str(len(bySample)) + ' cells parsed (' + str(numPairTcells) + ' of these have a single TCR chain pair).')
- return contigTable, barcodeRe, cellTable, clonotypeTable, clonaliasTable, cdrTable, cellGroups
-
- def collectSegments(self, annotations, cdrStart, cdrStop):
- segments, segline = [], []
- for anne in annotations:
- segments.append([anne['feature']['gene_name'], anne['contig_match_start'], anne['contig_match_end']])
- chain = anne['feature']['chain']
- segments.sort(key=lambda x: x[2])
- previ, inserted = 0, 0
- for s in segments:
- difi = s[1] - previ
- if previ >= cdrStart:
- if s[1] <= cdrStop:
- inserted += difi
- previ = s[2]
- if previ >= cdrStart:
- if s[1] <= cdrStop:
- segline.append(s[0])
- return inserted, segments, segline, chain
-
- def parseConsensus(self, fn, prefix, consensusTable):
- with open(fn) as f:
- data = json.load(f)
- for clone in data:
- contid, clonotype, seq, aas, info = prefix+clone['contig_name'], prefix+clone['clonotype'], clone['sequence'], clone['aa_sequence'], clone['info']
- cdrAA, cdrNuc, cdrStart, cdrStop = clone['cdr3'], clone['cdr3_seq'], clone['cdr3_start'], clone['cdr3_stop']
- highConf, mayProd, beenFilt = clone['high_confidence'], clone['productive'], clone['filtered']
- inserted, segments, segline, chain = self.collectSegments(clone['annotations'], cdrStart, cdrStop)
- consensusTable[contid] = {
- 'clonotype': clonotype,
- 'nseq': seq,
- 'aseq': aas,
- 'ncdr': cdrNuc,
- 'acdr': cdrAA,
- 'conf': highConf,
- 'prod': mayProd,
- 'filt': beenFilt,
- 'chain': chain,
- 'segments': segline,
- 'cdrlen': len(cdrAA),
- 'addednuc': inserted
- }
- for k, v in info.iteritems():
- if k not in ['cells', 'cell_contigs']:
- consensusTable[contid][k] = v
- consensusTable[contid]['cells'] = [prefix+x for x in info['cells']]
- consensusTable[contid]['cell_contigs'] = [prefix+x for x in info['cell_contigs']]
- if self.verbose:
- stampTime('Consensus contig annotations parsed.')
- return consensusTable
-
- def reassessClonotypes(self):
- sortand = []
- for clone, info in self.clonotypeTable.iteritems():
- N = len(info['cells'])
- info['cellNum'] = N
- if N >= self.criticalClonotypeSize:
- if info['cdrSym'] != '|||':
- sortand.append([clone, N])
- sortand.sort(key= lambda x: x[1], reverse=True)
- n = 0
- for a, b in sortand:
- n += 1
- newname = 'clonotype_'+str(n)
- self.clonotypeTable[a]['alias'] = newname
- self.cellGroups['major clonotypes'][newname] = self.clonotypeTable[a]['cells'][:]
- self.clonaliasTable[1][newname] = a
- if self.verbose:
- stampTime('After reassignment of clonotypes, ' + str(len(self.cellGroups['major clonotypes'])) + ' major clonotypes were found.')
- return
-
-if __name__ == '__main__':
- __main__()
\ No newline at end of file
diff --git a/scTCRpy/parseTCR.pyc b/scTCRpy/parseTCR.pyc
deleted file mode 100644
index a365c35de7542c76e890b423a00eb5469eeae1b5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 11146
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
diff --git a/scTCRpy/plotGraphs.py b/scTCRpy/plotGraphs.py
deleted file mode 100644
index dfcaa0dd3..000000000
--- a/scTCRpy/plotGraphs.py
+++ /dev/null
@@ -1,669 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-
-import math, collections, matplotlib
-matplotlib.use('Agg')
-import matplotlib.pyplot as plt
-import numpy as np
-import seaborn as sns
-import pandas as pd
-
-def __main__():
- print 'This module is not intended for direct command line usage. Currently suports import to Python only.'
- return
-
-class colorPalette:
- def __init__(self, colors, expandcorrection=1, shiftcorrection=0, is_divergent=False):
- self.N = len(colors)
- self.colors = tuple(colors)
- self.a = expandcorrection
- self.b = shiftcorrection
- if is_divergent:
- self.a = self.a*0.5
- self.b = self.b+0.5
- return
-
- def __getitem__(self, i):
- if type(i) == str:
- return i
- else:
- if type(i) == list:
- colorl = []
- for e in i:
- color = self.colors[0]
- if isinstance(e, int):
- color = self.colorOfInt(e)
- else:
- if isinstance(e, float):
- color = self.colorOfFloat(e)
- colorl.append(color)
- return colorl
- else:
- if isinstance(i, int):
- return self.colorOfInt(i)
- else:
- if isinstance(i, float):
- return self.colorOfFloat(i)
- else:
- return self.colors[0]
-
- def colorOfInt(self, i):
- if i < self.N:
- return self.colors[i]
- else:
- return self.colors[-1]
- return
-
- def colorOfFloat(self, i):
- x = self.a*i + self.b
- if x > 0:
- if x < 1:
- return self.colors[int(self.N*x)]
- else:
- return self.colors[-1]
- else:
- return self.colors[0]
-
-discretePal = colorPalette(['#008E9B', '#0087AF', '#407CB8', '#746DB1', '#9B5A99', '#B14A73'])
-discretePal = colorPalette(['#4980d8', '#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#ffe900', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080'])
-continousPal = colorPalette([(1.0, 1.0, 0.8980392156862745, 1.0), (0.9990157631680123, 0.9996309111880046, 0.8926259131103422, 1.0), (0.9980315263360247, 0.9992618223760092, 0.8872126105344099, 1.0), (0.9970472895040369, 0.9988927335640139, 0.8817993079584775, 1.0), (0.9950788158400615, 0.9981545559400231, 0.8709727028066129, 1.0), (0.9940945790080739, 0.9977854671280277, 0.8655594002306806, 1.0), (0.9931103421760861, 0.9974163783160324, 0.8601460976547481, 1.0), (0.9921261053440984, 0.9970472895040369, 0.8547327950788158, 1.0), (0.990157631680123, 0.9963091118800461, 0.8439061899269512, 1.0), (0.9891733948481354, 0.9959400230680507, 0.8384928873510189, 1.0), (0.9881891580161476, 0.9955709342560554, 0.8330795847750865, 1.0), (0.9862206843521722, 0.9948327566320646, 0.8222529796232219, 1.0), (0.9852364475201846, 0.9944636678200692, 0.8168396770472895, 1.0), (0.9842522106881968, 0.9940945790080739, 0.8114263744713571, 1.0), (0.9832679738562091, 0.9937254901960785, 0.8060130718954248, 1.0), (0.9812995001922338, 0.9929873125720877, 0.7951864667435602, 1.0), (0.9803152633602461, 0.9926182237600923, 0.7897731641676278, 1.0), (0.9793310265282583, 0.992249134948097, 0.7843598615916955, 1.0), (0.977362552864283, 0.9915109573241061, 0.7735332564398308, 1.0), (0.9763783160322953, 0.9911418685121107, 0.7681199538638985, 1.0), (0.9753940792003075, 0.9907727797001153, 0.7627066512879661, 1.0), (0.9744098423683198, 0.99040369088812, 0.7572933487120338, 1.0), (0.9724413687043445, 0.9896655132641292, 0.7464667435601692, 1.0), (0.9714571318723568, 0.9892964244521338, 0.7410534409842369, 1.0), (0.970472895040369, 0.9889273356401385, 0.7356401384083044, 1.0), (0.9681660899653979, 0.9880507497116494, 0.7251518646674355, 1.0), (0.9644752018454441, 0.9865743944636679, 0.7224452133794694, 1.0), (0.9607843137254902, 0.9850980392156863, 0.7197385620915032, 1.0), (0.9570934256055363, 0.9836216839677048, 0.7170319108035371, 1.0), (0.9497116493656286, 0.9806689734717416, 0.7116186082276048, 1.0), (0.9460207612456747, 0.9791926182237601, 0.7089119569396386, 1.0), (0.9423298731257209, 0.9777162629757786, 0.7062053056516724, 1.0), (0.938638985005767, 0.976239907727797, 0.7034986543637063, 1.0), (0.9312572087658593, 0.973287197231834, 0.6980853517877739, 1.0), (0.9275663206459054, 0.9718108419838524, 0.6953787004998078, 1.0), (0.9238754325259515, 0.9703344867358709, 0.6926720492118416, 1.0), (0.9164936562860438, 0.9673817762399077, 0.6872587466359092, 1.0), (0.91280276816609, 0.9659054209919262, 0.684552095347943, 1.0), (0.9091118800461361, 0.9644290657439446, 0.6818454440599769, 1.0), (0.9054209919261822, 0.9629527104959631, 0.6791387927720107, 1.0), (0.8980392156862745, 0.96, 0.6737254901960784, 1.0), (0.8943483275663207, 0.9585236447520185, 0.6710188389081122, 1.0), (0.8906574394463668, 0.957047289504037, 0.6683121876201461, 1.0), (0.883275663206459, 0.9540945790080738, 0.6628988850442137, 1.0), (0.8795847750865051, 0.9526182237600923, 0.6601922337562476, 1.0), (0.8758938869665513, 0.9511418685121107, 0.6574855824682814, 1.0), (0.8722029988465975, 0.9496655132641292, 0.6547789311803152, 1.0), (0.8648212226066897, 0.946712802768166, 0.6493656286043828, 1.0), (0.8611303344867358, 0.9452364475201845, 0.6466589773164167, 1.0), (0.857439446366782, 0.943760092272203, 0.6439523260284505, 1.0), (0.8496270665128797, 0.9405920799692425, 0.6385697808535178, 1.0), (0.8442137639369474, 0.9382545174932718, 0.6359861591695501, 1.0), (0.838800461361015, 0.9359169550173011, 0.6334025374855825, 1.0), (0.8333871587850826, 0.9335793925413303, 0.6308189158016148, 1.0), (0.822560553633218, 0.9289042675893887, 0.6256516724336794, 1.0), (0.8171472510572857, 0.9265667051134179, 0.6230680507497116, 1.0), (0.8117339484813533, 0.9242291426374472, 0.6204844290657439, 1.0), (0.806320645905421, 0.9218915801614763, 0.6179008073817762, 1.0), (0.7954940407535563, 0.9172164552095349, 0.6127335640138408, 1.0), (0.790080738177624, 0.914878892733564, 0.6101499423298731, 1.0), (0.7846674356016916, 0.9125413302575932, 0.6075663206459054, 1.0), (0.773840830449827, 0.9078662053056517, 0.60239907727797, 1.0), (0.7684275278738947, 0.9055286428296809, 0.5998154555940023, 1.0), (0.7630142252979624, 0.9031910803537101, 0.5972318339100346, 1.0), (0.75760092272203, 0.9008535178777394, 0.5946482122260669, 1.0), (0.7467743175701653, 0.8961783929257978, 0.5894809688581315, 1.0), (0.741361014994233, 0.893840830449827, 0.5868973471741638, 1.0), (0.7359477124183007, 0.8915032679738563, 0.5843137254901961, 1.0), (0.725121107266436, 0.8868281430219147, 0.5791464821222607, 1.0), (0.7197078046905037, 0.8844905805459439, 0.576562860438293, 1.0), (0.7142945021145714, 0.8821530180699731, 0.5739792387543252, 1.0), (0.708881199538639, 0.8798154555940023, 0.5713956170703576, 1.0), (0.6980545943867744, 0.8751403306420608, 0.5662283737024222, 1.0), (0.692641291810842, 0.87280276816609, 0.5636447520184544, 1.0), (0.6872279892349097, 0.8704652056901192, 0.5610611303344868, 1.0), (0.6759861591695502, 0.86560553633218, 0.5558938869665514, 1.0), (0.6694655901576317, 0.8627758554402153, 0.5533102652825836, 1.0), (0.6629450211457133, 0.8599461745482507, 0.550726643598616, 1.0), (0.6564244521337947, 0.8571164936562861, 0.5481430219146483, 1.0), (0.6433833141099577, 0.8514571318723568, 0.5429757785467129, 1.0), (0.6368627450980392, 0.8486274509803922, 0.5403921568627451, 1.0), (0.6303421760861208, 0.8457977700884276, 0.5378085351787774, 1.0), (0.6238216070742022, 0.8429680891964629, 0.5352249134948097, 1.0), (0.6107804690503653, 0.8373087274125337, 0.5300576701268743, 1.0), (0.6042599000384468, 0.834479046520569, 0.5274740484429066, 1.0), (0.5977393310265283, 0.8316493656286044, 0.5248904267589388, 1.0), (0.5846981930026913, 0.8259900038446751, 0.5197231833910034, 1.0), (0.5781776239907728, 0.8231603229527105, 0.5171395617070358, 1.0), (0.5716570549788543, 0.8203306420607459, 0.514555940023068, 1.0), (0.5651364859669358, 0.8175009611687812, 0.5119723183391004, 1.0), (0.5520953479430988, 0.811841599384852, 0.5068050749711649, 1.0), (0.5455747789311803, 0.8090119184928873, 0.5042214532871973, 1.0), (0.5390542099192619, 0.8061822376009228, 0.5016378316032295, 1.0), (0.5260130718954248, 0.8005228758169936, 0.4964705882352941, 1.0), (0.5194925028835063, 0.7976931949250289, 0.4938869665513264, 1.0), (0.5129719338715879, 0.7948635140330642, 0.4913033448673587, 1.0), (0.5064513648596695, 0.7920338331410997, 0.488719723183391, 1.0), (0.49341022683583236, 0.7863744713571703, 0.48355247981545557, 1.0), (0.4868896578239139, 0.7835447904652058, 0.4809688581314879, 1.0), (0.48036908881199536, 0.7807151095732411, 0.4783852364475202, 1.0), (0.4672049211841599, 0.7748096885813149, 0.4727873894655901, 1.0), (0.4604382929642445, 0.7714878892733564, 0.4693425605536332, 1.0), (0.4536716647443291, 0.7681660899653979, 0.46589773164167625, 1.0), (0.44690503652441366, 0.7648442906574394, 0.46245290272971934, 1.0), (0.4333717800845828, 0.7582006920415225, 0.45556324490580546, 1.0), (0.4266051518646674, 0.754878892733564, 0.4521184159938485, 1.0), (0.419838523644752, 0.7515570934256055, 0.44867358708189153, 1.0), (0.4130718954248366, 0.7482352941176471, 0.4452287581699346, 1.0), (0.39953863898500575, 0.7415916955017301, 0.43833910034602075, 1.0), (0.39277201076509033, 0.7382698961937716, 0.4348942714340638, 1.0), (0.3860053825451749, 0.7349480968858131, 0.4314494425221069, 1.0), (0.3724721261053441, 0.7283044982698962, 0.424559784698193, 1.0), (0.36570549788542867, 0.7249826989619377, 0.42111495578623603, 1.0), (0.35893886966551325, 0.7216608996539792, 0.41767012687427907, 1.0), (0.35217224144559783, 0.7183391003460208, 0.41422529796232216, 1.0), (0.338638985005767, 0.7116955017301038, 0.4073356401384083, 1.0), (0.33187235678585175, 0.7083737024221454, 0.40389081122645143, 1.0), (0.3251057285659361, 0.7050519031141869, 0.4004459823144944, 1.0), (0.3115724721261053, 0.6984083044982698, 0.39355632449058053, 1.0), (0.3048058439061899, 0.6950865051903113, 0.39011149557862357, 1.0), (0.29803921568627445, 0.6917647058823528, 0.38666666666666666, 1.0), (0.2912725874663591, 0.6884429065743944, 0.3832218377547097, 1.0), (0.27773933102652826, 0.6817993079584774, 0.3763321799307958, 1.0), (0.2709727028066128, 0.678477508650519, 0.37288735101883885, 1.0), (0.2642060745866974, 0.6751557093425605, 0.36944252210688194, 1.0), (0.25259515570934254, 0.6675893886966551, 0.36270665128796614, 1.0), (0.2489042675893887, 0.6627912341407151, 0.35950788158400615, 1.0), (0.2452133794694348, 0.657993079584775, 0.3563091118800461, 1.0), (0.24152249134948095, 0.653194925028835, 0.3531103421760861, 1.0), (0.23414071510957324, 0.643598615916955, 0.3467128027681661, 1.0), (0.23044982698961936, 0.638800461361015, 0.3435140330642061, 1.0), (0.2267589388696655, 0.634002306805075, 0.34031526336024603, 1.0), (0.22306805074971164, 0.629204152249135, 0.33711649365628604, 1.0), (0.21568627450980393, 0.6196078431372549, 0.330718954248366, 1.0), (0.21199538638985005, 0.6148096885813149, 0.327520184544406, 1.0), (0.2083044982698962, 0.6100115340253749, 0.32432141484044597, 1.0), (0.20092272202998845, 0.6004152249134949, 0.3179238754325259, 1.0), (0.1972318339100346, 0.5956170703575547, 0.31472510572856593, 1.0), (0.19354094579008074, 0.5908189158016147, 0.3115263360246059, 1.0), (0.18985005767012686, 0.5860207612456747, 0.3083275663206459, 1.0), (0.18246828143021915, 0.5764244521337947, 0.30193002691272586, 1.0), (0.17877739331026538, 0.5716262975778548, 0.2987312572087659, 1.0), (0.17508650519031144, 0.5668281430219146, 0.2955324875048059, 1.0), (0.1677047289504037, 0.5572318339100346, 0.2891349480968858, 1.0), (0.16401384083044984, 0.5524336793540946, 0.2859361783929258, 1.0), (0.16032295271049596, 0.5476355247981546, 0.2827374086889658, 1.0), (0.1566320645905421, 0.5428373702422146, 0.27953863898500575, 1.0), (0.14925028835063436, 0.5332410611303345, 0.27314109957708577, 1.0), (0.1455594002306805, 0.5284429065743945, 0.2699423298731257, 1.0), (0.14186851211072665, 0.5236447520184545, 0.2667435601691657, 1.0), (0.1340253748558247, 0.5150634371395617, 0.26163783160322956, 1.0), (0.1297193387158785, 0.5116186082276049, 0.260161476355248, 1.0), (0.12541330257593233, 0.5081737793156479, 0.25868512110726644, 1.0), (0.12110726643598617, 0.5047289504036909, 0.2572087658592849, 1.0), (0.11249519415609383, 0.49783929257977705, 0.2542560553633218, 1.0), (0.10818915801614765, 0.4943944636678201, 0.2527797001153403, 1.0), (0.10388312187620147, 0.4909496347558632, 0.2513033448673587, 1.0), (0.09957708573625529, 0.4875048058439062, 0.24982698961937716, 1.0), (0.09096501345636294, 0.48061514801999233, 0.2468742791234141, 1.0), (0.08665897731641677, 0.4771703191080354, 0.24539792387543252, 1.0), (0.0823529411764706, 0.47372549019607846, 0.24392156862745099, 1.0), (0.07374086889657824, 0.4668358323721646, 0.24096885813148788, 1.0), (0.06943483275663206, 0.4633910034602076, 0.23949250288350635, 1.0), (0.0651287966166859, 0.4599461745482507, 0.2380161476355248, 1.0), (0.06082276047673972, 0.45650134563629374, 0.23653979238754327, 1.0), (0.05221068819684736, 0.44961168781237987, 0.23358708189158017, 1.0), (0.04790465205690131, 0.446166858900423, 0.23211072664359866, 1.0), (0.04359861591695502, 0.442722029988466, 0.23063437139561707, 1.0), (0.034986543637062675, 0.4358323721645521, 0.227681660899654, 1.0), (0.030680507497116496, 0.43238754325259515, 0.22620530565167243, 1.0), (0.026374471357170318, 0.42894271434063824, 0.2247289504036909, 1.0), (0.02206843521722414, 0.4254978854286813, 0.22325259515570936, 1.0), (0.013456362937331795, 0.4186082276047674, 0.22029988465974626, 1.0), (0.009150326797385616, 0.41516339869281044, 0.21882352941176472, 1.0), (0.004844290657439437, 0.4117185697808535, 0.21734717416378319, 1.0), (0.0, 0.40407535563244906, 0.21417916186082278, 1.0), (0.0, 0.3997693194925029, 0.2124567474048443, 1.0), (0.0, 0.3954632833525567, 0.21073433294886584, 1.0), (0.0, 0.3911572472126105, 0.20901191849288736, 1.0), (0.0, 0.38254517493271817, 0.20556708958093042, 1.0), (0.0, 0.378239138792772, 0.20384467512495194, 1.0), (0.0, 0.3739331026528258, 0.20212226066897349, 1.0), (0.0, 0.36962706651287963, 0.200399846212995, 1.0), (0.0, 0.36101499423298733, 0.19695501730103807, 1.0), (0.0, 0.35670895809304115, 0.1952326028450596, 1.0), (0.0, 0.35240292195309497, 0.19351018838908113, 1.0), (0.0, 0.3437908496732026, 0.1900653594771242, 1.0), (0.0, 0.33948481353325644, 0.18834294502114574, 1.0), (0.0, 0.33517877739331026, 0.18662053056516725, 1.0), (0.0, 0.3308727412533641, 0.18489811610918877, 1.0), (0.0, 0.3222606689734717, 0.18145328719723186, 1.0), (0.0, 0.31795463283352565, 0.17973087274125343, 1.0), (0.0, 0.31364859669357936, 0.1780084582852749, 1.0), (0.0, 0.305036524413687, 0.17456362937331796, 1.0), (0.0, 0.3007304882737408, 0.1728412149173395, 1.0), (0.0, 0.29642445213379465, 0.17111880046136102, 1.0), (0.0, 0.2921184159938485, 0.16939638600538257, 1.0), (0.0, 0.28350634371395617, 0.16595155709342563, 1.0), (0.0, 0.27920030757401, 0.16422914263744715, 1.0), (0.0, 0.2748942714340638, 0.16250672818146866, 1.0)])
-divergentPal = colorPalette([(0.2298057, 0.298717966, 0.753683153, 1.0), (0.23437707945098038, 0.3055417303294118, 0.7596795275882353, 1.0), (0.2389484589019608, 0.3123654946588235, 0.7656759021764705, 1.0), (0.24351983835294116, 0.3191892589882353, 0.7716722767647058, 1.0), (0.2526625972549019, 0.3328367876470588, 0.7836650259411765, 1.0), (0.25723397670588233, 0.3396605519764706, 0.7896614005294117, 1.0), (0.26180535615686273, 0.3464843163058824, 0.795657775117647, 1.0), (0.26638146835294113, 0.35330440842352945, 0.8016373194980392, 1.0), (0.27582712294117645, 0.36671691552941177, 0.812552935372549, 1.0), (0.2805499502352941, 0.37342316908235296, 0.818010743309804, 1.0), (0.28527277752941177, 0.38012942263529415, 0.8234685512470589, 1.0), (0.29471843211764703, 0.39354192974117647, 0.8343841671215686, 1.0), (0.2994412594117647, 0.40024818329411765, 0.8398419750588235, 1.0), (0.3041742870039216, 0.40694488283921565, 0.8452627266980393, 1.0), (0.30906031906666664, 0.41349827226666663, 0.8501276338666667, 1.0), (0.31883238319215684, 0.4266050511215686, 0.8598574482039216, 1.0), (0.32371841525490197, 0.4331584405490196, 0.864722355372549, 1.0), (0.32860444731764704, 0.43971182997647057, 0.8695872625411765, 1.0), (0.3383765114431373, 0.45281860883137254, 0.8793170768784313, 1.0), (0.34327752343529416, 0.45935363472941176, 0.8841219216235294, 1.0), (0.34832334141176474, 0.4657111465098039, 0.8883461629411764, 1.0), (0.3533691593882353, 0.47206865829019606, 0.8925704042588235, 1.0), (0.3634607953411765, 0.4847836818509804, 0.9010188868941177, 1.0), (0.36850661331764706, 0.49114119363137254, 0.9052431282117647, 1.0), (0.37355243129411764, 0.4974987054117647, 0.9094673695294118, 1.0), (0.383662065772549, 0.5101834172862746, 0.9178306732313726, 1.0), (0.38885187195294113, 0.5162984355764706, 0.9213734830823529, 1.0), (0.3940416781333333, 0.5224134538666667, 0.9249162929333333, 1.0), (0.39923148431372546, 0.5285284721568628, 0.9284591027843138, 1.0), (0.4096110966745098, 0.540758508737255, 0.9355447224862745, 1.0), (0.41480090285490195, 0.5468735270274511, 0.939087532337255, 1.0), (0.4199907090352941, 0.5529885453176471, 0.9426303421882353, 1.0), (0.42519897019607844, 0.559058179764706, 0.9460614570784314, 1.0), (0.4358148063058824, 0.5707073031529412, 0.951717381282353, 1.0), (0.4411227243607843, 0.5765318648470589, 0.9545453433843137, 1.0), (0.4464306424156863, 0.5823564265411765, 0.9573733054862745, 1.0), (0.4570464785254902, 0.5940055499294118, 0.963029229690196, 1.0), (0.4623543965803922, 0.5998301116235294, 0.9658571917921568, 1.0), (0.46767809468235294, 0.6055912316235293, 0.9685462810941176, 1.0), (0.4730701729882353, 0.6110774376156862, 0.970633588262745, 1.0), (0.48385432959999997, 0.6220498496, 0.9748082026, 1.0), (0.48924640790588236, 0.6275360555921569, 0.9768955097686275, 1.0), (0.49463848621176465, 0.6330222615843136, 0.9789828169372549, 1.0), (0.5054226428235293, 0.6439946735686275, 0.9831574312745098, 1.0), (0.5108243242509803, 0.6493966148235294, 0.9850787763764707, 1.0), (0.5162603025411764, 0.6544976105882353, 0.9864073998117647, 1.0), (0.5216962808313725, 0.6595986063529412, 0.9877360232470589, 1.0), (0.5325682374117646, 0.6698005978823529, 0.9903932701176471, 1.0), (0.5380042157019607, 0.6749015936470587, 0.9917218935529412, 1.0), (0.5434401939921568, 0.6800025894117647, 0.9930505169882353, 1.0), (0.5543118699137254, 0.6900970112156862, 0.9955155482352941, 1.0), (0.5597467255686274, 0.6947677280784313, 0.9960753091764706, 1.0), (0.5651815812235294, 0.6994384449411764, 0.9966350701176471, 1.0), (0.5706164368784313, 0.7041091618039216, 0.9971948310588236, 1.0), (0.5814861481882353, 0.7134505955294117, 0.9983143529411764, 1.0), (0.5869210038431373, 0.7181213123921568, 0.9988741138823529, 1.0), (0.5923558594980393, 0.7227920292549019, 0.9994338748235294, 1.0), (0.5977767754941177, 0.7273297248823529, 0.9997767317764705, 1.0), (0.6085473603411764, 0.7357252298235294, 0.9993538252980392, 1.0), (0.6139326527647059, 0.7399229822941177, 0.9991423720588235, 1.0), (0.6193179451882354, 0.7441207347647059, 0.9989309188196078, 1.0), (0.6300885300352941, 0.7525162397058823, 0.9985080123411765, 1.0), (0.6354738224588236, 0.7567139921764706, 0.9982965591019608, 1.0), (0.640827782372549, 0.7607515064117647, 0.9978457748823529, 1.0), (0.6461128107647058, 0.7644364965294117, 0.9968684625058823, 1.0), (0.6566828675490196, 0.7718064767647058, 0.9949138377529412, 1.0), (0.6619678959411764, 0.7754914668823529, 0.9939365253764706, 1.0), (0.6672529243333334, 0.7791764569999999, 0.992959213, 1.0), (0.677822981117647, 0.786546437235294, 0.9910045882470588, 1.0), (0.6830556815607843, 0.790042626890196, 0.9897684281843138, 1.0), (0.6881884831921569, 0.7931783792980391, 0.9880381043568628, 1.0), (0.6933212848235294, 0.7963141317058823, 0.9863077805294118, 1.0), (0.7035868880862746, 0.8025856365215686, 0.9828471328745098, 1.0), (0.7087196897176471, 0.8057213889294117, 0.9811168090470588, 1.0), (0.7138524913490196, 0.8088571413372548, 0.9793864852196078, 1.0), (0.724041371882353, 0.8149103926470588, 0.9756509706470589, 1.0), (0.7289695795686274, 0.8174641357058824, 0.973187668372549, 1.0), (0.7338977872549018, 0.8200178787647059, 0.9707243660980392, 1.0), (0.7388259949411764, 0.8225716218235294, 0.9682610638235294, 1.0), (0.7486824103137254, 0.8276791079411765, 0.9633344592745098, 1.0), (0.753610618, 0.830232851, 0.960871157, 1.0), (0.7585388256862745, 0.8327865940588235, 0.9584078547254902, 1.0), (0.7633627801019607, 0.8350922218196078, 0.9556576765568627, 1.0), (0.7727059486039215, 0.8389782172392156, 0.9493187599137255, 1.0), (0.777377532854902, 0.8409212149490196, 0.9461493015921568, 1.0), (0.7820491171058823, 0.8428642126588235, 0.9429798432705883, 1.0), (0.7913922856078431, 0.8467502080784314, 0.9366409266274509, 1.0), (0.7960638698588236, 0.8486932057882353, 0.9334714683058823, 1.0), (0.8006008472941177, 0.8503583215607843, 0.9300075603921568, 1.0), (0.8049647588235295, 0.8516661605568627, 0.9261650744313725, 1.0), (0.8136925818823529, 0.8542818385490196, 0.9184801025098039, 1.0), (0.8180564934117647, 0.8555896775450981, 0.9146376165490196, 1.0), (0.8224204049411765, 0.8568975165411765, 0.9107951305882354, 1.0), (0.831148228, 0.8595131945333333, 0.9031101586666667, 1.0), (0.8353447113529412, 0.8605139972941176, 0.8989704099411765, 1.0), (0.839351442772549, 0.861166825654902, 0.8944937634156863, 1.0), (0.8433581741921568, 0.8618196540156863, 0.8900171168901961, 1.0), (0.8513716370313725, 0.8631253107372548, 0.8810638238392158, 1.0), (0.8553783684509804, 0.8637781390980391, 0.8765871773137255, 1.0), (0.8593850998705882, 0.8644309674588235, 0.8721105307882353, 1.0), (0.8674276350862745, 0.864376599772549, 0.8626024620196079, 1.0), (0.8714925112588235, 0.8623093793176471, 0.8570162640588236, 1.0), (0.8755573874313726, 0.860242158862745, 0.8514300660980393, 1.0), (0.8796222636039216, 0.8581749384078431, 0.845843868137255, 1.0), (0.8877520159490196, 0.8540404974980391, 0.8346714722156863, 1.0), (0.8918168921215687, 0.8519732770431372, 0.829085274254902, 1.0), (0.8958817682941177, 0.8499060565882353, 0.8234990762941177, 1.0), (0.8995432066000001, 0.8475002359999999, 0.8177890744, 1.0), (0.9061541340352941, 0.8420910651764706, 0.8061505930823529, 1.0), (0.9094595977529412, 0.8393864797647058, 0.8003313524235294, 1.0), (0.9127650614705882, 0.8366818943529412, 0.7945121117647058, 1.0), (0.9193759889058823, 0.8312727235294118, 0.7828736304470588, 1.0), (0.9226814526235294, 0.8285681381176471, 0.7770543897882353, 1.0), (0.925563423, 0.8255172980705883, 0.7711363078117647, 1.0), (0.9281160096666666, 0.8221971488627451, 0.765141349254902, 1.0), (0.933221183, 0.8155568504470588, 0.7531514321411764, 1.0), (0.9357737696666666, 0.8122367012392158, 0.7471564735843139, 1.0), (0.9383263563333333, 0.8089165520313726, 0.741161515027451, 1.0), (0.9434315296666667, 0.8022762536156862, 0.7291715979137255, 1.0), (0.945540298909804, 0.7986057405333333, 0.7231054172980392, 1.0), (0.9473454036, 0.7946955048, 0.7169905058, 1.0), (0.9491505082901961, 0.7907852690666667, 0.7108755943019608, 1.0), (0.9527607176705882, 0.7829647976, 0.6986457713058823, 1.0), (0.9545658223607844, 0.7790545618666667, 0.6925308598078431, 1.0), (0.9563709270509804, 0.7751443261333334, 0.6864159483098039, 1.0), (0.9595176584705882, 0.7669728545098039, 0.6741447150392157, 1.0), (0.9605811984235294, 0.7625010185254902, 0.6679635471019607, 1.0), (0.9616447383764706, 0.7580291825411765, 0.6617823791647058, 1.0), (0.9627082783294117, 0.7535573465568628, 0.655601211227451, 1.0), (0.9648353582352941, 0.7446136745882352, 0.6432388753529412, 1.0), (0.9658988981882353, 0.7401418386039216, 0.6370577074156862, 1.0), (0.9669624381411764, 0.7356700026196078, 0.6308765394784314, 1.0), (0.9675442976352941, 0.7308497161882352, 0.6246854782352941, 1.0), (0.968203399, 0.7208441, 0.6122929913333334, 1.0), (0.9685329496823529, 0.7158412919058823, 0.6060967478823529, 1.0), (0.9688625003647059, 0.7108384838117647, 0.5999005044313725, 1.0), (0.9695216017294117, 0.7008328676235294, 0.5875080175294117, 1.0), (0.9698511524117647, 0.6958300595294117, 0.5813117740784314, 1.0), (0.9696829796666666, 0.6904839307372549, 0.5751383613647059, 1.0), (0.9692885689999999, 0.6849817470823529, 0.5689753262588235, 1.0), (0.9684997476666667, 0.673977379772549, 0.5566492560470588, 1.0), (0.968105337, 0.6684751961176472, 0.5504862209411766, 1.0), (0.9677109263333333, 0.6629730124627451, 0.5443231858352942, 1.0), (0.966922105, 0.6519686451529412, 0.5319971156235295, 1.0), (0.9660167198392157, 0.6461297415882352, 0.5258903482588235, 1.0), (0.9649113881372549, 0.6401590780588234, 0.5198055987058824, 1.0), (0.963806056435294, 0.6341884145294118, 0.5137208491529413, 1.0), (0.9615953930313725, 0.6222470874705882, 0.5015513500470589, 1.0), (0.9604900613294117, 0.6162764239411764, 0.49546660049411767, 1.0), (0.9593847296274509, 0.6103057604117648, 0.4893818509411765, 1.0), (0.9566532109764706, 0.598033822717647, 0.4773022923529412, 1.0), (0.9548534056117647, 0.5916223450078432, 0.4713374634901961, 1.0), (0.9530536002470588, 0.5852108672980392, 0.465372634627451, 1.0), (0.951253794882353, 0.5787993895882353, 0.4594078057647059, 1.0), (0.9476541841529411, 0.5659764341686274, 0.4474781480392157, 1.0), (0.9458543787882353, 0.5595649564588235, 0.44151331917647063, 1.0), (0.9440545734235294, 0.5531534787490197, 0.4355484903137255, 1.0), (0.9417279298235294, 0.5464134770196079, 0.429707070372549, 1.0), (0.9367796132117647, 0.5327495001098039, 0.41809333948627453, 1.0), (0.9343054549058823, 0.525917511654902, 0.4122864740431373, 1.0), (0.9318312966, 0.5190855232, 0.4064796086, 1.0), (0.9268829799882353, 0.5054215462901961, 0.3948658777137255, 1.0), (0.9244088216823529, 0.49858955783529413, 0.38905901227058826, 1.0), (0.921406221227451, 0.49142041718431373, 0.38340843537647057, 1.0), (0.9182816725843137, 0.48417347218039214, 0.37779392507058823, 1.0), (0.9120325752980393, 0.469679582172549, 0.36656490445882356, 1.0), (0.908908026654902, 0.46243263716862765, 0.36095039415294133, 1.0), (0.9057834780117647, 0.4551856921647059, 0.35533588384705883, 1.0), (0.8995343807254902, 0.4406918021568627, 0.34410686323529416, 1.0), (0.8958845948352941, 0.43307455670588235, 0.3386806345176471, 1.0), (0.8921375427882353, 0.4253887370980392, 0.33328927276078435, 1.0), (0.8883904907411765, 0.41770291749019606, 0.32789791100392157, 1.0), (0.8808963866470588, 0.4023312782745098, 0.3171151874901961, 1.0), (0.8771493346, 0.39464545866666667, 0.31172382573333335, 1.0), (0.8734022825529412, 0.3869596390588235, 0.3063324639764706, 1.0), (0.8653913329372549, 0.3711276720470588, 0.2957689564156863, 1.0), (0.8610536002941176, 0.3629157635294118, 0.2906281271764706, 1.0), (0.8567158676509804, 0.3547038550117647, 0.2854872979372549, 1.0), (0.8523781350078431, 0.34649194649411763, 0.2803464686980392, 1.0), (0.8437026697215686, 0.3300681294588235, 0.2700648102196078, 1.0), (0.8393649370784314, 0.32185622094117644, 0.26492398098039216, 1.0), (0.8350272044352941, 0.3136443124235294, 0.25978315174117644, 1.0), (0.8301865219490197, 0.30473276355294115, 0.25489142806666665, 1.0), (0.8204010983882353, 0.2867649126352941, 0.2451595198, 1.0), (0.8155083866078432, 0.2777809871764706, 0.24029356566666665, 1.0), (0.810615674827451, 0.26879706171764706, 0.23542761153333333, 1.0), (0.8008302512666666, 0.2508292108, 0.22569570326666666, 1.0), (0.7959375394862745, 0.24184528534117647, 0.22082974913333334, 1.0), (0.7905615319411765, 0.23139699905882352, 0.21624203829411764, 1.0), (0.7851533046784314, 0.2208510887215686, 0.21167287700784312, 1.0), (0.7743368501529412, 0.19975926804705882, 0.2025345544352941, 1.0), (0.7689286228901963, 0.18921335770980421, 0.19796539314901973, 1.0), (0.763520395627451, 0.17866744737254903, 0.1933962318627451, 1.0), (0.7527039411019608, 0.1575756266980392, 0.1842579092901961, 1.0), (0.7468380122117647, 0.14002101948235293, 0.17999609695686275, 1.0), (0.7409573187529412, 0.12224032527058823, 0.17574419910588235, 1.0), (0.7350766252941177, 0.10445963105882351, 0.17149230125490195, 1.0), (0.7233152383764706, 0.06889824263529411, 0.16298850555294117, 1.0), (0.717434544917647, 0.05111754842352939, 0.15873660770196077, 1.0), (0.7115538514588235, 0.03333685421176469, 0.1544847098509804, 1.0)], is_divergent=True)
-grayscalePal = colorPalette(['#000000', '#080808', '#101010', '#181818', '#202020', '#282828', '#303030', '#383838', '#404040', '#484848', '#505050', '#585858', '#606060', '#686868', '#696969', '#707070', '#787878', '#808080', '#888888', '#909090', '#989898', '#A0A0A0', '#A8A8A8', '#A9A9A9', '#B0B0B0', '#B8B8B8', '#BEBEBE', '#C0C0C0', '#C8C8C8', '#D0D0D0', '#D3D3D3', '#D8D8D8', '#DCDCDC', '#E0E0E0', '#E8E8E8', '#F0F0F0', '#F5F5F5', '#F8F8F8', '#FFFFFF'])
-
-def divBar(l, c, palette=discretePal):
- h = ''
- N = np.sum(l)
- for i in range(0, len(l)):
- e = l[i]
- w = 5+int((float(e)/c)*45)
- g = int((float(e)/N)*20)
- h+='
'
- return h + '
'
-
-def hide_fake_axis(ax, prop=None, handletextpad=None, msize=None):
- ax.set_xlim(1,2)
- ax.set_ylim(1,2)
- ax.axis('off')
- lgnd = ax.legend(frameon=False, loc=2, handletextpad=handletextpad, prop=prop)
- if msize != None:
- for h in lgnd.legendHandles:
- h.set_width(msize)
- return ax
-
-def emptyFig():
- fig = plt.figure()
- ax = plt.subplots(111)
- return ax, fig
-
-def plotCellTree(order, dis, cellcolors, collabels, title='', figdim={'figsize': (7.2,2.2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal):
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((5, 7), (0, 0), rowspan=3, colspan=5)
- ax2 = plt.subplot2grid((5, 7), (3, 0), rowspan=2, colspan=5, sharex=ax)
- ax4 = plt.subplot2grid((5, 7), (0, 5), rowspan=5, colspan=1)
- ax5 = plt.subplot2grid((5, 7), (0, 6), rowspan=5, colspan=1)
- fig.subplots_adjust(left=0.02, bottom=0, wspace = 0.1)
- oldLw = matplotlib.rcParams['lines.linewidth']
- matplotlib.rcParams['lines.linewidth'] = 0.2
- dendro, linkage = dis.dendroFromDist(dis.distances, dis.labels, ax=ax)
- matplotlib.rcParams['lines.linewidth'] = oldLw
- tl = ax.get_xticks()
- step = tl[1]-tl[0]
- bot = 0
- for l in dendro['leaves']:
- l2, l3, l4 = cellcolors[dendro['ivl'][l]]
- ax2.barh(9, step, left=bot, color=palette[l4], linewidth=0, height=1, alpha=0.7)
- ax2.barh(5, step, left=bot, color=palette[l2], linewidth=0, height=1, alpha=0.7)
- ax2.barh(1, step, left=bot, color=palette[l3], linewidth=0, height=1, alpha=0.7)
- bot += step
- ax2.text(50, 10, 'Cluster', fontsize=fonthi[0])
- ax2.text(50, 6, 'Sample', fontsize=fonthi[0])
- ax2.text(50, 2, 'Cell type', fontsize=fonthi[0])
- ax2.set_ylim(0, 12)
- for i in range(0, len(collabels[0][1])):
- ax4.scatter(-1, -1, color=palette[i], label=collabels[0][1][i], alpha=0.9)
- for i in range(0, len(collabels[1][1])):
- ax5.scatter(-1, -1, color=palette[i], label=collabels[1][1][i], alpha=0.4)
- ax.axis('off')
- ax2.axis('off')
- ax4 = hide_fake_axis(ax4, prop={'size': fonthi[0]})
- ax5 = hide_fake_axis(ax5, prop={'size': fonthi[0]})
- fig.suptitle(title, fontsize=fonthi[1])
- return fig
-
-def plotGrTree(distances, groups, colors, title='', figdim={'figsize': (7.2,2.2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal):
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((5, 7), (0, 0), rowspan=4, colspan=7)
- try:
- distances.groupTree(groups, ax=ax)
- except:
- pass
- fig.subplots_adjust(bottom=0.4)
- fig.suptitle(title, fontsize=fonthi[1])
- for t in ax.get_xticklabels():
- t.set_color(palette[colors[t.get_text().split(', ')[0]]])
- t.set_rotation(45)
- t.set_horizontalalignment('right')
- t.set_fontsize(fonthi[0])
- ax.get_yaxis().set_visible(False)
- return fig
-
-def plotSimpleHeat(distance, title='', figdim={'figsize': (9.7,7.2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal):
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((9, 7), (1, 1), rowspan=8, colspan=6)
- ax_t = plt.subplot2grid((9, 7), (0, 1), rowspan=1, colspan=6)#, sharex=ax)
- ax_s = plt.subplot2grid((9, 7), (1, 0), rowspan=8, colspan=1)#, sharex=ax)
- fig.subplots_adjust(bottom=0.1, hspace=0.4)
- f, t1, t2 = distance.biClustMap(ax1=ax_s, ax2=ax_t)
- ax.imshow(f, aspect='auto')
- nxl = []
- for xl in ax_t.get_xticklabels():
- nxl.append('K'+str(1+int(xl.get_text())))
- ax_t.set_xticklabels(nxl, fontsize=fonthi[0])
- ax.axis('off')
- ax_s.axis('off')
- ax_t.get_yaxis().set_visible(False)
- ax_t.spines['top'].set_visible(False)
- ax_t.spines['bottom'].set_visible(False)
- ax_t.spines['left'].set_visible(False)
- ax_t.spines['right'].set_visible(False)
- ax_t.tick_params(bottom="off", left="off")
- fig.suptitle(title, fontsize=fonthi[1])
- return fig
-
-def plotHorGrStBar(data, labels, xticks=[], title= '', ylabel='', ydim=None, ax=None, figdim={'figsize': (3.5,2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal, secondarypalette=grayscalePal, hubysec=False):
- if ax == None:
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((1, 7), (0, 0), colspan=5)
- ax2 = plt.subplot2grid((1, 7), (0, 5), colspan=2)
- else:
- fig = ax.get_figure()
- #fig.set_size_inches(3.5, 2))
- fig.subplots_adjust(left=0.17, bottom=0.2, wspace = -0.15)
- if hubysec:
- ppalette = secondarypalette
- hpalette = palette
- else:
- ppalette = palette
- N = len(xticks)
- M = len(labels)
- labels = labels[::-1]
- bot = [0 for x in range(0, M)]
- for i in range(0, N):
- y = [data[j][i] for j in range(0, M)]
- x = [x+1 for x in range(0, M)]
- ifi = i+0
- edgecol = None
- linewidth = 0
- if hubysec:
- ifi = float(i)/N
- edgecol = [hpalette[j] for j in range(0, M)]
- linewidth = 1
- ax.barh(x, y, left=bot, color=ppalette[ifi], edgecolor=edgecol, linewidth=linewidth, height=0.6, alpha=0.7)
- ax2.bar(-1, -1, color=ppalette[ifi], label=xticks[i], width=0, alpha=0.7)
- bot = [bot[x]+y[x] for x in range(0, M)]
- groupWidth = 1
- ax2 = hide_fake_axis(ax2, handletextpad=0.1, prop={'size': fonthi[0]})
- ax.set_xlabel(ylabel, fontsize=fonthi[0])
- for yl in ax.get_xticklabels():
- yl.set_fontsize(fonthi[0])
- if ydim=='%':
- ax.set_xticks([x for x in np.arange(0, 1.1, 0.25)])
- ax.set_xticklabels([str(int(100*x))+'%' for x in np.arange(0, 1.1, 0.25)], fontsize=fonthi[0])
- ax.set_yticks([0.5+x+(groupWidth*0.5) for x in range(0, M)])
- ax.set_yticklabels(labels, fontsize=fonthi[0])
- fig.suptitle(title)
- return ax, fig
-
-def plotGrStBar(data, labels, xticks=[], ylabel='', ydim=None, ax=None, figdim={'figsize': (3.5,2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal):
- if ax == None:
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((1, 7), (0, 0), colspan=4)
- ax2 = plt.subplot2grid((1, 7), (0, 4), colspan=2)
- else:
- fig = ax.get_figure()
- #fig.set_size_inches(3.5, 2))
- fig.subplots_adjust(left=0.1, bottom=0.35, wspace = 0.1)
- N = len(xticks)
- M = len(labels)
- bot = [0 for x in range(0, M)]
- for i in range(0, N):
- y = [data[j][i] for j in range(0, M)]
- x = [x+1 for x in range(0, M)]
- ax.bar(x, y, bottom=bot, color=palette[i], edgecolor='white', width=0.6)
- ax2.bar(-1, -1, color=palette[i], label=xticks[i], width=0)
- bot = [bot[x]+y[x] for x in range(0, M)]
- groupWidth = 1
- ax2 = hide_fake_axis(ax2, prop={'size': fonthi[0]})
- ax.set_ylabel(ylabel, fontsize=fonthi[0])
- for yl in ax.get_yticklabels():
- yl.set_fontsize(fonthi[0])
- if ydim=='%':
- ax.set_yticks([x for x in np.arange(0, 1.1, 0.1)])
- ax.set_yticklabels([str(int(100*x))+'%' for x in np.arange(0, 1.1, 0.1)], fontsize=fonthi[0])
- ax.set_xticks([0.5+x+(groupWidth*0.5) for x in range(0, M)])
- ax.set_xticklabels(labels, fontsize=fonthi[0])
- return ax, fig
-
-def plotGrSegBar(data, labels, xticks=[], ylabel='', ydim=None, ax=None, figdim={'figsize': (3.5,2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal):
- if ax == None:
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((1, 7), (0, 0), colspan=4)
- ax2 = plt.subplot2grid((1, 7), (0, 4), colspan=2)
- else:
- fig = ax.get_figure()
- #fig.set_size_inches(3.5, 2))
- fig.subplots_adjust(left=0.1, bottom=0.35, wspace = 0.1)
- N = len(xticks)
- M = len(labels)
- bot = [0 for x in range(0, M)]
- for i in range(0, N):
- y = [data[j][i] for j in range(0, M)]
- x = [x+1 for x in range(0, M)]
- ax.bar(x, y, bottom=bot, color=palette[i], edgecolor='white', width=0.6)
- ax2.bar(-1, -1, color=palette[i], label=xticks[i], width=0)
- bot = [bot[x]+y[x] for x in range(0, M)]
- groupWidth = 1
- ax2 = hide_fake_axis(ax2, prop={'size': fonthi[0]})
- ax.set_ylabel(ylabel, fontsize=fonthi[0])
- for yl in ax.get_yticklabels():
- yl.set_fontsize(fonthi[0])
- if ydim=='%':
- ax.set_yticks([x for x in np.arange(0, 1.1, 0.1)])
- ax.set_yticklabels([str(int(100*x))+'%' for x in np.arange(0, 1.1, 0.1)], fontsize=fonthi[0])
- ax.set_xticks([0.5+x+(groupWidth*0.5) for x in range(0, M)])
- ax.set_xticklabels(labels, fontsize=fonthi[0])
- return ax, fig
-
-def plotGrBar(data, labels, barWidth=None, xticks=[], ylabel='', ax=None, figdim={'figsize': (3.5,2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal):
- if ax == None:
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((1, 7), (0, 0), colspan=6)
- ax2 = plt.subplot2grid((1, 7), (0, 6), colspan=1)
- else:
- fig = ax.get_figure()
- if barWidth == None:
- barWidth = 0.8/float(len(data))
- #fig.set_size_inches(3.5, 2)
- fig.subplots_adjust(left=0.1, bottom=0.2, wspace = 0.1)
- for i in range(0, len(data)):
- y = data[i]
- x = [x+(barWidth*i) for x in range(1, len(y)+1)]
- ax.bar(x, y, color=palette[i], width=barWidth, edgecolor='white')
- ax2.bar(-1, -1, color=palette[i], width=0, label=labels[i])
- groupWidth = barWidth*i
- ax2 = hide_fake_axis(ax2, prop={'size': fonthi[0]})
- ax.set_ylabel(ylabel, fontsize=fonthi[0])
- for yl in ax.get_yticklabels():
- yl.set_fontsize(fonthi[0])
- ax.set_xticks([x+(groupWidth*0.5) for x in range(1, len(xticks)+1)])
- ax.set_xticklabels(xticks, rotation=90, fontsize=fonthi[0])
- return ax, fig
-
-def plotGrDivBar(data, labels, barWidth=None, xticks=[], ylabel='', ax=None, figdim={'figsize': (3.5,2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal):
- if ax == None:
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((1, 7), (0, 0), colspan=5)
- ax2 = plt.subplot2grid((1, 7), (0, 5), colspan=2)
- else:
- fig = ax.get_figure()
- if barWidth == None:
- barWidth = 0.8/float(len(data))
- #fig.set_size_inches(3.5, 2)
- fig.subplots_adjust(left=0.15, bottom=0.41, wspace = 0.1)
- for i in range(0, len(data)):
- y = data[i]
- x = [x+(barWidth*i) for x in range(1, len(y)+1)]
- ax.bar(x, y, color=palette[i], width=barWidth, edgecolor='white')
- ax2.bar(-1, -1, color=palette[i], width=0, label=labels[i])
- groupWidth = barWidth*i
- ax2 = hide_fake_axis(ax2, prop={'size': fonthi[0]}, msize=8)
- ax.set_ylabel(ylabel, fontsize=fonthi[0])
- for yl in ax.get_yticklabels():
- yl.set_fontsize(fonthi[0])
- ax.set_xticks([x+(groupWidth*0.5) for x in range(1, len(xticks)+1)])
- ax.set_xticklabels(xticks, rotation=90, fontsize=fonthi[0])
- return ax, fig
-
-def plotPairBubble(s1, s2, x, y, z, ax=None, figdim={'figsize': (3.5,2.6), 'dpi': 600}, fonthi=[8, 10, 14]):
- if ax == None:
- fig = plt.figure(**figdim)
- ax = fig.add_subplot(111)
- fig.subplots_adjust(left=0.2, bottom=0.2)
- else:
- fig = ax.get_figure()
- ax.set_aspect(aspect=1, adjustable='box', anchor='SW')
- ax.scatter(x, y, s=z)
- ax.set_xlabel('Clonotype size in '+s1, fontsize=fonthi[0])
- ax.set_ylabel('Clonotype size in '+s2, fontsize=fonthi[0])
- lr = range(0, int(np.amax([x, y]))+6, 5)
- ax.set_xticks(lr)
- ax.set_xticklabels(lr, fontsize=fonthi[0])
- ax.set_xlim(left=0)
- ax.set_yticks(lr)
- ax.set_yticklabels(lr, fontsize=fonthi[0])
- ax.set_ylim(bottom=0)
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- fig.suptitle('Overlap between clonotypes in a pair of samples', fontsize=fonthi[1])
- return ax, fig
-
-def plotGridHist(data, xlab, ylab, zlab, collabels, order=None, palette=None, tickstep=2):
- cx, cy, cz = [], [], []
- N = 0
- for x, yl in data.iteritems():
- N += 1
- for y, zl in yl.iteritems():
- for z in zl:
- cx.append(x)
- cy.append(y)
- cz.append(z)
- data = {xlab: cx, ylab: cy, zlab: cz}
- df = pd.DataFrame(data)
- if palette == None:
- palette = sns.cubehelix_palette(N, rot=-.2, light=.5)
- midPal = int(len(palette)/2)
- g = sns.FacetGrid(df, row=xlab, hue=ylab, aspect=8, height=2, palette=palette, row_order=order)
- g.map(sns.kdeplot, zlab, clip_on=False, shade=True, alpha=.9, lw=1.5, bw=.2)
- g.map(sns.kdeplot, zlab, clip_on=False, lw=2, bw=.2, color='w')
- g.map(plt.axhline, y=0, lw=2, clip_on=False, color=palette[1])
- def label(x, color, label):
- if label == collabels[midPal]:
- for e in x:
- ax = plt.gca()
- ax.text(0, .2, e, fontweight='bold', color=color, alpha=.8, ha='left', va='center', transform=ax.transAxes)
- return
-
- g.map(label, xlab)
- g.fig.subplots_adjust(hspace=.25)
- g.set_titles('')
- g.set(yticks=[])
- g.despine(bottom=True, left=True)
- plt.xlabel(ylab, color=palette[midPal], fontweight='bold')
- plt.xticks(range(tickstep, tickstep*len(collabels)+tickstep, tickstep), collabels, color=palette[0])
- tl = plt.gca().get_xticklabels()
- for i in range(0, N):
- tl[i].set_color(palette[i])
- fig = plt.gcf()
- return fig
-
-def plotGexDistribution(data, xlabel, ylabel, title='', axisrotation=None, huerder=None, order=None, ylim=None, ax=None, hue=None, condensed=True, show_violin=True, show_swarm=True, show_box=True, show_strip=True, figdim={'figsize': (7.2,2.2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal):
- if ax == None:
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((1, 7), (0, 0), colspan=6)
- ax2 = plt.subplot2grid((1, 7), (0, 6), colspan=1)
- else:
- fig = ax.get_figure()
- if condensed:
- cx, cy, hueli = [], [], []
- for x, yl in data.iteritems():
- if x != hue:
- for i in range(0, len(yl)):
- cx.append(x)
- cy.append(yl[i])
- if hue != None:
- hueli.append(data[hue][i])
- if hue == None:
- data = {xlabel: cx, ylabel: cy}
- else:
- data = {xlabel: cx, ylabel: cy, hue: hueli}
- if huerder != None:
- if hue != None:
- new = zip(data[xlabel], data[ylabel], data[hue])
- new.sort(key=lambda x: huerder.index(x[2]))
- new=zip(*new)
- data = {xlabel: new[0][:], ylabel: new[1][:], hue: new[2][:]}
- new = ''
- for i in range(0, len(huerder)):
- ax2.scatter(-1, -1, color=palette[i], label=huerder[i], alpha=0.8)
- ax2 = hide_fake_axis(ax2, prop={'size': fonthi[0]})
- df = pd.DataFrame(data)
- if show_violin:
- ax = sns.violinplot(x=xlabel, y=ylabel, data=df, linewidth=0.1, inner=None, order=order, palette=palette, hue=hue, ax=ax)
- if show_swarm:
- ax = sns.swarmplot(x=xlabel, y=ylabel, data=df, color='white', edgecolor='gray', size=1, order=order, hue=hue, ax=ax)
- if show_box:
- ax = sns.boxplot(x=xlabel, y=ylabel, data=df, linewidth=0.5, saturation=0.6, boxprops={'alpha': 0.6}, showfliers=False, order=order, hue=hue, ax=ax)
- #ax = sns.boxplot(x=xlabel, y=ylabel, data=df, linewidth=1, boxprops={'facecolor': 'None'}, showfliers=False, order=order, hue=hue, ax=ax)
- if show_strip:
- ax = sns.stripplot(x=xlabel, y=ylabel, data=df, order=order, jitter=True, dodge=True, size=1, color='black', hue=hue, ax=ax)
- #ax = sns.stripplot(x=xlabel, y=ylabel, data=df, order=order, jitter=True, dodge=True, size=1, palette=palette, hue=hue, ax=ax)
- if ylim != None:
- ax.set_ylim(ylim[0], ylim[1])
- else:
- ax.set_ylim(bottom=0)
- if axisrotation != None:
- ax.set_xticklabels(ax.get_xticklabels(), rotation=axisrotation, va='top', ha='right')
- fig.subplots_adjust(bottom=0.35)
- for yl in ax.get_yticklabels():
- yl.set_fontsize(fonthi[0])
- for xl in ax.get_xticklabels():
- xl.set_fontsize(fonthi[0])
- ax.set_ylabel(ax.get_ylabel(), fontsize=fonthi[0])
- ax.set_xlabel(ax.get_xlabel(), fontsize=fonthi[0])
- ax.get_legend().remove()
- fig.suptitle(title, fontsize=fonthi[1])
- return ax, fig
-
-def plotDistribution(data, xlabel, ylabel, title='', axisrotation=None, huerder=None, order=None, ylim=None, ax=None, hue=None, condensed=True, show_violin=True, show_swarm=False, show_box=False, show_strip=False, figdim={'figsize': (3.5,2), 'dpi': 600}, fonthi=[8, 10, 14], palette=discretePal):
- if ax == None:
- fig = plt.figure(**figdim)
- ax = plt.subplot2grid((1, 7), (0, 0), colspan=5)
- ax2 = plt.subplot2grid((1, 7), (0, 5), colspan=2)
- else:
- fig = ax.get_figure()
- if condensed:
- cx, cy, hueli = [], [], []
- for x, yl in data.iteritems():
- if x != hue:
- for i in range(0, len(yl)):
- cx.append(x)
- cy.append(yl[i])
- if hue != None:
- hueli.append(data[hue][i])
- if hue == None:
- data = {xlabel: cx, ylabel: cy}
- else:
- data = {xlabel: cx, ylabel: cy, hue: hueli}
- if huerder != None:
- if hue != None:
- new = zip(data[xlabel], data[ylabel], data[hue])
- new.sort(key=lambda x: huerder.index(x[2]))
- new=zip(*new)
- data = {xlabel: new[0][:], ylabel: new[1][:], hue: new[2][:]}
- new = ''
- for i in range(0, len(huerder)):
- ax2.scatter(-1, -1, color=palette[i], label=huerder[i], alpha=0.8)
- ax2 = hide_fake_axis(ax2, prop={'size': fonthi[0]})
- fig.subplots_adjust(left=0.18, bottom=0.3, wspace = 0.1)
- df = pd.DataFrame(data)
- if show_violin:
- ax = sns.violinplot(x=xlabel, y=ylabel, data=df, linewidth=0.1, inner=None, order=order, palette=palette, hue=hue, ax=ax)
- if show_swarm:
- ax = sns.swarmplot(x=xlabel, y=ylabel, data=df, color='white', edgecolor='gray', size=1, order=order, hue=hue, ax=ax)
- if show_box:
- ax = sns.boxplot(x=xlabel, y=ylabel, data=df, linewidth=0.5, saturation=0.6, boxprops={'alpha': 0.6}, showfliers=False, order=order, hue=hue, ax=ax)
- #ax = sns.boxplot(x=xlabel, y=ylabel, data=df, linewidth=1, boxprops={'facecolor': 'None'}, showfliers=False, order=order, hue=hue, ax=ax)
- if show_strip:
- ax = sns.stripplot(x=xlabel, y=ylabel, data=df, order=order, jitter=True, dodge=True, size=1, color='black', hue=hue, ax=ax)
- #ax = sns.stripplot(x=xlabel, y=ylabel, data=df, order=order, jitter=True, dodge=True, size=1, palette=palette, hue=hue, ax=ax)
- if ylim != None:
- ax.set_ylim(ylim[0], ylim[1])
- if axisrotation != None:
- ax.set_xticklabels(ax.get_xticklabels(), rotation=axisrotation, va='top', ha='right')
- fig.subplots_adjust(bottom=0.2)
- nxl = []
- oxl = ax.get_xticklabels()
- for i in range(0, len(oxl)):
- tx = oxl[i].get_text()
- if i % 2 == 0:
- nxl.append(tx)
- else:
- nxl.append('\n'+tx)
- ax.set_xticklabels(nxl, fontsize=fonthi[0])
- for yl in ax.get_yticklabels():
- yl.set_fontsize(fonthi[0])
- ax.set_ylabel(ax.get_ylabel(), fontsize=fonthi[0])
- ax.set_xlabel(ax.get_xlabel(), fontsize=fonthi[0])
- ax.get_legend().remove()
- fig.suptitle(title, fontsize=fonthi[1])
- return ax, fig
-
-def plotFlowChain(regions, segFreqs, lineWidths, palette, freqTh=5, showlines=True, ylabel='', regionlabels=None, title='', ax=None):
- if ax == None:
- fig = plt.figure()
- ax = fig.add_subplot(111)
- else:
- fig = ax.get_figure()
- if regionlabels == None:
- regionlabels = regions[:]
- orderlists, bottoms = {}, {}
- M = sum(lineWidths.values())
- ic = 0
- for region in regions:
- N = len(segFreqs[region])
- ic += 1
- yl, ol = [], []
- baseline, cc = 0, 0
- for m, n in segFreqs[region].most_common()[::-1]:
- if not showlines:
- put_text = False
- color = palette[freqTh]
- if N-cc < freqTh:
- color = palette[N-cc-1]
- put_text = True
- ax.bar(ic, n, width=.2, bottom=baseline, color=color)
- if put_text:
- ax.text(ic-0.1, baseline+n, m, color='black')
- ol.append(m)
- bottoms[m] = baseline
- cc += 1
- baseline += n
- orderlists[region] = ol
- if showlines:
- shadows = {}
- for k, v in bottoms.iteritems():
- shadows[k] = 0
- segiter = [orderlists[x] for x in regions[1:]]
- lN = len(orderlists[regions[0]])
- for i in range(0, lN):
- if lN-i < freqTh:
- cc = lN-i-1
- else:
- cc = 5
- seg_start = orderlists[regions[0]][i]
- for seg_comb in itertools.product(*segiter):
- seg_comb = [seg_start]+list(seg_comb)
- seg = '|'.join(seg_comb)
- if seg in lineWidths:
- for j in range(0, lineWidths[seg]):
- x, y, colc = [], [], 0.0
- for seg_part in seg_comb:
- colc += 1
- x.append(colc-0.1)
- x.append(colc+0.1)
- y.append(bottoms[seg_part]+shadows[seg_part]+0.5)
- y.append(bottoms[seg_part]+shadows[seg_part]+0.5)
- shadows[seg_part]+=1
- ax.plot(x, y, color=palette[cc], alpha=.7, lw=3, zorder=-1)
- ic = 0
- for region in regions:
- ic += 1
- baseline, cc = 0, 0
- for m, n in segFreqs[region].most_common()[::-1]:
- if n > freqTh:
- ax.text(ic-0.1, baseline+n, m, color='black')
- ax.bar(ic, n, width=.2, bottom=baseline, color='w', edgecolor='grey', alpha=.4)
- baseline += n
- cc += 1
- ax.set_ylabel(ylabel)
- ax.set_xticklabels(['']+regionlabels, rotation='vertical')
- ax.set_title(title)
- return ax, fig
-
-def plotSeqLogo(sequences, palette='aa_chemistry', title='', xlabel='Amino acid position', ax=None, y_ln=30):
- colors = {'aa_chemistry': {'G': 'green', 'S': 'green', 'T': 'green', 'Y': 'green', 'C': 'green', 'K': 'blue', 'R': 'blue', 'H': 'blue', 'Q': 'magenta', 'N': 'magenta', 'D': 'red', 'E': 'red', 'A': 'black', 'V': 'black', 'L': 'black', 'I': 'black', 'P': 'black', 'W': 'black', 'F': 'black', 'M': 'black'}}
- colors = colors[palette]
- #hydrophobic 'black'; acidic 'red'; basic 'blue'; neutral 'magenta'; polar 'green'
- if ax == None:
- fig = plt.figure()
- ax = fig.add_subplot(111)
- else:
- fig = ax.get_figure()
- letter_freq, axis_length = [], 0
- for seq in sequences:
- if len(seq) > axis_length:
- axis_length = len(seq)
- for i in range(0, axis_length):
- letter_freq.append(collections.Counter())
- for seq in sequences:
- for i in range(0, len(seq)):
- letter_freq[i][seq[i]] += 1
- ax.set_ylim(0, y_ln)
- ax.set_xlim(0, 2*(axis_length))
- ax.set_xticks(range(1, 2*(axis_length), 2))
- ax.set_xticklabels(range(1, axis_length+1))
- ax.set_xlabel(xlabel)
- for i in range(0, axis_length):
- prevy = 0
- for m, n in letter_freq[i].most_common():
- try:
- color = colors[m]
- except:
- color = yellow
- ax.text((2*i)+1, prevy+1, m, color=color, fontsize=8*np.sqrt(n), horizontalalignment='center', verticalalignment='baseline')
- prevy += np.sqrt(n)
- ax.get_yaxis().set_visible(False)
- plt.title(title)
- return ax, fig
-
-def plotPojection(data, catorder=None, xlabel='', ylabel='', title='', alpha=0.6, marker='.', size=25, edgecolors='none', background=[[], []], backgroundcolor='grey', backgroundalpha=0.6, backgroundmarker='.', backgroundsize=15, backgroundedgecolors='none', figdim={'figsize': (3.5,2.6), 'dpi': 600}, fonthi=[8, 10, 14], ax=None, palette=discretePal):
- valid_input = False
- pgroup = 0
- if type(data) == dict:
- valid_input = True
- pgroup = -1
- if catorder == None:
- catorder = list(data.keys())
- if type(data) == list:
- if len(data) == 3:
- valid_input = True
- pgroup = 1
- if ax == None:
- fig = plt.figure(**figdim)
- if pgroup < 1:
- ax = plt.subplot2grid((1, 4), (0, 0), colspan=3)
- ax2 = plt.subplot2grid((1, 4), (0, 3), colspan=1)
- else:
- ax = fig.add_subplot(111)
- else:
- fig = ax.get_figure()
- if palette == None:
- palette = colget
- if valid_input:
- ax.scatter(background[0], background[1], color=backgroundcolor, alpha=backgroundalpha, marker=backgroundmarker, s=backgroundsize, edgecolors=backgroundedgecolors)
- if pgroup < 1:
- cc = 0
- for k in catorder:
- v = data[k]
- ax.scatter(v[0], v[1], color=palette[cc], alpha=alpha, marker=marker, s=size, edgecolors=edgecolors)
- ax2.scatter(0, 0, color=palette[cc], alpha=alpha, marker=marker, s=size, edgecolors=edgecolors, label=k)
- cc += 1
- ax2.set_xlim(1,2)
- ax2.set_ylim(1,2)
- ax2.axis('off')
- ax2.legend(frameon=False, loc=2, prop={'size': fonthi[0]})
- fig.subplots_adjust(left=0.06, bottom=0.06, wspace = -0.16)
- else:
- x, y, z = data
- ax.scatter(x, y, c=palette[z], alpha=alpha, marker=marker, s=size, edgecolors=edgecolors)
- #ax.get_xaxis().set_visible(False)
- #ax.get_yaxis().set_visible(False)
- ax.tick_params(axis='both', which='both', left=False, right=False, bottom=False, top=False, labelbottom=False, labeltop=False, labelleft=False, labelright=False)
- ax.set_xlabel('Dimension 1', fontsize=fonthi[0])
- ax.set_ylabel('Dimension 2', fontsize=fonthi[0])
- fig.suptitle(title, fontsize=fonthi[1])
- return ax, fig
-
-if __name__ == '__main__':
- __main__()
\ No newline at end of file
diff --git a/scTCRpy/plotGraphs.pyc b/scTCRpy/plotGraphs.pyc
deleted file mode 100644
index f3cc7db81b36ff20e66792e48923deef966c74d5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 46162
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