<jupyter_start><jupyter_text>This notebook was created to find the isolates in rollingDB that have the same SNPs identified from in-host SNP analysis<jupyter_code>import vcf

%matplotlib inline
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.ticker as ticker
from itertools import compress
from pylab import MaxNLocator
import seaborn as sns; sns.set()
from matplotlib.colors import LogNorm
from matplotlib import gridspec
from matplotlib.gridspec import GridSpec
import ast
import itertools
import seaborn as sns
from sklearn.preprocessing import StandardScaler

import fastcluster
from sklearn import cluster, datasets
import scipy.cluster.hierarchy as hier
from sklearn.cluster import KMeans
import time
import sys

import Bio
from Bio.Alphabet import IUPAC
from Bio.Blast.Applications import NcbiblastnCommandline
from Bio.Blast import NCBIXML
from Bio.Seq import Seq
from Bio.SeqRecord import SeqRecord
from Bio.SeqFeature import SeqFeature, FeatureLocation
from Bio import pairwise2
from Bio import SeqIO
from Bio.Graphics import GenomeDiagram
from Bio.SeqUtils import GC

from Bio.Align.Applications import MuscleCommandline
from StringIO import StringIO
from Bio import AlignIO
from Bio.Align import AlignInfo
from Bio.Seq import MutableSeq
import itertools
import gzip

import networkx as nx
import scipy

from collections import Counter

#for exporting to Adobe Illustrator
mpl.rcParams['pdf.fonttype'] = 42
mpl.rcParams['ps.fonttype'] = 42

import warnings
warnings.filterwarnings("ignore", module="matplotlib")
plt.style.use('ggplot')
plt.rcParams['lines.linewidth']=3
plt.rcParams['axes.facecolor']='1.0'
plt.rcParams['xtick.color']='black'
plt.rcParams['axes.grid']=True
plt.rcParams['axes.edgecolor']='black'
plt.rcParams['grid.color']= '1.0'
plt.rcParams.update({'font.size': 12})<jupyter_output><empty_output><jupyter_text>Load annotation for *in-host* SNPs<jupyter_code>in_host_SNPs_DF = pd.read_pickle('/n/data1/hms/dbmi/farhat/Roger/inhost_TB_dynamics_project/pickled_files/variant_calling/longitudinal_SNPs/SNPs_between_isolates_delta_70_intergenic_annotated_with_allele1_allele2_info.pkl')
in_host_SNPs_DF.head()
np.shape(in_host_SNPs_DF)<jupyter_output><empty_output><jupyter_text>Subest to 142/175 SNPs in which the frequency of the Alternate Allele increased over time (Reference Allele > Alternate Allele)<jupyter_code>in_host_SNPs_DF = in_host_SNPs_DF[in_host_SNPs_DF.altAF2_minus_altAF1 > 0]
np.shape(in_host_SNPs_DF)<jupyter_output><empty_output><jupyter_text>Save a list of H37Rv Reference Positions that in-host SNPs occur at to filter Genotypes Matrix below<jupyter_code>in_host_ref_positions_list = list(set(in_host_SNPs_DF.ref_position))<jupyter_output><empty_output><jupyter_text>Save a list of specific mutations observed in-host to filter SNPs called in rollingDB later<jupyter_code>in_host_SNPs_mut_keys_list = [str(ref_pos_i) + '_' + alt_allele_i for ref_pos_i , alt_allele_i in zip(in_host_SNPs_DF.ref_position , in_host_SNPs_DF.alt_allele)]<jupyter_output><empty_output><jupyter_text>Load SNPs from scraping Luca's DB (Genotypes Matrix)<jupyter_code>#load SNP annotation file (rows of Genotype Matrix)
SNP_annotation_DF = pd.read_pickle('/n/data1/hms/dbmi/farhat/Roger/inhost_TB_dynamics_project/genotypes_matrix_and_tSNE/Genotype_Filtered_2/genotypes_SNP_annotation.pkl')

#load isolate annotation file (columns of Genotypes Matrix)
isolate_annotation_DF = pd.read_pickle('/n/data1/hms/dbmi/farhat/Roger/inhost_TB_dynamics_project/genotypes_matrix_and_tSNE/Genotype_Filtered_2/genotypes_isolate_annotation.pkl')

#load Genotypes Matrix
genotypes_array = np.load('/n/data1/hms/dbmi/farhat/Roger/inhost_TB_dynamics_project/genotypes_matrix_and_tSNE/Genotype_Filtered_2/genotypes_matrix.npy')

#SNP functional annotation
SNP_functional_annotation_DF = pd.read_pickle('/n/data1/hms/dbmi/farhat/Roger/inhost_TB_dynamics_project/genotypes_matrix_and_tSNE/Genotype_Filtered_2/genotypes_SNP_functional_annotation.pkl')
SNP_annotation_DF.head()
np.shape(SNP_annotation_DF)
isolate_annotation_DF.head()
np.shape(isolate_annotation_DF)
np.shape(genotypes_array)
SNP_functional_annotation_DF.head()<jupyter_output><empty_output><jupyter_text>Rule 1A: Filter SNPs - Subset genotypes matrix to SNPs that occur at same sites as *in-host* SNPs<jupyter_code>SNPs_to_keep_filter = [ SNP_i_ref_pos in in_host_ref_positions_list for SNP_i_ref_pos in list(SNP_annotation_DF.pos) ]<jupyter_output><empty_output><jupyter_text>49 in-host SNP sites detected in Genotypes Matrix<jupyter_code>sum(SNPs_to_keep_filter)<jupyter_output><empty_output><jupyter_text>Filter SNPs annotation DF<jupyter_code>SNP_annotation_DF = SNP_annotation_DF[SNPs_to_keep_filter]
SNP_annotation_DF.reset_index(inplace = True , drop = True)
SNP_annotation_DF.head()
np.shape(SNP_annotation_DF)<jupyter_output><empty_output><jupyter_text>Filter Genotypes Matrix<jupyter_code>genotypes_array = genotypes_array[SNPs_to_keep_filter , :]
genotypes_array
np.shape(genotypes_array)<jupyter_output><empty_output><jupyter_text>Reformat Data: format SNP (with alternate call) per Isolate into a DF with each row corresponding to a specific SNP called in an isolate<jupyter_code>base_to_code_map = {'A':0 , 'C':1 , 'G':2 , 'T':3}
base_to_code_map_r = {0:'A' , 1:'C' , 2:'G' , 3:'T'}
SNP_i_from_Lucas_DF_list = []

for SNP_index in SNP_annotation_DF.index:

    #SNP annotation
    SNP_info = SNP_annotation_DF.loc[SNP_index , :]
    SNP_ref_allele_code = base_to_code_map[SNP_info.ref]

    #genotypes for SNP
    SNP_genotypes = genotypes_array[SNP_index , :]

    #filter for isolates that have a missing call at this position
    isolates_with_missing_call_for_SNP_filter = list(SNP_genotypes == 9)

    #filter for isolates that support the reference allele at this position
    isolates_support_ref_allele_for_SNP_filter = list(SNP_genotypes == SNP_ref_allele_code)

    #filter for isolates to keep - isolates with good call that support an alternate allele
    isolate_calls_to_keep = [(not missing_call) and (not ref_allele) for missing_call , ref_allele in zip(isolates_with_missing_call_for_SNP_filter , isolates_support_ref_allele_for_SNP_filter)]

    #subset Isolates Annotation and Genotypes to Isolates with alternate call
    SNP_genotypes_isolates_support_alt_allele_for_SNP = SNP_genotypes[isolate_calls_to_keep]
    SNP_genotypes_isolates_support_alt_allele_for_SNP = [base_to_code_map_r[allele_code] for allele_code in SNP_genotypes_isolates_support_alt_allele_for_SNP] #convert to nucleotides

    isolate_annotation_isolates_support_alt_allele_for_SNP = isolate_annotation_DF[isolate_calls_to_keep]
    isolate_annotation_isolates_support_alt_allele_for_SNP.reset_index(inplace = True , drop = True)

    #combine (SNP info) , (genotypes for isolates w/ alt allele) , isolate annotation into 1 DF
    SNP_i_from_Lucas_DB_df = pd.DataFrame()
    isolate_ID_list = isolate_annotation_isolates_support_alt_allele_for_SNP.isolate_ID
    ref_pos_list = [SNP_info.pos] * np.shape(isolate_annotation_isolates_support_alt_allele_for_SNP)[0]
    ref_allele_list = [SNP_info.ref] * np.shape(isolate_annotation_isolates_support_alt_allele_for_SNP)[0]
    gene_id_list = [SNP_info.gene_id[0]] * np.shape(isolate_annotation_isolates_support_alt_allele_for_SNP)[0]
    gene_category_list = [SNP_info.gene_category[0]] * np.shape(isolate_annotation_isolates_support_alt_allele_for_SNP)[0]
    symbol_list = [SNP_info.gene_name[0]] * np.shape(isolate_annotation_isolates_support_alt_allele_for_SNP)[0]

    #get functional SNP annotation (will change per isolate depending on the alternate allele)
    genomic_coord_list = [ SNP_functional_annotation_DF.loc[str(pos_i) + '_' + alt_allele_i , 'gene_pos'] for pos_i , alt_allele_i in zip(ref_pos_list , SNP_genotypes_isolates_support_alt_allele_for_SNP)]
    SNP_type_list = [ SNP_functional_annotation_DF.loc[str(pos_i) + '_' + alt_allele_i , 'SNP_type'] for pos_i , alt_allele_i in zip(ref_pos_list , SNP_genotypes_isolates_support_alt_allele_for_SNP)]
    AA_change_list = [ SNP_functional_annotation_DF.loc[str(pos_i) + '_' + alt_allele_i , 'AA_change'] for pos_i , alt_allele_i in zip(ref_pos_list , SNP_genotypes_isolates_support_alt_allele_for_SNP)]

    #create DataFrame with information about this SNP for each isolate with alt allele
    SNP_i_from_Lucas_DB_df.loc[: , 'isolate_ID'] = isolate_ID_list
    SNP_i_from_Lucas_DB_df.loc[: , 'ref_position'] = ref_pos_list
    SNP_i_from_Lucas_DB_df.loc[: , 'genomic_coord'] = genomic_coord_list
    SNP_i_from_Lucas_DB_df.loc[: , 'ref_allele'] = ref_allele_list
    SNP_i_from_Lucas_DB_df.loc[: , 'alt_allele'] = SNP_genotypes_isolates_support_alt_allele_for_SNP
    SNP_i_from_Lucas_DB_df.loc[: , 'gene_id'] = gene_id_list
    SNP_i_from_Lucas_DB_df.loc[: , 'Gene_Category'] = gene_category_list
    SNP_i_from_Lucas_DB_df.loc[: , 'symbol'] = symbol_list
    SNP_i_from_Lucas_DB_df.loc[: , 'SNP_type'] = SNP_type_list
    SNP_i_from_Lucas_DB_df.loc[: , 'AA_change'] = AA_change_list

    #merge DataFrame with SNP info with the DataFrame with the Isolate info
    SNP_i_from_Lucas_DB_df = SNP_i_from_Lucas_DB_df.merge(isolate_annotation_isolates_support_alt_allele_for_SNP , how = 'right' , on = 'isolate_ID')
    
    #append to list of DataFrames for each SNP
    SNP_i_from_Lucas_DF_list.append(SNP_i_from_Lucas_DB_df)
    
#append all DataFrames (1 for each SNP site) into one master DF
SNPs_from_Lucas_DB_df = pd.concat(SNP_i_from_Lucas_DF_list)
SNPs_from_Lucas_DB_df.reset_index(inplace = True , drop = True)
SNPs_from_Lucas_DB_df.head()
SNPs_from_Lucas_DB_df.tail()
np.shape(SNPs_from_Lucas_DB_df)<jupyter_output><empty_output><jupyter_text>Rule 1B: Retain only SNP calls in which the Alternate Allele matches the Alternate Allele called *in-host* This is needed since some SNP sites are not biallelic<jupyter_code>SNPs_from_Lucas_DB_to_keep_filter = []

for SNP_i_ref_pos , SNP_i_alt_allele in zip(SNPs_from_Lucas_DB_df.ref_position , SNPs_from_Lucas_DB_df.alt_allele):
    
    if str(SNP_i_ref_pos) + '_' + SNP_i_alt_allele in in_host_SNPs_mut_keys_list:
        
        SNPs_from_Lucas_DB_to_keep_filter.append(True)
        
    else:
        
        SNPs_from_Lucas_DB_to_keep_filter.append(False)
        
SNPs_from_Lucas_DB_df = SNPs_from_Lucas_DB_df[SNPs_from_Lucas_DB_to_keep_filter]
SNPs_from_Lucas_DB_df.reset_index(inplace = True , drop = True) #reset index
SNPs_from_Lucas_DB_df.head()
np.shape(SNPs_from_Lucas_DB_df)<jupyter_output><empty_output><jupyter_text>Output DataFrame of all SNPs picked up from RollingDB and used for analysis for Supplementary Table<jupyter_code>SNPs_from_Lucas_DB_df.to_csv('/n/data1/hms/dbmi/farhat/Roger/inhost_TB_dynamics_project/CSV_files/rolling_DB_scrape/SNPs_from_rollingDB.csv')<jupyter_output><empty_output><jupyter_text>Count the number of each global lineage represented in the Luca's isolate pool<jupyter_code>global_lineage_count = pd.Series( Counter( isolate_annotation_DF.lineage_1 ) )
global_lineage_count = global_lineage_count[['1' , '2' , '3' , '4' , '5' , '6']]
global_lineage_count.fillna(0.0 , inplace = True)
global_lineage_count
int( global_lineage_count.sum() )
pie_slice_proportions = []
labels = []
colors = []

for global_lineage_i in global_lineage_count.index:
    
    proportion = float(global_lineage_count[global_lineage_i]) / float(global_lineage_count.sum())
    pie_slice_proportions.append(proportion)
    labels.append(global_lineage_i)
    
    if global_lineage_i == '1':
        colors.append('xkcd:pink')
    if global_lineage_i == '2':
        colors.append('xkcd:bright blue')
    if global_lineage_i == '3':
        colors.append('xkcd:purple')
    if global_lineage_i == '4':
        colors.append('xkcd:red')
    if global_lineage_i == '5':
        colors.append('xkcd:brown')
    if global_lineage_i == '6':
        colors.append('xkcd:green')
        
# Make square figures and axes
the_grid = GridSpec(1, 1)

fig, ax = plt.subplots()

wedges, texts = ax.pie(pie_slice_proportions, shadow=False , colors = colors , wedgeprops = {'linewidth': 12 } , labeldistance = 1.1 , startangle = 23)

fig = plt.gcf()
fig.set_size_inches(4, 4)
fig.tight_layout()

for w in wedges:
    w.set_linewidth(1.5)
    w.set_edgecolor('black')
    
#for text in texts:
#    text.set_rotation(0)

file_name = '/n/data1/hms/dbmi/farhat/Roger/inhost_TB_dynamics_project/figures/scraping_rollingDB/Global_Lineage_Distribution_across_all_isolates.pdf'
plt.savefig(file_name, bbox_inches='tight', dpi = 300 , transparent = True)
    
plt.show()<jupyter_output><empty_output><jupyter_text>Count the number of SNPs that occur for each individual SNP site (identified from *in-host* SNPs)  Add a column to specify specific SNP Reference Position and Alterante Allele<jupyter_code>SNPs_from_Lucas_DB_df['ref_position_and_alt_allele'] = [ (str(int(ref_pos)) + '_' + alt_allele) for ref_pos, alt_allele in zip(list( SNPs_from_Lucas_DB_df.ref_position ) , list( SNPs_from_Lucas_DB_df.alt_allele ) )]<jupyter_output><empty_output><jupyter_text>Rule 2A: Look for SNPs that were present in $\ge 3$ global lineages<jupyter_code>SNPs_present_in_multiple_lineages = []

for SNP_i in list(set(SNPs_from_Lucas_DB_df.ref_position_and_alt_allele)):
    
    lineage_call_count_for_SNPs_in_rollingDB = pd.Series( Counter( SNPs_from_Lucas_DB_df[SNPs_from_Lucas_DB_df.ref_position_and_alt_allele == SNP_i].lineage_1 ) )
    
    num_global_lineages = len(lineage_call_count_for_SNPs_in_rollingDB)
    
    if num_global_lineages >= 3:
        
        SNPs_present_in_multiple_lineages.append(SNP_i)<jupyter_output><empty_output><jupyter_text>Create DataFrame to hold information for SNPs present in multiple global lineages<jupyter_code>#drop 'duplicate' rows in longitudinal SNPs df (SNPs that were present in > than 1 subject)
codon_SNPs_no_repeat_SNPs = SNPs_from_Lucas_DB_df[ [not duplicate_SNP for duplicate_SNP in SNPs_from_Lucas_DB_df.duplicated(subset = ['genomic_coord' , 'ref_allele' , 'alt_allele' , 'gene_id' , 'ref_position_and_alt_allele'], keep = 'first')] ]

#re-index codon SNP df by reference position-alt allele keys
codon_SNPs_reindexed = codon_SNPs_no_repeat_SNPs.set_index('ref_position_and_alt_allele' , drop = True)

#subset df to SNPs that cropped up in multiple global lineages
SNPs_present_in_multiple_lineages_DF = codon_SNPs_reindexed.loc[SNPs_present_in_multiple_lineages , :]

#drop unneccessary columns
SNPs_present_in_multiple_lineages_DF.drop(['isolate_ID' , 'lineage_1' , 'lineage_2' , 'lineage_3' , 'lineage_4', 'lineage_5'] , axis = 1 , inplace = True)

#make ref_position a column
SNPs_present_in_multiple_lineages_DF['ref_position_and_alt_allele'] = SNPs_present_in_multiple_lineages_DF.index 

#sort by reference position
SNPs_present_in_multiple_lineages_DF.sort_values(by = 'ref_position' , ascending = True , inplace = True)

#re-index
SNPs_present_in_multiple_lineages_DF.reset_index(inplace = True , drop = True)
SNPs_present_in_multiple_lineages_DF<jupyter_output><empty_output><jupyter_text>Store the global lineage distribution for each SNP (Alternate Allele)<jupyter_code>global_lineage_distribution_for_SNPs = pd.DataFrame( index = SNPs_present_in_multiple_lineages_DF.index , columns = ['1' , '2' , '3' , '4' , '5' , '6'] )

for SNP_i in SNPs_present_in_multiple_lineages_DF.index:
    
    ref_pos_alt_base_i = SNPs_present_in_multiple_lineages_DF.loc[SNP_i , 'ref_position_and_alt_allele']
    
    #this counts the number of each global lineage represented in the isolates that have the SNP
    lineage_call_count_for_SNPs_in_rollingDB = pd.Series( Counter( SNPs_from_Lucas_DB_df[SNPs_from_Lucas_DB_df.ref_position_and_alt_allele == ref_pos_alt_base_i].lineage_1 ) )
    
    #fill in the dataframe that holds distribution
    for global_lineage in global_lineage_distribution_for_SNPs.columns:
        
        try:
            
            global_lineage_distribution_for_SNPs.loc[SNP_i , global_lineage] = lineage_call_count_for_SNPs_in_rollingDB[global_lineage]
            
        except KeyError:
            
            global_lineage_distribution_for_SNPs.loc[SNP_i , global_lineage] = 0.0<jupyter_output><empty_output><jupyter_text>Append a column that stores the total number of isolates that SNP was found in<jupyter_code>global_lineage_distribution_for_SNPs['num_isolates'] = global_lineage_distribution_for_SNPs.sum(axis = 1)
global_lineage_distribution_for_SNPs.head()<jupyter_output><empty_output><jupyter_text>Merge DataFrame that holds SNP information to DF that holds global lineage distribution<jupyter_code>SNPs_present_in_multiple_lineages_DF = SNPs_present_in_multiple_lineages_DF.merge(global_lineage_distribution_for_SNPs , how = 'inner' , left_index = True , right_index = True)
SNPs_present_in_multiple_lineages_DF.head()
SNPs_present_in_multiple_lineages_DF.tail()<jupyter_output><empty_output><jupyter_text>Rule 2B: Filter for SNPs in which the Alternate Allele is present in at least 1 isolate $\ge 3$ global lineages and *not* present in $> 95\%$ of isolates within those global lineages  Get the percentage of isolates (within each global lineage) that supported the alternate allele<jupyter_code>SNPs_present_in_multiple_lineages_DF['lin1_prop'] = SNPs_present_in_multiple_lineages_DF.loc[: , '1'].astype(float) / float(global_lineage_count['1'])
SNPs_present_in_multiple_lineages_DF['lin2_prop'] = SNPs_present_in_multiple_lineages_DF.loc[: , '2'].astype(float) / float(global_lineage_count['2'])
SNPs_present_in_multiple_lineages_DF['lin3_prop'] = SNPs_present_in_multiple_lineages_DF.loc[: , '3'].astype(float) / float(global_lineage_count['3'])
SNPs_present_in_multiple_lineages_DF['lin4_prop'] = SNPs_present_in_multiple_lineages_DF.loc[: , '4'].astype(float) / float(global_lineage_count['4'])
SNPs_present_in_multiple_lineages_DF['lin5_prop'] = SNPs_present_in_multiple_lineages_DF.loc[: , '5'].astype(float) / float(global_lineage_count['5'])
SNPs_present_in_multiple_lineages_DF['lin6_prop'] = SNPs_present_in_multiple_lineages_DF.loc[: , '6'].astype(float) / float(global_lineage_count['6'])
SNPs_present_in_multiple_lineages_DF.head()<jupyter_output><empty_output><jupyter_text>Retain only SNPs in which the Alternate Allele was present in $ \ge 1$ isolate and  $\le 95 \%$ of isolates within at least **3 global lineages**<jupyter_code>global_lineage_array = np.array(['1','2','3','4','5','6'])
multiple_lineage_support_alt_allele_filter = [] #boolean filter that will retain SNPs for which alt allele is called in at least 1 isolate and less than 95% of isolates for at least 3 lineages

for SNP_i in SNPs_present_in_multiple_lineages_DF.index:

    keep_SNP = False
    
    #raw counts
    SNP_alt_allele_global_lineage_num_support = SNPs_present_in_multiple_lineages_DF.loc[SNP_i , ['1','2','3','4','5','6']]
    
    #proportions
    SNP_alt_allele_global_lineage_prop_support = SNPs_present_in_multiple_lineages_DF.loc[SNP_i , ['lin1_prop','lin2_prop','lin3_prop','lin4_prop','lin5_prop','lin6_prop']]
    
    #iterate through each global lineage and see if it supports the alternate allele according to rules
    global_lineages_support_alt_allele = 0
    for lin_i_isolate_count , lin_i_isolate_prop in zip(SNP_alt_allele_global_lineage_num_support , SNP_alt_allele_global_lineage_prop_support):
        
        if (lin_i_isolate_count >= 1) and (lin_i_isolate_prop <= 0.95):
            global_lineages_support_alt_allele += 1
            
    if global_lineages_support_alt_allele >= 3:
            keep_SNP = True

    multiple_lineage_support_alt_allele_filter.append(keep_SNP)
SNPs_present_in_multiple_lineages_DF = SNPs_present_in_multiple_lineages_DF[multiple_lineage_support_alt_allele_filter]
#reset index of subset DF
SNPs_present_in_multiple_lineages_DF.reset_index(drop = True , inplace = True)
SNPs_present_in_multiple_lineages_DF.head()<jupyter_output><empty_output><jupyter_text>**re-index:** Distribution of Global Lineages within each isolates pool that has SNP<jupyter_code>SNPs_present_in_multiple_lineages_DF_reindexed = SNPs_present_in_multiple_lineages_DF.set_index('ref_position_and_alt_allele' , drop = True)
with pd.option_context('display.max_rows', None, 'display.max_columns', None):  # more options can be specified also
    display(SNPs_present_in_multiple_lineages_DF_reindexed)<jupyter_output><empty_output><jupyter_text>Output DF as CSV<jupyter_code>SNPs_present_in_multiple_lineages_DF_reindexed.to_csv('/n/data1/hms/dbmi/farhat/Roger/inhost_TB_dynamics_project/CSV_files/rolling_DB_scrape/SNPs_in_multiple_global_lineages.csv')
np.shape(SNPs_present_in_multiple_lineages_DF_reindexed)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08446550307015423, 'fraction_numerical': 0.008219310544891941, 'mean_word_length': 6.849715370018975, 'pattern_counts': {'":': 0, '<': 98, '<?xml version=': 0, '>': 104, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '24', 'dir': 'jupyter-structured-clean-dedup', 'id': '37957', 'license': 'Naumen', 'n_tokens_mistral': 7852, 'n_tokens_neox': 7350, 'n_words': 1320, 'path': 'SNPs from Public Samples & tSNE Homoplasy Visualization/(D) Phylogenetic Convergence Test in Public Samples for In-Host SNPs.ipynb', 'repo_name': 'farhat-lab/in-host-Mtbc-dynamics', 'size': '20683'}