├── .DS_Store ├── README.md ├── afdb-regions-network-R ├── .DS_Store ├── README.md ├── Rscript_1.R ├── Rscript_10.R ├── Rscript_2.R ├── Rscript_3.R ├── Rscript_4.R ├── Rscript_5.R ├── Rscript_6.R ├── Rscript_7.R ├── Rscript_8.R └── Rscript_9.R ├── commands ├── commands_darkening ├── commands_distribution ├── commands_purity ├── commands_sapiens ├── commands_share_db ├── dark_distribution └── dark_distribution.ipynb ├── purity ├── pfam_consistency.ipynb ├── purity_figure.ipynb └── subsitute_clan.ipynb ├── sapiens_go_exploration └── find_immune_related_human_cluster.ipynb └── sapiens_plot └── go_plot.ipynb /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steineggerlab/afdb-clusters-analysis/4c38d80184fbb967b5fc9fe75d7a765a1c6cf98e/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # afdb-clusters-analysis 2 | Scripts to generate and analyze afdb clusters 3 | 4 | [Barrio-Hernandez I, Yeo J, Jänes J, Wein T, Varadi M, Velankar S, Beltrao P, Steinegger M. Clustering predicted structures at the scale of the known protein universe. Nature, doi.org:10.1101/2023.03.09.531927 (2023)]([https://www.nature.com/articles/s41586-023-06510-w](https://www.nature.com/articles/s41586-023-06510-w)) 5 | -------------------------------------------------------------------------------- /afdb-regions-network-R/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steineggerlab/afdb-clusters-analysis/4c38d80184fbb967b5fc9fe75d7a765a1c6cf98e/afdb-regions-network-R/.DS_Store -------------------------------------------------------------------------------- /afdb-regions-network-R/README.md: -------------------------------------------------------------------------------- 1 | # afdb-regions-network 2 | 3 | Scripts to analyse protein protein similarities based on foldseek output, as described in methods 4 | 5 | Barrio-Hernandez I, Yeo J, Jänes J, Wein T, Varadi M, Velankar S, Beltrao P, Steinegger M. Clustering predicted structures at the scale of the known protein universe. bioRxiv, doi.org:10.1101/2023.03.09.531927 (2023) 6 | 7 | SCRIPT 1: partition of Foldseek output for paralelization 8 | SCRIPT 2: filtering edges for evalue<=0.001 plus protein files per partition (loop) 9 | SCRIPT 3: getting ready for hierarchical clustering of regions per protein 10 | SCRIPT 4: hierarchical clustering of regions per protein (loop) 11 | SCRIPT 5: assembling clustering results 12 | SCRIPT 6: recoding the edges (based on clustering results) 13 | SCRIPT 7: assembling the recoded tables, selection of connected components 14 | SCRIPT 8: PFAM annotation of regions, first part, extracting information from database and cuting of files 15 | SCRIPT 9: annotation of regions using pfam (loop) 16 | SCRIPT 10: trimming of the network, clustering of regions from connected components and connecting modules 17 | -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_1.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ###SCRIPT1: partition of original table to handle size 5 | 6 | ######Due to file size, we split it in files containing 2,000,000 lines (561 files in total) 7 | 8 | ####open connexion 9 | 10 | raw_data_path <- "/nfs/research/beltrao/ibarrioh/AF-3D/071022/afdb50best_clu_nosingleton_repseq_ava.m8.gz" 11 | raw_data_nrow <- length(count.fields(raw_data_path)) 12 | 13 | con = file(raw_data_path, "r") 14 | 15 | ###cutting loop 16 | 17 | for (i in 0:560){ 18 | 19 | pairs=read.delim(con, nrows=2000000,header=F) 20 | 21 | temp_node=unique(c(paste(as.character(pairs[,1]), 22 | pairs[,7], 23 | pairs[,8],sep="_"), 24 | paste(as.character(pairs[,2]), 25 | pairs[,9], 26 | pairs[,10],sep="_"))) 27 | 28 | temp_edge=cbind(paste(as.character(pairs[,1]), 29 | pairs[,7], 30 | pairs[,8],sep="_"), 31 | paste(as.character(pairs[,2]), 32 | pairs[,9], 33 | pairs[,10],sep="_"), 34 | pairs[,11], 35 | pairs[,12]) 36 | 37 | path_1=paste("interactome_nodes_temp/nodes_",i,".rds",sep="") 38 | path_2=paste("interactome_edges_temp/edges_",i,".rds",sep="") 39 | 40 | saveRDS(temp_node,path_1) 41 | saveRDS(temp_edge,path_2) 42 | 43 | } 44 | close(con) 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | # -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_10.R: -------------------------------------------------------------------------------- 1 | 2 | ####SCRIPT-10: trimming of the network, clustering of regions from connected components and connecting modules 3 | 4 | 5 | library(igraph) 6 | 7 | pairs=readRDS("cut_001eval/recode_edges_all_FILTER.rds") 8 | modules=readRDS("cut_001eval/result_modules_all.rds") 9 | colnames(pairs)=c("Query","Target","Eval","score") 10 | 11 | pairs=pairs[as.numeric(pairs[,"Eval"])<=0.00001,] 12 | 13 | modules=cbind(modules,"","") 14 | colnames(modules)[(ncol(modules)-1):ncol(modules)]=c("subnet_trim","clust_trim") 15 | 16 | ####sizes of recoded regions 17 | 18 | length_structures=as.numeric(modules[,"end"])-as.numeric(modules[,"start"]) 19 | 20 | ####stablishing filter to trim the network, length<350 and pval<=0.00001 -5 21 | 22 | criteria=pairs[,"Query"]%in%rownames(modules)[length_structures<=350] & 23 | pairs[,"Target"]%in%rownames(modules)[length_structures<=350] 24 | 25 | net=graph_from_data_frame(d=pairs[criteria,c("Query","Target")],directed=F) 26 | E(net)$weight=as.numeric(pairs[criteria,"Eval"]) 27 | E(net)$score=as.numeric(pairs[criteria,"score"]) 28 | subnet=components(net) 29 | 30 | modules[names(subnet$membership),"subnet_trim"]=subnet$membership 31 | 32 | saveRDS(modules,"cut_001eval/result_modules_all_trim350_pval5.rds") 33 | 34 | ####Selection of connected components for walktrap clustering (at least 100 members) 35 | 36 | sel=table(subnet$membership) 37 | sel=sel[sel>=100] 38 | 39 | 40 | criteria=pairs[,"Query"]%in%rownames(modules)[modules[,"subnet_trim"]%in%names(sel)] & 41 | pairs[,"Target"]%in%rownames(modules)[modules[,"subnet_trim"]%in%names(sel)] 42 | 43 | pairs=pairs[criteria,] 44 | rm(net) 45 | gc() 46 | 47 | for (i in 1:length(sel)){ 48 | 49 | criteria=pairs[,"Query"]%in%rownames(modules)[modules[,"subnet_trim"]%in%names(sel)[i]] & 50 | pairs[,"Target"]%in%rownames(modules)[modules[,"subnet_trim"]%in%names(sel)[i]] 51 | 52 | 53 | net=graph_from_data_frame(d=pairs[criteria,c("Query","Target")],directed=F) 54 | E(net)$weight=as.numeric(pairs[criteria,"Eval"]) 55 | E(net)$score=as.numeric(pairs[criteria,"score"]) 56 | 57 | cwt=cluster_walktrap( net, 58 | weights = E(net)$weight, 59 | steps = 6, 60 | merges = TRUE, 61 | modularity = TRUE, 62 | membership = TRUE) 63 | 64 | modules[V(net)$name,"clust_trim"]=cwt$membership 65 | 66 | } 67 | 68 | ###saving the tables with connected components and clustr information 69 | 70 | saveRDS(modules,"cut_001eval/result_modules_all_trim350_pval5.rds") 71 | 72 | ################################################################################ 73 | ################################################################################ 74 | ################################################################################ 75 | ####Table of modules (connected components plus clusters) 76 | 77 | modules=readRDS("cut_001eval/result_modules_all_trim350_pval5.rds") 78 | sum(modules[,"clust_trim"]!="") 79 | sum(modules[,"subnet_trim"]!="") 80 | 81 | modules[modules[,"clust_trim"]!="","subnet_trim"]=paste(modules[modules[,"clust_trim"]!="","subnet_trim"], 82 | modules[modules[,"clust_trim"]!="","clust_trim"], 83 | sep=";") 84 | 85 | ###Protein regions that are part of a community (connected component or cluster) 86 | 87 | modules=modules[modules[,"subnet_trim"]!="",] 88 | 89 | mod_pfam_long=readRDS("cut_001eval/result_longCut_all.rds") 90 | mod_pfam_long=mod_pfam_long[mod_pfam_long[,"ID"]%in%rownames(modules),] 91 | mod_pfam_long[,"subnet"]=modules[mod_pfam_long[,"ID"],"subnet_trim"] 92 | 93 | #####Table of modules 94 | 95 | pfam_clusters=cbind(table(modules[,"subnet_trim"]), 96 | "", 97 | "", 98 | "", 99 | "", 100 | "", 101 | "", 102 | "", 103 | "") 104 | 105 | colnames(pfam_clusters)=c("counts_chunks", 106 | "counts_chunks_pfam", 107 | "counts_chunks_pfam_075", 108 | "pfam_first", 109 | "pfam_first_count", 110 | "pfam_first_rel", 111 | "pfam_second", 112 | "pfam_second_count", 113 | "pfam_second_rel") 114 | 115 | pfam_clusters=pfam_clusters[as.numeric(pfam_clusters[,1])>=5,] 116 | 117 | ####Annotating the modules with pfam from regions 118 | 119 | modules=modules[modules[,"subnet_trim"]%in%rownames(pfam_clusters),] 120 | mod_pfam_long=mod_pfam_long[mod_pfam_long[,"subnet"]%in%rownames(pfam_clusters),] 121 | 122 | temp=table(modules[modules[,"pfam_counts"]!="","subnet_trim"]) 123 | temp=temp[names(temp)%in%rownames(pfam_clusters)] 124 | pfam_clusters[names(temp),"counts_chunks_pfam"]=temp 125 | 126 | ###intermediate table 127 | 128 | intermedio=mod_pfam_long[,c("subnet","pfam_names","ID")] 129 | intermedio=intermedio[!duplicated(intermedio),] 130 | 131 | for (i in 1:nrow(pfam_clusters)){ 132 | 133 | temp=cbind(intermedio[intermedio[,"subnet"]%in%rownames(pfam_clusters)[i],"pfam_names"], 134 | intermedio[intermedio[,"subnet"]%in%rownames(pfam_clusters)[i],"ID"]) 135 | 136 | if(length(temp)>2){ 137 | 138 | temp1=table(temp[,1]) 139 | temp1=temp1[order(temp1,decreasing=T)] 140 | 141 | if(length(temp1)>1){ 142 | 143 | pfam_clusters[i,c("pfam_first","pfam_second")]=names(temp1)[1:2] 144 | pfam_clusters[i,c("pfam_first_count","pfam_second_count")]=temp1[1:2] 145 | pfam_clusters[i,c("counts_chunks_pfam_075")]=sum(!duplicated(temp[,2])) 146 | 147 | }else{ 148 | 149 | pfam_clusters[i,c("pfam_first","pfam_second")]=c(names(temp1),"") 150 | pfam_clusters[i,c("pfam_first_count","pfam_second_count")]=c(temp1,"") 151 | pfam_clusters[i,c("counts_chunks_pfam_075")]=sum(!duplicated(temp[,2])) 152 | } 153 | 154 | }else{ 155 | 156 | pfam_clusters[i,c("pfam_first","pfam_second")]=c(temp[1],"") 157 | pfam_clusters[i,c("pfam_first_count","pfam_second_count")]=c(1,"") 158 | pfam_clusters[i,c("counts_chunks_pfam_075")]=1 159 | 160 | } 161 | 162 | } 163 | 164 | ####REcoding for missing 165 | 166 | sum(is.na(pfam_clusters[,"pfam_first"])) 167 | sum(is.na(pfam_clusters[,"pfam_second"])) 168 | 169 | pfam_clusters[is.na(pfam_clusters[,"pfam_first"]),"counts_chunks_pfam_075"]="0" 170 | pfam_clusters[is.na(pfam_clusters[,"pfam_first"]),"pfam_first_count"]="0" 171 | pfam_clusters[is.na(pfam_clusters[,"pfam_first"]),"pfam_first"]="" 172 | pfam_clusters[pfam_clusters[,"pfam_second_count"]=="","pfam_second_count"]="0" 173 | pfam_clusters[pfam_clusters[,"pfam_first_count"]=="","pfam_first_count"]="0" 174 | pfam_clusters[pfam_clusters[,"counts_chunks_pfam_075"]=="0","pfam_first_count"]="0" 175 | pfam_clusters[pfam_clusters[,"counts_chunks_pfam_075"]=="0","pfam_second_count"]="0" 176 | 177 | pfam_clusters[pfam_clusters[,"counts_chunks_pfam_075"]!="0","pfam_first_rel"]=as.numeric(pfam_clusters[pfam_clusters[,"counts_chunks_pfam_075"]!="0","pfam_first_count"])/ 178 | as.numeric(pfam_clusters[pfam_clusters[,"counts_chunks_pfam_075"]!="0","counts_chunks_pfam_075"]) 179 | 180 | pfam_clusters[pfam_clusters[,"counts_chunks_pfam_075"]!="0","pfam_second_rel"]=as.numeric(pfam_clusters[pfam_clusters[,"counts_chunks_pfam_075"]!="0","pfam_second_count"])/ 181 | as.numeric(pfam_clusters[pfam_clusters[,"counts_chunks_pfam_075"]!="0","counts_chunks_pfam_075"]) 182 | 183 | saveRDS(pfam_clusters,"cut_001eval/communities_trim350_pval5_min5struc.rds")###supplementary table 184 | 185 | 186 | ################################################################################ 187 | ################################################################################ 188 | #####Selection of edges connecting modules 189 | 190 | pairs=readRDS("cut_001eval/recode_edges_all_FILTER.rds") 191 | colnames(pairs)=c("Query","Target","Eval","score") 192 | 193 | modules=readRDS("cut_001eval/result_modules_all_trim350_pval5.rds") 194 | 195 | modules[modules[,"clust_trim"]!="","subnet_trim"]=paste(modules[modules[,"clust_trim"]!="","subnet_trim"], 196 | modules[modules[,"clust_trim"]!="","clust_trim"], 197 | sep=";") 198 | 199 | ###Filtering 200 | 201 | modules=modules[modules[,"subnet_trim"]!="",] 202 | 203 | temp=table(modules[,"subnet_trim"]) 204 | temp=temp[temp>=10] 205 | 206 | modules=modules[modules[,"subnet_trim"]%in%names(temp),] 207 | 208 | ####Finding the edges connecting modules 209 | 210 | recoding=modules[,"subnet_trim"] 211 | names(recoding)=rownames(modules) 212 | 213 | pairs=pairs[pairs[,"Query"]%in%names(recoding) & 214 | pairs[,"Target"]%in%names(recoding) ,] 215 | 216 | pairs[,"Query"]=recoding[pairs[,"Query"]] 217 | pairs[,"Target"]=recoding[pairs[,"Target"]] 218 | 219 | ###Keeping the ones with smaller evalues 220 | 221 | net=graph_from_data_frame(d=pairs[,c("Query","Target")],directed=F) 222 | E(net)$weight=as.numeric(pairs[,"Eval"]) 223 | E(net)$score=as.numeric(pairs[,"score"]) 224 | 225 | net=igraph::simplify(net,remove.loops = T,remove.multiple = T , edge.attr.comb = c(weight="min",score="max","ignore")) 226 | 227 | saveRDS(cbind(get.edgelist(net,names = T), 228 | E(net)$weight, 229 | E(net)$score), 230 | "cut_001eval/recode_edges_all_comunities_trim350_pval5.rds") 231 | 232 | ################################################################################ 233 | ################################################################################ 234 | ################################################################################ 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_2.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | ###SCRIPT2: cutting for evalue<=0.001 plus protein tables 4 | 5 | 6 | 7 | ###Argument to loop in a cluster system 8 | 9 | i <- as.numeric(commandArgs(trailingOnly = TRUE)) 10 | 11 | path1="interactome_edges_temp/edges_" ###path with the 561 original file partitions 12 | 13 | path2_edges="cut_001eval/interactome_edges_temp/edges_"###new location of filtered tables 14 | path2_nodes="cut_001eval/interactome_nodes_temp/nodes_" 15 | path2_nodes_nonred="cut_001eval/interactome_nodes_temp/nodes_prot" 16 | 17 | library(igraph) 18 | 19 | setwd("/hps/nobackup/beltrao/ibarrioh/AF-3D/071022/interactome_edges_temp") 20 | 21 | ###open original tables, filter names to keep uniprot IDs 22 | pairs=readRDS(paste(path1,i,".rds",sep="")) 23 | colnames(pairs)=c("Query","Target","Eval","score") 24 | pairs=pairs[as.numeric(pairs[,"Eval"])<=0.001,] 25 | pairs[,"Query"]=gsub("-F1-model_v3.cif","",pairs[,"Query"]) 26 | pairs[,"Query"]=gsub("AF-","",pairs[,"Query"]) 27 | pairs[,"Target"]=gsub("-F1-model_v3.cif","",pairs[,"Target"]) 28 | pairs[,"Target"]=gsub("AF-","",pairs[,"Target"]) 29 | gc() 30 | 31 | ###Use igraph to remove duplicities keeping max score and min evalue 32 | net=graph_from_data_frame(d=pairs[,c("Query","Target")],directed=F) 33 | E(net)$weight=as.numeric(pairs[,"Eval"]) 34 | E(net)$score=as.numeric(pairs[,"score"]) 35 | net=igraph::simplify(net,remove.loops = T,remove.multiple = T , edge.attr.comb = c(weight="min",score="max","ignore")) 36 | Isolated = which(igraph::degree(net)==0) 37 | length(Isolated) 38 | net = delete.vertices(net, Isolated) 39 | 40 | nodes=V(net)$name 41 | 42 | ###Saving protein sequence regions 43 | saveRDS(nodes,paste(path2_nodes,i,".rds",sep="")) 44 | saveRDS(cbind(get.edgelist(net,names = T), 45 | E(net)$weight, 46 | E(net)$score),paste(path2_edges,i,".rds",sep="")) 47 | 48 | ###saving unique roteins the regions beong to 49 | nodes=unlist(strsplit(nodes,"_"))[c(T,F,F)] 50 | nodes=nodes[!duplicated(nodes)] 51 | saveRDS(nodes,paste(path2_nodes_nonred,i,".rds",sep="")) 52 | -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_3.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | ####SCRIPT3: getting ready for hierarchical clustering of regions 4 | 5 | ####Here we generate vectors with uniprot identifiers, start and stop positions for each region 6 | 7 | setwd("cut_001eval/interactome_nodes_temp") 8 | 9 | files=list.files(pattern = "nodes_prot") 10 | files1=list.files(pattern = "node") 11 | files1=files1[!files1%in%files] 12 | 13 | nodes=readRDS(files1[1]) 14 | 15 | for (i in 2:length(files1)){ 16 | 17 | nodes=c(nodes,readRDS(files1[i])) 18 | 19 | } 20 | 21 | nodes=nodes[!duplicated(nodes)] 22 | saveRDS(nodes,"cut_001eval/all_proteins.rds") 23 | 24 | 25 | names_unlist=unlist(strsplit(nodes,"_"))[c(T,F,F)] 26 | saveRDS(names_unlist,"cut_001eval/all_uniprotID.rds") 27 | prots=table(names_unlist) 28 | 29 | print(sum(prots==1)) 30 | print(length(prots)) 31 | 32 | rm(names_unlist) 33 | gc() 34 | 35 | start_unlist=unlist(strsplit(nodes,"_"))[c(F,T,F)] 36 | saveRDS(start_unlist,"cut_001eval/all_start.rds") 37 | 38 | rm(start_unlist) 39 | gc() 40 | 41 | stop_unlist= unlist(strsplit(nodes,"_"))[c(F,F,T)] 42 | saveRDS(stop_unlist,"cut_001eval/all_stop.rds") 43 | 44 | 45 | ####################################################### 46 | #####Generating 580 part files with protein ID, start and stop positions 47 | 48 | ####Lines for proteins with only one region (no clustering) 49 | 50 | names_unlist=readRDS("cut_001eval/all_uniprotID.rds") 51 | start_unlist=readRDS("cut_001eval/all_start.rds") 52 | stop_unlist=readRDS("cut_001eval/all_stop.rds") 53 | 54 | prots=table(names_unlist) 55 | 56 | ##clean out proteins with one region 57 | prots=prots[prots>1] 58 | start_unlist=start_unlist[names_unlist%in%names(prots)] 59 | stop_unlist=stop_unlist[names_unlist%in%names(prots)] 60 | names_unlist=names_unlist[names_unlist%in%names(prots)] 61 | 62 | ### regions cut 63 | 64 | coor=cbind(seq(from=1, to=2004717, by=3452), 65 | c(seq(from=3452, to=2004717, by=3452),2004717)) 66 | 67 | pathID="cut_001eval/hierar/uniprotID_" 68 | pathstart="cut_001eval/hierar/start_" 69 | pathstop="cut_001eval/hierar/stop_" 70 | 71 | for (i in 1:nrow(coor)){ 72 | 73 | cluster_temp=names_unlist[names_unlist%in%names(prots)[coor[i,1]:coor[i,2]]] 74 | start_temp=start_unlist[names_unlist%in%cluster_temp] 75 | stop_temp=stop_unlist[names_unlist%in%cluster_temp] 76 | 77 | saveRDS(cluster_temp,paste(pathID,i,sep="")) 78 | saveRDS(start_temp,paste(pathstart,i,sep="")) 79 | saveRDS(stop_temp,paste(pathstop,i,sep="")) 80 | 81 | } 82 | 83 | #################################################### 84 | #################################################### 85 | 86 | 87 | ###Creasome seed 88 | 89 | i <- as.numeric(commandArgs(trailingOnly = TRUE)) 90 | 91 | pathID="/hps/nobackup/beltrao/ibarrioh/AF-3D/181022/cut_001eval/hierar/uniprotID_" 92 | pathstart="/hps/nobackup/beltrao/ibarrioh/AF-3D/181022/cut_001eval/hierar/start_" 93 | pathstop="/hps/nobackup/beltrao/ibarrioh/AF-3D/181022/cut_001eval/hierar/stop_" 94 | pathcluster="/hps/nobackup/beltrao/ibarrioh/AF-3D/181022/cut_001eval/hierar/cluster_" 95 | ####subimos los vectores 96 | 97 | vector_guia_uniprot=readRDS(paste(pathID,i,sep="")) 98 | vector_guia_from=readRDS(paste(pathstart,i,sep="")) 99 | vector_guia_to=readRDS(paste(pathstop,i,sep="")) 100 | vector_guia_cluster=rep(1,length(vector_guia_to)) 101 | protes=table(vector_guia_uniprot) 102 | 103 | 104 | for (j in 1:length(protes)){ 105 | 106 | temp=cbind(vector_guia_from[vector_guia_uniprot%in%names(protes)[j]], 107 | vector_guia_to[vector_guia_uniprot%in%names(protes)[j]]) 108 | 109 | vector_guia_cluster[vector_guia_uniprot%in%names(protes)[j]]=cutree(hclust(dist(temp,method = "euclidean")),h= 250) 110 | 111 | } 112 | 113 | saveRDS(vector_guia_cluster,paste(pathcluster,i)) 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_4.R: -------------------------------------------------------------------------------- 1 | #################################################### 2 | 3 | ###SCRIPT 4: hierarchical clustering of regions per protein 4 | 5 | ###This script is ment to run in side a loop 6 | 7 | i <- as.numeric(commandArgs(trailingOnly = TRUE)) 8 | 9 | pathID="cut_001eval/hierar/uniprotID_" 10 | pathstart="cut_001eval/hierar/start_" 11 | pathstop="cut_001eval/hierar/stop_" 12 | pathcluster="cut_001eval/hierar/cluster_" 13 | 14 | ####Protein ID plus start stop positions 15 | #### 16 | vector_guia_uniprot=readRDS(paste(pathID,i,sep="")) 17 | vector_guia_from=readRDS(paste(pathstart,i,sep="")) 18 | vector_guia_to=readRDS(paste(pathstop,i,sep="")) 19 | vector_guia_cluster=rep(1,length(vector_guia_to)) 20 | protes=table(vector_guia_uniprot) 21 | 22 | 23 | for (j in 1:length(protes)){ 24 | 25 | temp=cbind(vector_guia_from[vector_guia_uniprot%in%names(protes)[j]], 26 | vector_guia_to[vector_guia_uniprot%in%names(protes)[j]]) 27 | 28 | vector_guia_cluster[vector_guia_uniprot%in%names(protes)[j]]=cutree(hclust(dist(temp,method = "euclidean")),h= 250) 29 | 30 | } 31 | 32 | saveRDS(vector_guia_cluster,paste(pathcluster,i)) 33 | 34 | 35 | -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_5.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | ####SCRIPT5: assembling clustering results to one file 4 | 5 | setwd("cut_001eval/hierar") 6 | 7 | paths_clust=files=list.files(pattern="cluster") 8 | paths_start=files=list.files(pattern="start") 9 | paths_stop=files=list.files(pattern="stop") 10 | paths_uniprot=files=list.files(pattern="uniprot") 11 | 12 | paths_uniprot=paths_uniprot[!paths_uniprot%in%"uniprotID_0"] 13 | paths_start=paths_start[!paths_start%in%"start_0"] 14 | paths_stop=paths_stop[!paths_stop%in%"stop_0"] 15 | 16 | ####Empezamos 17 | 18 | temp=readRDS("uniprotID_0") 19 | 20 | names_vect=paste(gsub("_1","",temp), 21 | readRDS("start_0"), 22 | readRDS("stop_0"),sep="_") 23 | 24 | final_vect=temp 25 | names(final_vect)=names_vect 26 | 27 | for (i in 1:length(paths_uniprot)){ 28 | 29 | temp_uni=readRDS(paths_uniprot[i]) 30 | temp_from=readRDS(paths_start[i]) 31 | temp_to=readRDS(paths_stop[i]) 32 | temp_cl=readRDS(paths_clust[i]) 33 | 34 | temp=paste(temp_uni,temp_cl,sep="_") 35 | names(temp)=paste(temp_uni,temp_from,temp_to,sep="_") 36 | 37 | final_vect=c(final_vect,temp) 38 | 39 | } 40 | 41 | saveRDS(final_vect,"cut_001eval/mapping_chunks.rds") 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_6.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #####SCRIPT6: recoding the edges (similarity based on clustering results) 7 | 8 | ####Script meant to run inside a loop 9 | 10 | library("igraph") 11 | 12 | i <- as.numeric(commandArgs(trailingOnly = TRUE)) 13 | 14 | path=paste("cut_001eval/interactome_edges_temp/edges_",i,".rds",sep="") 15 | 16 | ####loading previous files 17 | pairs=readRDS(path) 18 | colnames(pairs)=c("Query","Target","Eval","score") 19 | net=graph_from_data_frame(d=pairs[,c("Query","Target")],directed=F) 20 | 21 | #loading mapping 22 | nodes=readRDS("cut_001eval/mapping_chunks.rds") 23 | nodes=nodes[names(nodes)%in%V(net)$name] 24 | gc() 25 | 26 | pairs=pairs[pairs[,"Query"]%in%names(nodes) & 27 | pairs[,"Target"]%in%names(nodes),] 28 | 29 | pairs[,"Query"]=nodes[pairs[,"Query"]] 30 | pairs[,"Target"]=nodes[pairs[,"Target"]] 31 | 32 | ###recoding the network and eliminating duplicates 33 | 34 | net=graph_from_data_frame(d=pairs[,c("Query","Target")],directed=F) 35 | E(net)$weight=as.numeric(pairs[,"Eval"]) 36 | E(net)$score=as.numeric(pairs[,"score"]) 37 | net=igraph::simplify(net,remove.loops = T,remove.multiple = T , edge.attr.comb = c(weight="min",score="max","ignore")) 38 | Isolated = which(igraph::degree(net)==0) 39 | length(Isolated) 40 | net = delete.vertices(net, Isolated) 41 | 42 | ###New edges 43 | 44 | path_node=paste("cut_001eval/recode/node_",i,".rds",sep="") 45 | path_edge=paste("cut_001eval/recode/edge_",i,".rds",sep="") 46 | 47 | saveRDS(nodes,path_node) 48 | saveRDS(cbind(get.edgelist(net,names = T), 49 | E(net)$weight, 50 | E(net)$score),path_edge) 51 | 52 | ############## 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_7.R: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | ############################################################################ 3 | 4 | ###SCRIPT7: assembling the recoded tables, selection of connected components 5 | 6 | #####Part1: assembly 7 | ####EDGES 8 | 9 | path="cut_001eval/recode/edge_" 10 | 11 | 12 | i=0 13 | 14 | edges=readRDS(paste(path,i,".rds",sep="")) 15 | 16 | for (i in 1:560){ 17 | 18 | edges=rbind(edges, 19 | readRDS(paste(path,i,".rds",sep=""))) 20 | 21 | } 22 | 23 | colnames(edges)=c("Query","Target","Eval","score") 24 | 25 | ###saving the assembly 26 | 27 | saveRDS(edges,"cut_001eval/recode_edges_all.rds") 28 | 29 | ####NODES 30 | 31 | path="cut_001eval/recode/node_" 32 | 33 | i=0 34 | 35 | nodes=unique(readRDS(paste(path,i,".rds",sep=""))) 36 | 37 | for (i in 1:560){ 38 | 39 | nodes=c(nodes, 40 | readRDS(paste(path,i,".rds",sep=""))) 41 | 42 | } 43 | 44 | ###saving the assembly 45 | 46 | saveRDS(nodes,"cut_001eval/recode_nodes_all.rds") 47 | 48 | rm(edges) 49 | rm(nodes) 50 | 51 | ############################################################### 52 | ############################################################### 53 | 54 | ###Part2: components 55 | 56 | ####We are going to selected connected components with at least 5 nodes 57 | 58 | library(igraph) 59 | 60 | ################################################### 61 | ####Volvemos localmente a ver que sale de todo esto 62 | 63 | pairs=readRDS("cut_001eval/recode_edges_all.rds") 64 | 65 | net=graph_from_data_frame(d=pairs[,c("Query","Target")],directed=F) 66 | E(net)$weight=as.numeric(pairs[,"Eval"]) 67 | E(net)$score=as.numeric(pairs[,"score"]) 68 | net=igraph::simplify(net,remove.loops = T,remove.multiple = T , edge.attr.comb = c(weight="min",score="max","ignore")) 69 | Isolated = which(igraph::degree(net)==0) 70 | length(Isolated) 71 | net = delete.vertices(net, Isolated) 72 | 73 | ##saving assmbled edges after removing dups 74 | 75 | saveRDS(cbind(get.edgelist(net,names = T), 76 | E(net)$weight, 77 | E(net)$score),"cut_001eval/recode_edges_all_FILTER.rds") 78 | 79 | ###Components 80 | 81 | subnet=components(net) 82 | 83 | nodes_sel=subnet$membership[subnet$membership%in%names(table(subnet$membership)[table(subnet$membership)>=5])] 84 | 85 | saveRDS(nodes_sel,"cut_001eval/recode_nodes_all_FILTER_components5.rds") 86 | saveRDS(pairs[pairs[,1]%in%names(nodes_sel) & 87 | pairs[,2]%in%names(nodes_sel) ,],"cut_001eval/recode_edges_all_FILTER_components5.rds") 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_8.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ####Script8: PFAM annotation 5 | 6 | ###Selecting pfam mapped to our sequences from the database 7 | 8 | genes=readRDS("cut_001eval/recode_nodes_all_FILTER_components5.rds") 9 | genes=names(genes) 10 | genes=unlist(strsplit(genes,"_"))[c(T,F)] 11 | length(genes) 12 | 13 | raw_data_path <- "Pfam-A.regions.uniprot.tsv.gz" 14 | raw_data_nrow <- length(count.fields(raw_data_path)) 15 | 16 | ###open connexion 17 | con = file(raw_data_path, "r") 18 | ###Getting ready for filtering 19 | filtered_data=read.delim(con, nrows=raw_data_nrow-2.72e+08) 20 | filtered_data=filtered_data[filtered_data[,1]%in%genes ,c("uniprot_acc","pfamA_acc","seq_start","seq_end")] 21 | rownames(filtered_data)=NULL 22 | gc() 23 | 24 | for (i in 1:136){ 25 | 26 | temp=read.delim(con, nrows=2000000,header=F) 27 | temp=temp[temp[,1]%in%genes ,c(1,5,6,7)] 28 | 29 | colnames(temp)= colnames(filtered_data) 30 | 31 | filtered_data=rbind(filtered_data, 32 | temp) 33 | gc() 34 | print(i) 35 | 36 | } 37 | close(con) 38 | 39 | saveRDS(filtered_data, 40 | "cut_eval001/filtered_pfam_cut001.rds") 41 | 42 | ########################################################################################## 43 | 44 | ####Splitting data to run annotation in paralel 45 | 46 | ###All positions 47 | nodes=readRDS("cut_001eval/recode_nodes_all.rds") 48 | ###All components 49 | modules=readRDS("cut_001eval/recode_nodes_all_FILTER_components5.rds") 50 | modules=cbind(modules, 51 | unlist(strsplit(names(modules),"_"))[c(T,F)]) 52 | modules=cbind(modules,"","") 53 | colnames(modules)=c("subnet","uniprot","from","to") 54 | ###pfam domains 55 | pfam=as.matrix(readRDS("cut_001eval/filtered_pfam_cut001.rds")) 56 | pfam=pfam[pfam[,"uniprot_acc"]%in%modules[,"uniprot"],] 57 | 58 | ####coordinates to cut in 1000 files 59 | coor=cbind(seq(from=1, to=3725915, by=3726), 60 | c(seq(from=3726, to=3725915, by=3726),3725915)) 61 | 62 | path_node="cut_001eval/pfam_anot/recode_nodes_" 63 | path_module="cut_001eval/pfam_anot/modules_" 64 | path_pfam="cut_001eval/pfam_anot/pfam_" 65 | 66 | for (i in 1:nrow(coor)){ 67 | 68 | temp_module=modules[coor[i,1]:coor[i,2],] 69 | saveRDS(nodes[nodes%in%rownames(temp_module)],paste(path_node,i,sep="")) 70 | saveRDS(pfam[pfam[,"uniprot_acc"]%in%temp_module[,"uniprot"],],paste(path_pfam,i,sep="")) 71 | saveRDS(temp_module,paste(path_module,i,sep="")) 72 | } 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /afdb-regions-network-R/Rscript_9.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #####SCRIPT9 : annotation of regions using pfam 4 | 5 | ####Lines to annotate a region using pfam domains,, 75% of the domain must be included in the region to be considered 6 | 7 | ###Ment to run inside a loop 8 | 9 | 10 | i <- as.numeric(commandArgs(trailingOnly = TRUE)) 11 | 12 | 13 | path_node="cut_001eval/pfam_anot/recode_nodes_" 14 | path_module="cut_001eval/pfam_anot/modules_" 15 | path_pfam="cut_001eval/pfam_anot/pfam_" 16 | 17 | nodes=readRDS(paste(path_node,i,sep="")) 18 | modules=readRDS(paste(path_module,i,sep="")) 19 | pfam=readRDS(paste(path_pfam,i,sep="")) 20 | 21 | for (j in 1:nrow(modules)){ 22 | 23 | temp=names(nodes)[nodes==rownames(modules)[j]] 24 | modules[j,"from"]=min(as.numeric(unlist(strsplit(temp,"_"))[c(F,T,F)])) 25 | modules[j,"to"]=max(as.numeric(unlist(strsplit(temp,"_"))[c(F,F,T)])) 26 | 27 | } 28 | 29 | modules=cbind(modules,"","") 30 | colnames(modules)=c("subnet","uniprot","start","end","pfam_names","pfam_counts") 31 | 32 | ###Ahora anotacion de pfams 33 | 34 | for (j in c(1:nrow(modules))[modules[,"uniprot"]%in%pfam[,"uniprot_acc"]]){ 35 | 36 | criteria=pfam[,"uniprot_acc"]%in%modules[j,"uniprot"] & ( 37 | (as.numeric(pfam[,"seq_start"])>=as.numeric( modules[j,"start"]) & 38 | as.numeric(pfam[,"seq_end"])<=as.numeric( modules[j,"end"])) | 39 | (as.numeric(pfam[,"seq_start"])<=as.numeric( modules[j,"start"]) & 40 | as.numeric(pfam[,"seq_end"])>=as.numeric( modules[j,"start"])) | 41 | (as.numeric(pfam[,"seq_start"])<=as.numeric( modules[j,"end"]) & 42 | as.numeric(pfam[,"seq_end"])>=as.numeric( modules[j,"end"]))) 43 | temp=unique(pfam[criteria,"pfamA_acc"]) 44 | modules[j,"pfam_names"]=paste(temp,collapse=";") 45 | modules[j,"pfam_counts"]=length(temp) 46 | 47 | } 48 | 49 | ####Ahora vamos a buscar el porcentaje 50 | 51 | modules=cbind(modules,"") 52 | colnames(modules)[ncol(modules)]="pfam_chunk_rel" 53 | 54 | for (j in c(1:nrow(modules))[modules[,"pfam_counts"]=="1"]){ 55 | 56 | temp=as.numeric(pfam[pfam[,"uniprot_acc"]%in%modules[j,"uniprot"] & ( 57 | (as.numeric(pfam[,"seq_start"])>=as.numeric( modules[j,"start"]) & 58 | as.numeric(pfam[,"seq_end"])<=as.numeric( modules[j,"end"])) | 59 | (as.numeric(pfam[,"seq_start"])<=as.numeric( modules[j,"start"]) & 60 | as.numeric(pfam[,"seq_end"])>=as.numeric( modules[j,"start"])) | 61 | (as.numeric(pfam[,"seq_start"])<=as.numeric( modules[j,"end"]) & 62 | as.numeric(pfam[,"seq_end"])>=as.numeric( modules[j,"end"]))) ,c("seq_start","seq_end")]) 63 | 64 | A=c(temp[1]:temp[2]) 65 | B=c(as.numeric(modules[j,"start"]):as.numeric(modules[j,"end"])) 66 | 67 | modules[j,"pfam_chunk_rel"]=round(sum(A%in%B)/length(A),3) 68 | 69 | } 70 | 71 | 72 | modules=cbind(modules,"") 73 | colnames(modules)[ncol(modules)]="pfam_all" 74 | 75 | modules[modules[,"pfam_counts"]=="1","pfam_all"]=modules[modules[,"pfam_counts"]=="1","pfam_names"] 76 | 77 | 78 | for (j in c(1:nrow(modules))[modules[,"pfam_counts"]%in%c("2","3","4","5","6","7","8","9")]){ 79 | 80 | temp=cbind(pfam[pfam[,"uniprot_acc"]%in%modules[j,"uniprot"] & ( 81 | (as.numeric(pfam[,"seq_start"])>=as.numeric( modules[j,"start"]) & 82 | as.numeric(pfam[,"seq_end"])<=as.numeric( modules[j,"end"])) | 83 | (as.numeric(pfam[,"seq_start"])<=as.numeric( modules[j,"start"]) & 84 | as.numeric(pfam[,"seq_end"])>=as.numeric( modules[j,"start"])) | 85 | (as.numeric(pfam[,"seq_start"])<=as.numeric( modules[j,"end"]) & 86 | as.numeric(pfam[,"seq_end"])>=as.numeric( modules[j,"end"]))) ,c("pfamA_acc","seq_start","seq_end")],"") 87 | 88 | for (k in 1:nrow(temp)){ 89 | 90 | A=c(as.numeric(temp[k,"seq_start"]):as.numeric(temp[k,"seq_end"])) 91 | B=c(as.numeric(modules[j,"start"]):as.numeric(modules[j,"end"])) 92 | temp[k,4]=round(sum(A%in%B)/length(A),3) 93 | 94 | } 95 | 96 | modules[j,"pfam_chunk_rel"]=paste( temp[,4],collapse=";") 97 | modules[j,"pfam_all"]=paste( temp[,1],collapse=";") 98 | 99 | } 100 | 101 | 102 | ################################################ 103 | ################################################ 104 | ############Long version table (one line per pfam per domain) 105 | 106 | 107 | mod_pfam_long=modules[modules[,"pfam_counts"]=="1",c("subnet", 108 | "uniprot", 109 | "start", 110 | "end", 111 | "pfam_names", 112 | "pfam_counts", 113 | "pfam_chunk_rel")] 114 | mod_pfam_long=cbind(rownames(mod_pfam_long),mod_pfam_long) 115 | colnames(mod_pfam_long)[1]="ID" 116 | 117 | temp_pfam=modules[modules[,"pfam_counts"]%in%c("2","3","4","5","6","7","8","9"),] 118 | 119 | temp=unlist(strsplit(temp_pfam[1,"pfam_all"],";")) 120 | primer=cbind(rep(rownames(temp_pfam)[1],length(temp)), 121 | rep(temp_pfam[1,"subnet"],length(temp)), 122 | rep(temp_pfam[1,"uniprot"],length(temp)), 123 | rep(temp_pfam[1,"start"],length(temp)), 124 | rep(temp_pfam[1,"end"],length(temp)), 125 | temp, 126 | rep(temp_pfam[1,"pfam_counts"],length(temp)), 127 | unlist(strsplit(temp_pfam[1,"pfam_chunk_rel"],";"))) 128 | 129 | for (j in 2:nrow(temp_pfam)){ 130 | 131 | temp=unlist(strsplit(temp_pfam[j,"pfam_all"],";")) 132 | temp1=cbind(rep(rownames(temp_pfam)[j],length(temp)), 133 | rep(temp_pfam[j,"subnet"],length(temp)), 134 | rep(temp_pfam[j,"uniprot"],length(temp)), 135 | rep(temp_pfam[j,"start"],length(temp)), 136 | rep(temp_pfam[j,"end"],length(temp)), 137 | temp, 138 | rep(temp_pfam[j,"pfam_counts"],length(temp)), 139 | unlist(strsplit(temp_pfam[j,"pfam_chunk_rel"],";"))) 140 | 141 | primer=rbind(primer,temp1) 142 | 143 | } 144 | 145 | mod_pfam_long=rbind(mod_pfam_long, 146 | primer) 147 | rownames(mod_pfam_long)=NULL 148 | 149 | ############################################ 150 | ############################################ 151 | ############################################ 152 | ####Saving the files 153 | 154 | path_result="cut_001eval/pfam_anot/result_modules_"###Table with annotation 155 | path_result_long="cut_001eval/pfam_anot/result_long_"###long format 156 | path_result_long_cut="cut_001eval/pfam_anot/result_longCut_"###Long format keeping only annotation 157 | 158 | saveRDS(modules,paste(path_result,i,sep="")) 159 | saveRDS(mod_pfam_long,paste(path_result_long,i,sep="")) 160 | saveRDS(mod_pfam_long[as.numeric(mod_pfam_long[,"pfam_chunk_rel"])>=0.75,],paste(path_result_long_cut,i,sep="")) 161 | 162 | 163 | 164 | ############################################ 165 | ############################################ 166 | #### 167 | ####Assembling all together 168 | 169 | path_result="cut_001eval/pfam_anot/result_modules_" 170 | path_result_long="cut_001eval/pfam_anot/result_long_" 171 | path_result_long_cut="cut_001eval/pfam_anot/result_longCut_" 172 | 173 | ####Primero los resultados 174 | 175 | table1=readRDS(paste(path_result,1,sep="")) 176 | 177 | for (i in 2:1000){ 178 | 179 | table1=rbind(table1, 180 | readRDS(paste(path_result,i,sep=""))) 181 | 182 | } 183 | 184 | saveRDS(table1,"cut_001eval/result_modules_all.rds") 185 | 186 | ######## 187 | 188 | table1=readRDS(paste(path_result_long,1,sep="")) 189 | 190 | for (i in 2:1000){ 191 | 192 | table1=rbind(table1, 193 | readRDS(paste(path_result_long,i,sep=""))) 194 | 195 | } 196 | 197 | saveRDS(table1,"cut_001eval/result_long_all.rds") 198 | 199 | ######## 200 | 201 | table1=readRDS(paste(path_result_long_cut,1,sep="")) 202 | 203 | for (i in 2:1000){ 204 | 205 | table1=rbind(table1, 206 | readRDS(paste(path_result_long_cut,i,sep=""))) 207 | 208 | } 209 | 210 | saveRDS(table1,"cut_001eval/result_longCut_all.rds") 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /commands: -------------------------------------------------------------------------------- 1 | ### Removing fragments 2 | 3 | # removing fragments and alter the centroid 4 | awk 'BEGIN{newclu=""} FNR==NR{f[$2]=1;next} ($1 != rename){newclu="";rename=""} ($1 in f && $2 in f){rename=$1; next} ($1 == rename && !($2 in f) && newclu==""){newclu=$2; print $2"\t"$2; next} ($1 == rename && !($2 in f) && newclu!=""){print newclu"\t"$2; next} !($2 in f){print}' /storage/martin/foldseek_cluster/uniprot_trembl_sprot_fragments.ids /storage/martin/foldseek_cluster/afdb50best_foldseek_clu.tsv > afdb50best_foldseek_clu_nofragments.tsv & 5 | 6 | # tsv2db 7 | foldseek tsv2db afdb50best_foldseek_clu_nofragments.tsv ./databases/afdb50best_foldseek_clu_nofragments --output-dbtype 6 8 | 9 | # w/o frag to tsv file 10 | mmseqs createtsv /storage/martin/foldseek_cluster/afdb /storage/martin/foldseek_cluster/afdb ./databases/afdb50best_foldseek_clu_nofragments ./databases/afdb50best_foldseek_clu_nofragments.tsv 11 | 12 | # count the number w/o frag 13 | wc -l databases/afdb50best_foldseek_clu_nofragments.index # 15315246 14 | 15 | ### Removing singletons 16 | 17 | # count the number of members 18 | awk '{id[$1]+=1; next; } END { for (key in id) print key"\t"id[key]}' afdb50best_foldseek_clu_nofragments.tsv > afdb50best_foldseek_clu_nofragments-repIndex_nMem.tsv 19 | 20 | # count the number of singletones 21 | awk '$2==1 {n+=1;} END {print n}' afdb50best_foldseek_clu_nofragments-repIndex_nMem.tsv # 13012338 22 | 23 | # find the rep Ids of singleotns 24 | awk '$2==1 {print $1}' afdb50best_foldseek_clu_nofragments-repIndex_nMem.tsv > singleton_repIndex 25 | 26 | # remove singletons 27 | awk 'FNR==NR {singletons[$1]=1; next;} !($1 in singletons) {print $0}' singleton_repIndex afdb50best_foldseek_clu_nofragments.tsv > afdb50best_foldseek_clu_nofrag_nosingletons.tsv 28 | 29 | # create nosingleton db 30 | foldseek tsv2db afdb50best_foldseek_clu_nofrag_nosingletons.tsv ./databases/afdb50best_foldseek_clu_nofrag_nosingletons --output-dbtype 6 31 | 32 | # tsv - repId memId 33 | mmseqs createtsv /storage/martin/foldseek_cluster/afdb /storage/martin/foldseek_cluster/afdb ./databases/afdb50best_foldseek_clu_nofrag_nosingletons ./databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv 34 | 35 | ### Create AFDB clusters database 36 | 37 | # pick reps 38 | awk '!($1 in id) {print $1; id[$1]=1; next;}' databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > ./databases/afdb50best_foldseek_clu_nofrag_nosingletons-reps.tsv 39 | 40 | # representative sequences db 41 | foldseek createsubdb databases/afdb50best_foldseek_clu_nofrag_nosingletons-reps.tsv /storage/martin/foldseek_cluster/afdb databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs --id-mode 1 42 | foldseek createsubdb databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs.index /storage/martin/foldseek_cluster/afdb_ss databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs_ss 43 | foldseek createsubdb databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs.index /storage/martin/foldseek_cluster/afdb_ca databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs_ca 44 | 45 | ### Analyze AFDB clusters 46 | 47 | # count how many clusters left 48 | wc -l ./databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs.index # 2302908 49 | 50 | # compute LCA 51 | mmseqs lca /storage/martin/foldseek_cluster/afdb50best databases/afdb50best_foldseek_clu_nofrag_nosingletons lca/afdb50best_foldseek_nofrag_nosingletons_lca --tax-lineage 1 52 | 53 | # make lca report 54 | mmseqs taxonomyreport /storage/martin/foldseek_cluster/afdb50best lca/afdb50best_foldseek_nofrag_nosingletons_lca lca/afdb50best_foldseek_nofrag_nosingletons_lca.report 55 | 56 | # create lca tsv 57 | mmseqs createtsv /storage/martin/foldseek_cluster/afdb lca/afdb50best_foldseek_nofrag_nosingletons_lca ./lca/afdb50best_foldseek_clu_nofragments_nosingleton_lca.tsv 58 | 59 | # print the number of clusters conserved to high superkingdoms 60 | awk -F "\t" 'BEGIN {interest["Bacteria"]=1; interest["Archaea"]=1; interest["cellular organisms"]=1; interest["Eukaryota"]=1;} {gsub(/^\s*/, "", $6)} $6 in interest {print $6"\t"$3}' lca/afdb50best_foldseek_nofrag_nosingletons_lca.report 61 | # OUTPUT is 62 | # cellular organisms 529373 63 | # Bacteria 370762 64 | # Eukaryota 311226 65 | # Archaea 11336 66 | 67 | # revise Fig 3 A 68 | 69 | # align lddt, tm-score values 70 | 71 | 72 | ### Summary file 73 | 74 | # number of members 75 | awk '{id[$1]+=1;} END {for (key in id) print key"\t"id[key]}' ./databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > ./summary/repId_nMem.tsv & 76 | 77 | # length 78 | awk 'FNR==NR {id[$1]=$2; next;} $1 in id {print id[$1]"\t"$3-2}' /storage/martin/foldseek_cluster/afdb.lookup /storage/martin/foldseek_cluster/afdb.index > ./summary/entryId_length.tsv & 79 | 80 | # avg length 81 | wk 'FNR==NR {len[$1]=$2; next;} {slen[$1] += len[$2]; n[$1]+=1;} END {for (key in slen) print key"\t"slen[key]/n[key]} ' ./summary/entryId_length.tsv ./databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > ./summary/repId_avgLen.tsv & 82 | 83 | # avg plddt 84 | awk 'FNR==NR {plddt[$1]=$2; next;} {splddt[$1] += plddt[$2]; n[$1]+=1;} END {for (key in splddt) print key"\t"splddt[key]/n[key]} ' ./plddt/entryId_plddt.tsv ./databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > ./summary/repId_avgPlddt.tsv & 85 | 86 | # + repLen 87 | awk 'FNR==NR {nMem[$1]=$0; next;} $1 in nMem {print nMem[$1]"\t"$2}' ./summary/repId_nMem.tsv ./summary/entryId_length.tsv > ./summary/repId_nMem_repLen.tsv & 88 | # + avgLen 89 | awk 'FNR==NR {prev[$1]=$0; next;} $1 in prev {print prev[$1]"\t"$2}' ./summary/repId_nMem_repLen.tsv ./summary/repId_avgLen.tsv > ./summary/repId_nMem_repLen_avgLen.tsv & 90 | # + repPlddt 91 | awk 'FNR==NR {prev[$1]=$0; next;} $1 in prev {print prev[$1]"\t"$2}' ./summary/repId_nMem_repLen_avgLen.tsv ./plddt/entryId_plddt.tsv > ./summary/repId_nMem_repLen_avgLen_repPlddt.tsv & 92 | # + avgPlddt 93 | awk 'FNR==NR {prev[$1]=$0; next;} $1 in prev {print prev[$1]"\t"$2}' ./summary/repId_nMem_repLen_avgLen_repPlddt.tsv ./summary/repId_avgPlddt.tsv > ./summary/repId_nMem_repLen_avgLen_repPlddt_avgPlddt.tsv & 94 | # + taxId, lineage 95 | awk -F "\t" 'FNR==NR {prev[$1]=$0; next;} $1 in prev {print prev[$1]"\t"$2"\t"$5}' ./summary/repId_nMem_repLen_avgLen_repPlddt_avgPlddt.tsv lca/afdb50best_foldseek_clu_nofragments_nosingleton_lca.tsv > ./summary/repId_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv 96 | -------------------------------------------------------------------------------- /commands_darkening: -------------------------------------------------------------------------------- 1 | ### Darkening 2 | 3 | # mmseqs pfam search 4 | srun -p compute -w super002 -c 16 -t 2-0 mmseqs search ./databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs ../../cluster_analysis_old/pfam_pdb/pfam darkening/mmseqs_pfam/mmseqs_pfam tmp -e 0.1 --threads 32 -s 7.5 --max-seqs 100000 5 | 6 | # convert mmseqs pfam search result to alns 7 | mmseqs convertalis ./databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs ../../cluster_analysis_old/pfam_pdb/pfam ./darkening/mmseqs_pfam/mmseqs_pfam ./darkening/aln_mmseqs_pfam 8 | 9 | # fodlseek pdb search 10 | srun -p compute -w super001 -c 16 -t 2-0 foldseek search ./databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs ../../cluster_analysis_old/pfam_pdb/pdb ./darkening/foldseek_pdb/foldseek_pdb tmp -e 0.1 --threads 32 11 | 12 | # conver foldseek pdb search result to alns 13 | foldseek convertalis ./databases/afdb50best_foldseek_clu_nofrag_nosingletons_repseqs ../../cluster_analysis_old/pfam_pdb/pdb ./darkening/foldseek_pdb/foldseek_pdb ./darkening/aln_foldseek_pdb 14 | 15 | ## uniprot&sprot pfam, tigrfam search 16 | 17 | # sprot pfam 18 | awk 'FNR==NR {id[$1]=$2; next;} $2 in id {print $1"\t"$2"\t"id[$2]} ' ../replicate_find_dark_cluster/web_hit/accession_pfam_sprot_long_semi.tsv databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > ./darkening/ftp_pfam_tigrfam/hit_pfam_sprot.tsv & 19 | # uniprot pfam 20 | awk 'FNR==NR {id[$1]=$2; next;} $2 in id {print $1"\t"$2"\t"id[$2]} ' ../replicate_find_dark_cluster/web_hit/accession_pfam_uniprot_long_semi.tsv databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > ./darkening/ftp_pfam_tigrfam/hit_pfam_uniprot.tsv & 21 | # sprot tigrfam 22 | awk 'FNR==NR {id[$1]=$2; next;} $2 in id {print $1"\t"$2"\t"id[$2]} ' ../replicate_find_dark_cluster/web_hit/accession_tigrfam_sprot_long_semi.tsv databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > ./darkening/ftp_pfam_tigrfam/hit_tigrfam_sprot.tsv & 23 | # sprot pfam 24 | awk 'FNR==NR {id[$1]=$2; next;} $2 in id {print $1"\t"$2"\t"id[$2]} ' ../replicate_find_dark_cluster/web_hit/accession_tigrfam_uniprot_long_semi.tsv databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > ./darkening/ftp_pfam_tigrfam/hit_tigrfam_uniprot.tsv & 25 | 26 | # integrate all ftp hits 27 | awk '{id[$1]=1} END { for (key in id) print key}' ./darkening/ftp_pfam_tigrfam/hit_pfam_sprot.tsv ./darkening/ftp_pfam_tigrfam/hit_pfam_uniprot.tsv ./darkening/ftp_pfam_tigrfam/hit_tigrfam_sprot.tsv ./darkening/ftp_pfam_tigrfam/hit_tigrfam_uniprot.tsv > ./darkening/all_ftp_pfam_tigrfam 28 | 29 | # find reps w/o pdb hit by foldseek 30 | awk 'FNR==NR {id[$1]=1; next;} !($1 in id) {print $0}' ./darkening/aln_foldseek_pdb ./databases/afdb50best_foldseek_clu_nofrag_nosingletons-reps.tsv > ./darkening/without_foldseek-pdb 31 | # residues 32 | wc -l ./darkening/without_foldseek-pdb # 1135118 33 | 34 | # find reps w/o ( * ) & pfam hit by mmseqs 35 | awk 'FNR==NR {id[$1]=1; next;} !($1 in id) {print $0}' ./darkening/aln_mmseqs_pfam ./darkening/without_foldseek-pdb > ./darkening/without_foldseek-pdb_mmseqs-pfam 36 | # residues 37 | wc -l ./darkening/without_foldseek-pdb_mmseqs-pfam # 883788 38 | 39 | # find reps w/o ( * ) & pfam and tigrfam by ftp data 40 | awk 'FNR==NR {id[$1]=1; next;} !($1 in id) {print $0}' ./darkening/all_ftp_pfam_tigrfam ./darkening/without_foldseek-pdb_mmseqs-pfam > ./darkening/without_foldseek-pdb_mmseqs-pfam_ftp-pfam-tigrfram 41 | # residues 42 | wc -l ./darkening/without_foldseek-pdb_mmseqs-pfam_ftp-pfam-tigrfram # 711705 43 | 44 | ### Dark clusters analysis 45 | 46 | # pick dark clusters representatives and members 47 | awk 'FNR==NR {id[$1]=1; next;} $1 in id {print $0}' darkening/without_foldseek-pdb_mmseqs-pfam_ftp-pfam-tigrfram databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > darkening/dark-repId_memId.tsv 48 | 49 | # dark clusters summary file 50 | awk 'FNR==NR {id[$1]=1; next;} $1 in id {print $0}' darkening/without_foldseek-pdb_mmseqs-pfam_ftp-pfam-tigrfram summary/repId_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv > darkening/dark-repId_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv 51 | 52 | # pick high avgPlddt clusters 53 | awk '$6 > 90 {print $0}' darkening/dark-repId_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv > darkening/highAvgPlddt-dark-repId_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv 54 | 55 | # pick highest pLDDT member in each cluster 56 | awk 'FNR==NR {plddt[$1]=$2; next;} !($1 in id) {id[$1]=$2; highest[$1]=plddt[$2]; next;} ($1 in id) && plddt[$2]>highest[$1] {id[$1]=$2; highest[$1]=plddt[$2];} END {for (key in id) print key"\t"id[key]"\t"highest[key]}' plddt/entryId_plddt.tsv ./darkening/dark-repId_memId.tsv > darkening/dark-repId_highestId_plddt.tsv & 57 | 58 | # pick the high plddt members from the clusters >90% avgPlddt 59 | awk 'FNR==NR && $6 > 90 {id[$1]=1; next;} $1 in id {print "wget https://alphafold.ebi.ac.uk/files/"$2}' ./darkening/dark-repId_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv darkening/dark-repId_highestId_plddt.tsv | sed -E 's/cif/pdb/' > darkening/enzyme_analysis_pdb_download.sh 60 | 61 | # pick the highets plddt members from all clusters 62 | awk '{print "wget https://alphafold.ebi.ac.uk/files/"$2}' darkening/dark-repId_highestId_plddt.tsv | sed -E 's/cif/pdb/' > darkening/all_dark_clusters_pdb_download.sh -------------------------------------------------------------------------------- /commands_distribution: -------------------------------------------------------------------------------- 1 | ### Let's generate Fig 1 D - the distribution of dark clusters 2 | 3 | # repId_isDark_nMem 4 | awk 'FNR==NR {dark[$1]=1; next;} {d=0;} $1 in dark {d=1} {print $1"\t"d"\t"$2}' darkening/without_foldseek-pdb_mmseqs-pfam_ftp-pfam-tigrfram summary/repId_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv > ./summary/repId_isDark_nMem.tsv 5 | 6 | # find AFDB removed, dark, bright numbers 7 | awk 'FNR==NR && $2==1 {dark[$1]=1; next;} FNR==NR && $2==0 {bright[$1]=1; next;} $1 in dark {nDark+=1; next;} $1 in bright {nBright+=1; next;} {nRemoved+=1; next;} END {print nRemoved"\t"nDark"\t"nBright}' summary/repId_isDark_nMem.tsv share_db/all-repId_memId_cluFlag-1234-2.tsv > summary/AFDB-removed_dark_bright.tsv 8 | 9 | # find AFDB clusters dark and bright numbers 10 | awk '$2==1 {nDark += 1; next;} $2==0 {nBright += 1; next;} END {print "0\t"nDark"\t"nBright}' summary/repId_isDark_nMem.tsv > summary/AFDB-Clusters-removed_dark-bright.tsv 11 | 12 | # Draw dark and bright clusters' distribution 13 | # execution: dark_distribution.ipynb -------------------------------------------------------------------------------- /commands_purity: -------------------------------------------------------------------------------- 1 | ### lddt, tm-score, pfam-consistency per clusters 2 | 3 | # align structurally members to representative 4 | foldseek structurealign /storage/martin/foldseek_cluster/afdb50best /storage/martin/foldseek_cluster/afdb50best ./databases/afdb50best_foldseek_clu_nofrag_nosingletons purity_analysis/database/aln_db -a -e INF --threads 64 5 | 6 | # convert align output to tsv 7 | foldseek convertalis /storage/martin/foldseek_cluster/afdb50best /storage/martin/foldseek_cluster/afdb50best purity_analysis/database/aln_db purity_analysis/aln-query_target_fident_alnlen_mismatch_gapopen_qstart_qend_tstart_tend_evalue_bits_lddt_alntmscore.tsv --format-output query,target,fident,alnlen,mismatch,gapopen,qstart,qend,tstart,tend,evalue,bits,lddt,alntmscore --threads 128 8 | 9 | # lddt 10 | awk '{ if($(NF-1) != "-NAN"){ sum[$1]+=$(NF-1); cnt[$1]++; } }END{for(key in sum){print key"\t"sum[key]"\t"cnt[key]"\t"sum[key]/cnt[key]}}' purity_analysis/aln-query_target_fident_alnlen_mismatch_gapopen_qstart_qend_tstart_tend_evalue_bits_lddt_alntmscore.tsv > purity_analysis/lddt-repId_sumLddt_nMem_avgLddt.tsv 11 | 12 | # tm-score 13 | awk '{ if($NF != "-NAN"){ sum[$1]+=$NF; cnt[$1]++; } }END{for(key in sum){print key"\t"sum[key]"\t"cnt[key]"\t"sum[key]/cnt[key]}}' purity_analysis/aln-query_target_fident_alnlen_mismatch_gapopen_qstart_qend_tstart_tend_evalue_bits_lddt_alntmscore.tsv > purity_analysis/tmScore-repId_sumTmScore_nMem_avgTmScore.tsv -------------------------------------------------------------------------------- /commands_sapiens: -------------------------------------------------------------------------------- 1 | ### Homo Sapiens clusters analysis 2 | 3 | # pick homo sapiens (9606) proteins 4 | mmseqs filtertaxseqdb /storage/martin/foldseek_cluster/afdb ./homo_sapiens/afdb_v3_human --taxon-list 9606 --threads 64 5 | 6 | # extract homo sapiens containing clusters 7 | awk 'FNR==1 {fn+=1;} fn==1 {id[$2]=1; next;} fn==2 && $2 in id {rep[$1]=1; next;} fn==3 && $1 in rep {print $0}' ./homo_sapiens/afdb_v3_human.index afdb50best_foldseek_clu_nofrag_nosingletons.tsv afdb50best_foldseek_clu_nofrag_nosingletons.tsv > homo_sapiens/afdb50best_foldseek_clu_nofrag_nosingletons_containing_human_index.tsv 8 | awk 'FNR==1 {fn+=1;} fn==1 {id[$1]=1; next;} fn==2 && $2 in id {rep[$1]=1; next;} fn==3 && $1 in rep {print $0}' ./homo_sapiens/afdb_v3_human.index afdb50best_foldseek_clu_nofrag_nosingletons.tsv afdb50best_foldseek_clu_nofrag_nosingletons.tsv > homo_sapiens/afdb50best_foldseek_clu_nofrag_nosingletons_containing_human_index.tsv 9 | 10 | # create homo sapiens clusters 11 | mmseqs tsv2db homo_sapiens/afdb50best_foldseek_clu_nofrag_nosingletons_containing_human_index.tsv homo_sapiens/afdb50best_foldseek_clu_nofrag_nosingletons_containing_human 12 | 13 | # repId-memId tsv file 14 | mmseqs createtsv /storage/martin/foldseek_cluster/afdb /storage/martin/foldseek_cluster/afdb homo_sapiens/afdb50best_foldseek_clu_nofrag_nosingletons_containing_human homo_sapiens/afdb50best_foldseek_clu_nofrag_nosingletons_containing_human.tsv 15 | 16 | # LCA 17 | mmseqs createsubdb ./homo_sapiens/afdb50best_foldseek_clu_nofrag_nosingletons_containing_human.index ./lca/afdb50best_foldseek_nofrag_nosingletons_lca ./homo_sapiens/human_containing_lca 18 | 19 | # taxonomyreport 20 | mmseqs taxonomyreport /storage/martin/foldseek_cluster/afdb50best ./homo_sapiens/human_containing_lca ./homo_sapiens/human_containing_lca.report 21 | 22 | ### GO data set up 23 | awk '{gsub(";", "")} $1=="AC" { AC=$2} $1=="DR" && $2=="GO" {print AC"\t"$3} ' ../../cluster_analysis_old/pfam_pdb/uniprot_trembl.dat > ./go/trembl_accession_GO.tsv 24 | awk ' !($1 in go) {go[$1] = $2} $1 in go {go[$1]=go[$1]";"$2} END { for (key in go) print key"\t"go[key]}' ./go/trembl_accession_GO.tsv > ./go/trembl_accession_GO_semicolon.tsv 25 | awk '{gsub(";", "")} $1=="AC" { AC=$2} $1=="DR" && $2=="GO" {print AC"\t"$3} ' ../../cluster_analysis_old/pfam_pdb/uniprot_sprot.dat > ./go/sprot_accession_GO.tsv & 26 | awk 'FNR==NR {print $0; id[$1$2]=1; next} !($1$2 in id) {print $0}' go/sprot_accession_GO.tsv go/trembl_accession_GO.tsv > go/union_accession_GO.tsv 27 | 28 | # find homo sapiens AFDB id 29 | awk 'FNR==NR {id[$1]=1; next;} $1 in id {print $2}' homo_sapiens/afdb_v3_human.index homo_sapiens/afdb_v3_human.lookup > homo_sapiens/afdb_v3_human.ids 30 | 31 | # map GO to human proteins 32 | awk 'FNR==NR {id[$1]=1; next;} "AF-"$1"-F1-model_v3.cif" in id {print "AF-"$1"-F1-model_v3.cif\t"$2}' homo_sapiens/afdb_v3_human.ids go/union_accession_GO.tsv > homo_sapiens/human-sapId_GO.tsv 33 | 34 | ### pick the higher plddt sapiens protein in each cluster 35 | # map plddt to homo sapiens AFDB proteins 36 | awk 'FNR==NR {id[$1]=1; next;} $1 in id {print }' homo_sapiens/afdb_v3_human.ids plddt/entryId_plddt.tsv > homo_sapiens/human-sapId_plddt.tsv 37 | 38 | # pick the highest plddt sapiens protein 39 | awk 'FNR==NR {plddt[$1]=$2; next;} !($1 in id) {id[$1]=$2; highest[$1]=plddt[$2]; next;} ($1 in id) && plddt[$2]>highest[$1] {id[$1]=$2; highest[$1]=plddt[$2];} END {for (key in id) print key"\t"id[key]"\t"highest[key]}' homo_sapiens/human-sapId_plddt.tsv homo_sapiens/afdb50best_foldseek_clu_nofrag_nosingletons_containing_human.tsv > homo_sapiens/human-repId_highestSapId_plddt.tsv & 40 | 41 | # map plddt and GO to highest Plddt sapiens protein 42 | awk 'FNR==NR {id[$2]=$0; next;} $1 in id {print id[$1]"\t"$2}' homo_sapiens/human-repId_highestSapId_plddt.tsv homo_sapiens/human-sapId_GO.tsv > homo_sapiens/human-repId_highestSapId_sapPlddt_GO.tsv 43 | 44 | # map lca rank info 45 | awk -F "\t" 'FNR==NR {rep[$1]=$2"\t"$4; next;} $1 in rep {print $1"\t"rep[$1]"\t"$2"\t"$3"\t"$4}' lca/afdb50best_foldseek_clu_nofragments_nosingleton_lca.tsv homo_sapiens/human-repId_highestSapId_sapPlddt_GO.tsv > homo_sapiens/clu-sap-repId_lcaTaxId_lcaRankName_sapId_sapPlddt_sapGO.tsv 46 | 47 | # annotate taxonomy to spaiens cluster members 48 | awk -F "\t" 'FNR==NR {mem[$2]=$1; next} $2 in mem {print mem[$2]"\t"$2"\t"$3"\t"$4"\t"$5"\t"$6}' homo_sapiens/afdb50best_foldseek_clu_nofrag_nosingletons_containing_human.tsv ./taxonomy/afdb50best_clu_lineage.tsv > homo_sapiens/repId_memId_taxId_rank_rankName_lieage.tsv 49 | 50 | # find out immune related cluster with python (below) 51 | # by the file - find_immune_related_human_cluster.ipynb 52 | # the ipynb file returns the output file - homo_sapiens/human-immune-go-repId_sapId_sapGO_lca_sapGOFunc.tsv 53 | 54 | # find human immunity clusters that has Bacteria or Archaea in it 55 | grep cellular homo_sapiens/human-immune-go-repId_sapId_sapGO_lca_sapGOFunc.tsv > homo_sapiens/across-kingdom-human-immune-go-repId_sapId_sapGO_lca_sapGOFunc.tsv 56 | 57 | # find the examples in Fig 3 58 | # A 59 | 60 | # find the D2N2J3 cluster from nucleous (GO:0005634) annotated clusters 61 | grep GO:0005634 homo_sapiens/clu-sap-repId_lcaTaxId_lcaRankName_sapId_sapPlddt_sapGO.tsv 62 | # output: 63 | # ... 64 | # AF-D2N2J3-F1-model_v3.cif 131567 cellular organisms AF-A0A2R8Y619-F1-model_v3.cif 84.45 GO:0005634 65 | # ... 66 | 67 | # find the Bacteria protein (A0A1G5ASE0) in the D2N2J3 cluster 68 | grep AF-D2N2J3 homo_sapiens/repId_memId_taxId_rank_rankName_lieage.tsv | grep Bacteria 69 | # output: 70 | # ... 71 | # AF-D2N2J3-F1-model_v3.cif AF-A0A1G5ASE0-F1-model_v3.cif 582692 species Paenibacillus polysaccharolyticus -_cellular organisms;d_Bacteria;-_Terrabacteria group;p_Firmicutes;c_Bacilli;o_Bacillales;f_Paenibacillaceae;g_Paenibacillus;s_Paenibacillus polysaccharolyticus 72 | # ... 73 | 74 | # B 75 | 76 | # find the B4DKH6 cluster from the immune related GO annotated clusters 77 | grep B4DKH6 homo_sapiens/across-kingdom-human-immune-go-repId_sapId_sapGO_lca_sapGOFunc.tsv 78 | # output: 79 | # ... 80 | # AF-A0A401S3L8-F1-model_v3.cif AF-B4DKH6-F1-model_v3.cif GO:0006955 cellular organisms immune response 81 | # ... 82 | 83 | # find the Bacteria protein (A0A2D5ZNG0) in the D2N2J3 cluster 84 | grep A0A401S3L8 homo_sapiens/repId_memId_taxId_rank_rankName_lieage.tsv | grep Bacteria 85 | # output: 86 | # ... 87 | # AF-A0A401S3L8-F1-model_v3.cif AF-A0A2D5ZNG0-F1-model_v3.cif 2026742 species Gemmatimonadetes bacterium -_cellular organisms;d_Bacteria;-_FCB group;p_Gemmatimonadetes;-_unclassified Gemmatimonadetes;s_Gemmatimonadetes bacterium 88 | # ... 89 | 90 | # C 91 | 92 | # find the O14862 cluster from the immune related GO annotated clusters 93 | grep O14862 homo_sapiens/across-kingdom-human-immune-go-repId_sapId_sapGO_lca_sapGOFunc.tsv 94 | # output: 95 | # ... 96 | # AF-A0A286S9Y4-F1-model_v3.cif AF-O14862-F1-model_v3.cif GO:0002218 cellular organisms activation of innate immune response 97 | # ... 98 | 99 | # find the Bacteria protein (A0A1C5UEQ5) in the A0A286S9Y4 cluster 100 | grep A0A286S9Y4 homo_sapiens/repId_memId_taxId_rank_rankName_lieage.tsv | grep Bacteria 101 | # output: 102 | # ... 103 | # AF-A0A286S9Y4-F1-model_v3.cif AF-A0A1C5UEQ5-F1-model_v3.cif 59620 species uncultured Clostridium sp. -_cellular organisms;d_Bacteria;-_Terrabacteria group;p_Firmicutes;c_Clostridia;o_Eubacteriales;f_Clostridiaceae;g_Clostridium;-_environmental samples;s_uncultured Clostridium sp. 104 | # ... 105 | 106 | -------------------------------------------------------------------------------- /commands_share_db: -------------------------------------------------------------------------------- 1 | ### Generate DB for sharing 2 | 3 | # Foldseek cluster 4 | mmseqs createtsv /storage/martin/foldseek_cluster/afdb /storage/martin/foldseek_cluster/afdb /storage/martin/foldseek_cluster/afdb50best_foldseek_clu afdb50best_foldseek_clu.tsv 5 | 6 | # Flag 2 - AFDB clusters 7 | awk '{print $1"\t"$2"\t2"}' databases/afdb50best_foldseek_clu_nofrag_nosingletons.tsv > share_db/all-repId_memId_cluFlag-2.tsv 8 | 9 | # Flag 4 - add singletons 10 | awk 'FNR==NR {id[$2]=1; print $0; next;} !($2 in id) {print $1"\t"$2"\t4"}' share_db/all-repId_memId_cluFlag-2.tsv databases/afdb50best_foldseek_clu_nofragments.tsv > share_db/all-repId_memId_cluFlag-24.tsv 11 | 12 | # Find fragments repId-memId (repId should be modified) 13 | awk 'FNR==NR {rep[$2]=$1; next;} !($2 in rep) {print $0}' databases/afdb50best_foldseek_clu_nofragments.tsv afdb50best_foldseek_clu.tsv > ./share_db/fragments-removed_foldseekRepId_memId-2 & 14 | 15 | # find other protein if there is any other member in the AFDB clusters 16 | awk 'FNR==NR {mem2rep[$2]=$1; rep2other[$1]="N/A"; next;} $1 in rep2other && !($2 in mem2rep) {rep2other[$1]=$2;} END {for (key in mem2rep) print mem2rep[key]"\t"key"\t"rep2other[mem2rep[key]]}' ./share_db/fragments-removed_foldseekRepId_memId-2 afdb50best_foldseek_clu.tsv > ./share_db/fragments-other-member_repId_memId_otherId-2 & 17 | 18 | # get the altered rep iD. If there is other Id, get the repId from the other Id. If not, the fragment's repId remains the same. 19 | awk 'FNR==NR {mem2rep[$2]=$1; next;} $3=="N/A" {print $1"\t"$2"\t"$3"\t"$1; next;} $3!="N/A" {print $1"\t"$2"\t"$3"\t"mem2rep[$3]} ' ./databases/afdb50best_foldseek_clu_nofragments.tsv ./share_db/fragments-other-member_repId_memId_otherId-2 > ./share_db/fragments-other-member_repId_memId_otherId_alteredRepId-2 & 20 | 21 | # Flag 3 - add fragments 22 | awk 'FNR==NR {id[$2]=1; print $0; next;} !($2 in id) {print $4"\t"$2"\t3"}' share_db/all-repId_memId_cluFlag-24.tsv ./share_db/fragments-other-member_repId_memId_otherId_alteredRepId-2 > share_db/all-repId_memId_cluFlag-234-2.tsv & 23 | 24 | # AFDB50 25 | mmseqs createtsv /storage/martin/foldseek_cluster/afdb /storage/martin/foldseek_cluster/afdb /storage/martin/foldseek_cluster/afdb50best_clu ./afdb50best_clu_repId_memId.tsv 26 | 27 | # Flag 1 - add AFDB50 28 | awk 'FNR==NR {mem2rep[$2]=$1; print $0; next;} !($2 in mem2rep) {print mem2rep[$1]"\t"$2"\t1"}' share_db/all-repId_memId_cluFlag-234-2.tsv afdb50best_clu_repId_memId.tsv | sort > share_db/all-repId_memId_cluFlag-1234-2.tsv & 29 | 30 | # create entry taxonomy 31 | foldseek addtaxonomy /storage/martin/foldseek_cluster/afdb /storage/martin/foldseek_cluster/afdb50best_clu ./taxonomy/afdb50best_clu_lineage --tax-lineage 1 && foldseek createtsv /storage/martin/foldseek_cluster/afdb /storage/martin/foldseek_cluster/afdb ./taxonomy/afdb50best_clu_lineage ./taxonomy/afdb50best_clu_lineage.tsv 32 | 33 | # a file for the website 34 | awk 'FNR==NR {mem2tax[$2]=$3; next;} {print $1"\t"$2"\t"$3"\t"mem2tax[$2]}' ./taxonomy/afdb50best_clu_lineage.tsv ./share_db/all-repId_memId_cluFlag-1234-2.tsv > ./share_db/website-all-repId_memId_cluFlag_taxId.tsv & 35 | 36 | # Cluster file with non-AFDB-clusters rep Ids (for web) 37 | awk 'FNR==NR {print $1"\t1\t"$2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7"\t"$8; id[$1]=1; next;} !($1 in id) {id[$1]=1; print $1"\t0\t0\t0\t0\t0\t0\t0\tN/A"}' summary/repId_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv share_db/all-repId_memId_cluFlag-1234-2.tsv > share_db/all-clusters-repId_isAFDBCluster_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv 38 | 39 | ### Supplements 40 | awk -F "\t" 'FNR==NR {dark[$1]=1; next;} ($1 in dark) {print $1"\t1\t"$2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7; next;} !($1 in darK) {print $1"\t0\t"$2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7}' ./darkening/without_foldseek-pdb_mmseqs-pfam_ftp-pfam-tigrfram summary/repId_nMem_repLen_avgLen_repPlddt_avgPlddt_taxId_lineage.tsv | sed -E 's/-F1-model_v3.cif//' | sed -E 's/AF-//' > share_db/2-repId_isDark_nMem_repLen_avgLen_repPlddt_avgPlddt_LCAtaxId.tsv -------------------------------------------------------------------------------- /dark_distribution/dark_distribution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# read file\n", 10 | "fn = \"repId_isDark_nMem.tsv\"\n", 11 | "f = open(f'../summary/{fn}', 'r')\n", 12 | "\n", 13 | "bright_nMem_hit = {}\n", 14 | "dark_nMem_hit = {}\n", 15 | "\n", 16 | "while True:\n", 17 | " line = f.readline().strip()\n", 18 | "\n", 19 | " if not line:\n", 20 | " break\n", 21 | "\n", 22 | " [repId, isDark, nMem] = line.split('\\t')\n", 23 | " isDark = int(isDark)\n", 24 | " nMem = int(nMem)\n", 25 | "\n", 26 | " if isDark == 1:\n", 27 | " if dark_nMem_hit.get(nMem):\n", 28 | " dark_nMem_hit[nMem] += 1\n", 29 | " else:\n", 30 | " dark_nMem_hit[nMem] = 1\n", 31 | " else:\n", 32 | " if bright_nMem_hit.get(nMem):\n", 33 | " bright_nMem_hit[nMem] += 1\n", 34 | " else:\n", 35 | " bright_nMem_hit[nMem] = 1\n", 36 | "\n", 37 | "f.close()" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 23, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "# dictionary to array\n", 47 | "max_nMem = max(list(bright_nMem_hit.keys()) + list(dark_nMem_hit.keys())) \n", 48 | "bright_hist_nMem = [ bright_nMem_hit[i] if bright_nMem_hit.get(i) else 0 for i in range(max_nMem+1)]\n", 49 | "dark_hist_nMem = [ dark_nMem_hit[i] if dark_nMem_hit.get(i) else 0 for i in range(max_nMem+1)]" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 59, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "# arrange histogram - set variables\n", 59 | "delimiters = [4, 10, 20, 40, 80, 160, 320, 700, 1800, 38901]\n", 60 | "delimiters_starting_point = [2] + delimiters\n", 61 | "Xs = [f\"{delimiters_starting_point[i-1]}~{delimiters_starting_point[i]}\" for i in range(1, len(delimiters_starting_point)) ]\n", 62 | "num_bins = len(delimiters)\n", 63 | "\n", 64 | "num_member_AFDB_Clusters = 0\n", 65 | "\n", 66 | "dark_bins = [0] * num_bins\n", 67 | "bright_bins = [0] * num_bins\n", 68 | "occupations_per_bins = [0] * num_bins\n", 69 | "\n", 70 | "dark_rate_bins = [0] * num_bins\n", 71 | "bright_rate_bins = [0] * num_bins" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 60, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "# histogram into 10 bins\n", 81 | "bin_i = 0\n", 82 | "nMem_i = 2\n", 83 | "\n", 84 | "for bin_i in range(len(delimiters)):\n", 85 | " bin_nMem_upper_bound = delimiters[bin_i]\n", 86 | "\n", 87 | " # traverse hist array\n", 88 | " while True:\n", 89 | " if nMem_i > max_nMem:\n", 90 | " break\n", 91 | " \n", 92 | " dark_bins[bin_i] += dark_hist_nMem[nMem_i]\n", 93 | " bright_bins[bin_i] += bright_hist_nMem[nMem_i]\n", 94 | "\n", 95 | " occupations_per_bins[bin_i] += ( dark_hist_nMem[nMem_i] + bright_hist_nMem[nMem_i] ) * nMem_i\n", 96 | " num_member_AFDB_Clusters += ( dark_hist_nMem[nMem_i] + bright_hist_nMem[nMem_i] ) * nMem_i\n", 97 | "\n", 98 | " nMem_i += 1\n", 99 | "\n", 100 | " if nMem_i > bin_nMem_upper_bound:\n", 101 | " break" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 61, 107 | "metadata": {}, 108 | "outputs": [ 109 | { 110 | "name": "stdout", 111 | "output_type": "stream", 112 | "text": [ 113 | "12.24%, 10.59%, 9.20%, 10.07%, 10.46%, 10.05%, 9.04%, 9.20%, 9.19%, 9.96%, " 114 | ] 115 | } 116 | ], 117 | "source": [ 118 | "# find occupations\n", 119 | "for i in range(num_bins):\n", 120 | " occupations_per_bins[i] = occupations_per_bins[i] / num_member_AFDB_Clusters * 100\n", 121 | "\n", 122 | "for e in occupations_per_bins:\n", 123 | " print(\"{:.2f}%\".format(e), end=\", \")" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 63, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "# generate ratio per bin\n", 133 | "for i in range(num_bins):\n", 134 | " denominator = bright_bins[i] + dark_bins[i]\n", 135 | "\n", 136 | " bright_rate_bins[i] = bright_bins[i] / denominator * 100\n", 137 | " dark_rate_bins[i] = dark_bins[i] / denominator * 100" 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 65, 143 | "metadata": {}, 144 | "outputs": [ 145 | { 146 | "data": { 147 | "image/png": "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qyucnJyQnJz8zu1WndW/iZEBYLz3h/9k6mt2wLDzZyb7u5iZmcHI6NPvYcaCjoiIcpSxsfF7+zM9g34WFRYWH/6Tqa/ZAcPOn5ns/3WffslKRERE9IljQUdERERk4FjQERERERk4FnREREREBo4FHREREZGBY0FHREREZOBY0BEREREZOBZ0RERERAaOBR0RERGRgWNBR0RERGTgWNARERERGTgWdEREREQGjgUdERERkYFjQUdERERk4FjQERERERk4FnREREREBo4FHREREZGBY0FHREREZOBY0BEREREZOBZ0RERERAaOBR0RERGRgWNBR0RERGTgWNARERERGTgWdEREREQGjgUdERERkYHT64IuJSUFY8aMgYeHBywtLVGkSBFMnDgRIqJsIyIYO3YsXF1dYWlpicDAQERGRuowNREREVHO0uuCbvr06ViyZAkWLlyIS5cuYfr06ZgxYwYWLFigbDNjxgzMnz8fS5cuxfHjx5ErVy7Uq1cPr1690mFyIiIiopxjousA73PkyBE0bdoUjRo1AgC4u7tj/fr1OHHiBIDU1rm5c+di9OjRaNq0KQBg9erVcHZ2xtatW9G2bVudZSciIiLKKXrdQufv74/g4GBcuXIFAHD27FkcOnQIDRo0AADcuHEDMTExCAwMVJ5jZ2cHX19fHD169J2vm5iYiLi4OI0vIiIiIkOl1y10w4cPR1xcHLy9vWFsbIyUlBRMnjwZQUFBAICYmBgAgLOzs8bznJ2dlXUZmTp1KsaPH599wYmIiIhykF630G3cuBFr167FunXrcPr0afz888/4/vvv8fPPP/+r1x0xYgSePXumfEVHR2dRYiIiIqKcp3UL3Y0bN3Dw4EFERUXhxYsXcHR0RNmyZeHn5wcLC4ssDTdkyBAMHz5c6QtXqlQpREVFYerUqejYsSNcXFwAAPfv34erq6vyvPv376NMmTLvfF1zc3OYm5tnaVYiIiIiXcl0Qbd27VrMmzcPYWFhcHZ2hpubGywtLfH48WNcu3YNFhYWCAoKwrBhw1CoUKEsCffixQsYGWk2IhobG0OtVgMAPDw84OLiguDgYKWAi4uLw/Hjx9G7d+8syUBERESk7zJV0JUtWxZmZmbo1KkTNm/ejAIFCmisT0xMxNGjR7FhwwZUqFABixcvRqtWrf51uMaNG2Py5MkoWLAgSpQogfDw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3r17yrkeEREhX375pQwYMEAcHBw0pnjQF5cvX5b169fLtm3blFGtr1+/ljx58sj48eNF5H8/syIi7dq1E39/f71obQwPD1emHErLsn//fsmXL58yMOvND5ilSpWSzp076yTr227duiWXL1/WaLHav3+/uLm56X12kdSfzZkzZ8qSJUuUDyspKSnvPW8qV66scc48ffr0PznFCQs6EhGRKlWqSMuWLWXQoEHKpKy7d+8WT09PmTRpkojoT6GRkbRst27dknbt2knt2rWVju/60D8tTUZ/qB49eiQ9evSQgQMHpluXtl/Pnz+X06dPy8OHD7M94/tkdA6sX79e6tWrp8w1pi8DbTJi6PkzyvT7779L7dq1lRGL+px/3bp14uzsLI8ePRKR/7USbdq0Sby9vWX+/Pl69XsmbcSoiMiIESM0pvFJO85TpkwRW1tbZUS7Ph53Q84uIrJ27dp3njdFixZV5mWMjo6Wrl27ioeHh3h6ekrFihXl+vXrOsud01jQkVy7dk0KFy4s7u7uyuXXiIgICQgIkICAAGU7ff1hfzPX2LFjxdfXV5mc9e3ML1++VFoL9Mnx48clT5480q5dO3n48KHyCzbNsmXLpHnz5lKmTBlZsmSJjlL+z5vHNTY2Vlq0aCH169fXYSLtaJs/KSlJ7ty5o0yxoGtv5n/8+LF07NhR6tat+87tU1JSZM+ePRp3odCFPXv2iJubm8ZxjIqKkkqVKknbtm2V5Wn7p0/F3axZs8Tf31+51CeSOvm2kZGRTJs2TWO5iH59kDTU7GnnwfvOm9atW8v9+/fln3/+kVatWomjo6OsX79eDh8+LN26dZPy5ctrTDfzKWNBRyKS+smmTZs2YmFhIdOnT5fx48eLvb290ndOX37A02SU59dff5WAgADp37+/siztMtudO3dkzZo1Urp0afH395cmTZro3VD36OhoqVmzpvj6+kr79u01Cs/ExEQ5fPiwLF++XAoUKCBBQUEalxB17enTp1K5cmXJly+fTJs2TRYuXKhMufH2pfFXr17pVXaRjPOnZbx+/boMHDhQXF1d5bPPPpNGjRrp3bmTkJAgAQEBki9fPpk/f77MnDlTY9TirVu3JCgoSEqWLCktWrSQ58+f6yTnP//8I97e3rJq1Sp5+PChRERESLly5aRGjRoaU/nExcUp3UFE9OPDZHBwsLi4uMja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", 148 | "text/plain": [ 149 | "
" 150 | ] 151 | }, 152 | "metadata": {}, 153 | "output_type": "display_data" 154 | } 155 | ], 156 | "source": [ 157 | "import matplotlib.pyplot as plt\n", 158 | "\n", 159 | "colors = ['#d4453d', '#67c8fb', '#67c8fb']\n", 160 | "labels = ['w/o annotation',\n", 161 | " 'with annotation',\n", 162 | " 'sequences without annotation in (1)',]\n", 163 | "\n", 164 | "plt.bar(Xs, bright_rate_bins, bottom=dark_rate_bins, color=colors[2], label=labels[1])\n", 165 | "plt.bar(Xs, dark_rate_bins, color=colors[0], label=labels[0])\n", 166 | "plt.xticks(Xs, rotation=-35, ha='left')\n", 167 | "plt.xlabel(\"cluster size range\")\n", 168 | "plt.ylabel(\"occupation in each bin (%)\")\n", 169 | "plt.legend()\n", 170 | "\n", 171 | "plt.tight_layout()\n", 172 | "plt.savefig('darks.svg')" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": 5, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "import matplotlib.pyplot as plt\n", 182 | "import numpy as np\n", 183 | "\n", 184 | "# set variables\n", 185 | "label_bars = ['removed (fragments, singletons)', 'w/o annotation', 'with annotation']\n", 186 | "colors = ['#b6b6b6', '#d4453d', '#67c8fb']\n", 187 | "Xs = ['AFDB\\n214M', 'AFDB clusters\\n2.27M']\n", 188 | "Ys_top = np.arange(len(Xs))\n", 189 | "\n", 190 | "afdb_r_d_b = [0, 0, 0] # removed, dark, bright\n", 191 | "afdb_clusters_r_d_b = [0, 0, 0]" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 6, 197 | "metadata": {}, 198 | "outputs": [], 199 | "source": [ 200 | "fn_afdb = 'AFDB-removed_dark_bright.tsv'\n", 201 | "f_afdb = open(f\"../summary/{fn_afdb}\")\n", 202 | "\n", 203 | "afdb_r_d_b = list(map(int, f_afdb.readline().strip().split()))\n", 204 | "\n", 205 | "f_afdb.close()\n", 206 | "\n", 207 | "fn_afdb_clusters = 'AFDB-Clusters-removed_dark-bright.tsv'\n", 208 | "f_afdb_clusters = open(f'../summary/{fn_afdb_clusters}')\n", 209 | "\n", 210 | "afdb_clusters_r_d_b = list(map(int, f_afdb_clusters.readline().strip().split()))\n", 211 | "\n", 212 | "f_afdb_clusters.close()" 213 | ] 214 | }, 215 | { 216 | "cell_type": "code", 217 | "execution_count": 7, 218 | "metadata": {}, 219 | "outputs": [], 220 | "source": [ 221 | "# generate ratio\n", 222 | "layers = np.array([afdb_r_d_b, afdb_clusters_r_d_b]).T\n", 223 | "denominators = np.sum(layers, axis=0)\n", 224 | "layers = layers / denominators * 100" 225 | ] 226 | }, 227 | { 228 | "cell_type": "code", 229 | "execution_count": 11, 230 | "metadata": {}, 231 | "outputs": [ 232 | { 233 | "data": { 234 | "image/png": "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", 235 | "text/plain": [ 236 | "
" 237 | ] 238 | }, 239 | "metadata": {}, 240 | "output_type": "display_data" 241 | } 242 | ], 243 | "source": [ 244 | "\n", 245 | "fig = plt.figure()\n", 246 | "gs = fig.add_gridspec(1, 3)\n", 247 | "ax1 = fig.add_subplot(gs[0, 2])\n", 248 | "ax2 = fig.add_subplot(gs[0, 0:1])\n", 249 | "\n", 250 | "w = 0.5\n", 251 | "bottoms = np.zeros(len(Ys_top))\n", 252 | "[I, J] = layers.shape\n", 253 | "\n", 254 | "for i in range(len(layers)):\n", 255 | " ax2.bar(Ys_top, layers[i], w, bottom=bottoms, color=colors[i], label=label_bars[i])\n", 256 | " bottoms = bottoms + layers[i]\n", 257 | "\n", 258 | " for j in range(J-1):\n", 259 | " ax2.plot([Ys_top[j] + w/2, Ys_top[j+1] - w/2],\n", 260 | " [bottoms[j]-0.3, bottoms[j+1]-0.3],\\\n", 261 | " color='C7', ls='--', zorder=1)\n", 262 | "\n", 263 | "ax2.set_xticks(Ys_top, Xs, rotation=-35, ha='left')\n", 264 | "ax2.set_ylabel('occupation in each bin (%)')\n", 265 | "ax2.set_ylim([0, 105])\n", 266 | "# ax2.legend()\n", 267 | "\n", 268 | "plt.legend()\n", 269 | "plt.tight_layout()\n", 270 | "plt.savefig('two_bars2.svg')\n", 271 | "# plt.show()" 272 | ] 273 | }, 274 | { 275 | "cell_type": "code", 276 | "execution_count": null, 277 | "metadata": {}, 278 | "outputs": [], 279 | "source": [] 280 | } 281 | ], 282 | "metadata": { 283 | "kernelspec": { 284 | "display_name": "tutorial", 285 | "language": "python", 286 | "name": "python3" 287 | }, 288 | "language_info": { 289 | "codemirror_mode": { 290 | "name": "ipython", 291 | "version": 3 292 | }, 293 | "file_extension": ".py", 294 | "mimetype": "text/x-python", 295 | "name": "python", 296 | "nbconvert_exporter": "python", 297 | "pygments_lexer": "ipython3", 298 | "version": "3.10.6" 299 | }, 300 | "orig_nbformat": 4 301 | }, 302 | "nbformat": 4, 303 | "nbformat_minor": 2 304 | } 305 | -------------------------------------------------------------------------------- /purity/pfam_consistency.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# open file\n", 10 | "fn = \"pfamOrClan-uniprot-numHits_repId_pfamOrClan.tsv\"\n", 11 | "f = open(f\"../purity/{fn}\")\n", 12 | "\n", 13 | "# data\n", 14 | "rep_pfams = {}\n", 15 | "\n", 16 | "# read file\n", 17 | "while True:\n", 18 | " line = f.readline().strip()\n", 19 | " \n", 20 | " if not line:\n", 21 | " break\n", 22 | " \n", 23 | " tokens = line.split()\n", 24 | " hit = int(tokens[0])\n", 25 | " repId = tokens[1]\n", 26 | " pfams = set(tokens[2].split(';')[:-1])\n", 27 | " \n", 28 | " if not rep_pfams.get(repId):\n", 29 | " rep_pfams[repId] = []\n", 30 | " \n", 31 | " rep_pfams[repId].append([pfams, hit])\n", 32 | "\n", 33 | "# close file\n", 34 | "f.close()" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 4, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "# count the diversity of pfam\n", 44 | "def compute_sum_hits(pfam_hits):\n", 45 | " L = len(pfam_hits)\n", 46 | " \n", 47 | " sum_hits = 0\n", 48 | " for i in range(L):\n", 49 | " [pfam, hits] = pfam_hits[i]\n", 50 | " \n", 51 | " sum_hits += hits\n", 52 | " \n", 53 | " return sum_hits" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 7, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "import math\n", 63 | "\n", 64 | "rep_cov = {}\n", 65 | "iteration = math.inf\n", 66 | "\n", 67 | "check_id = 'AF-A0A009G5I8-F1-model_v3.cif'\n", 68 | "\n", 69 | "for repId, pfam_hits in rep_pfams.items():\n", 70 | " \n", 71 | " # if there is only one hit at a cluster, we don't measure the consistency value\n", 72 | " if compute_sum_hits(pfam_hits) < 2:\n", 73 | " continue\n", 74 | " \n", 75 | " rep_cov[repId] = 0\n", 76 | " N = len(pfam_hits) \n", 77 | " \n", 78 | " repId_hits = 0\n", 79 | " \n", 80 | " for i in range(N):\n", 81 | " pairwise_score = 0\n", 82 | " \n", 83 | " query_pfams = pfam_hits[i][0]\n", 84 | " query_hits = pfam_hits[i][1]\n", 85 | " repId_hits += query_hits\n", 86 | " \n", 87 | " query_N_pfams = len(query_pfams)\n", 88 | " \n", 89 | " for j in range(N):\n", 90 | " coverage = 0\n", 91 | " target_pfams = pfam_hits[j][0]\n", 92 | " target_hits = pfam_hits[j][1]\n", 93 | " \n", 94 | " # w/o self-pair\n", 95 | " if i == j :\n", 96 | " target_hits -= 1\n", 97 | " \n", 98 | " for pfam in query_pfams:\n", 99 | " if pfam in target_pfams:\n", 100 | " coverage += 1\n", 101 | " \n", 102 | " coverage = coverage/ query_N_pfams * target_hits\n", 103 | " pairwise_score += coverage\n", 104 | " \n", 105 | " pairwise_score *= query_hits\n", 106 | " rep_cov[repId] += pairwise_score\n", 107 | " \n", 108 | " rep_cov[repId] /= (repId_hits**2 - repId_hits)\n" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 8, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "fon = \"pfam-consistency_repId_cov.tsv\"\n", 118 | "fo = open(f'../purity/{fon}', 'w')\n", 119 | "\n", 120 | "for key, value in rep_cov.items():\n", 121 | " fo.write(f'{key}\\t{value}\\n')\n", 122 | "\n", 123 | "fo.close()" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": null, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [] 132 | } 133 | ], 134 | "metadata": { 135 | "kernelspec": { 136 | "display_name": "tutorial", 137 | "language": "python", 138 | "name": "python3" 139 | }, 140 | "language_info": { 141 | "codemirror_mode": { 142 | "name": "ipython", 143 | "version": 3 144 | }, 145 | "file_extension": ".py", 146 | "mimetype": "text/x-python", 147 | "name": "python", 148 | "nbconvert_exporter": "python", 149 | "pygments_lexer": "ipython3", 150 | "version": "3.10.6" 151 | }, 152 | "orig_nbformat": 4 153 | }, 154 | "nbformat": 4, 155 | "nbformat_minor": 2 156 | } 157 | -------------------------------------------------------------------------------- /purity/purity_figure.ipynb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steineggerlab/afdb-clusters-analysis/4c38d80184fbb967b5fc9fe75d7a765a1c6cf98e/purity/purity_figure.ipynb -------------------------------------------------------------------------------- /purity/subsitute_clan.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 4, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# open file\n", 10 | "fcn = \"pfam-clan.tsv\"\n", 11 | "fc = open(f'../purity/{fcn}')\n", 12 | "\n", 13 | "# data\n", 14 | "pfam_clan = {}\n", 15 | "\n", 16 | "# read file\n", 17 | "while True:\n", 18 | " line = fc.readline().strip()\n", 19 | " \n", 20 | " if not line:\n", 21 | " break\n", 22 | " \n", 23 | " tokens = line.split()\n", 24 | " \n", 25 | " pfam = tokens[0]\n", 26 | " clan = tokens[1]\n", 27 | " \n", 28 | " pfam_clan[pfam] = clan\n", 29 | "\n", 30 | "# close file\n", 31 | "fc.close()" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 6, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "# open file\n", 41 | "fn = \"pfam-uniprot-numHits_repId_pfams.tsv\"\n", 42 | "f = open(f'../darkening/ftp_pfam_tigrfam/{fn}')\n", 43 | "\n", 44 | "# data\n", 45 | "lines = []\n", 46 | "\n", 47 | "# read file & clan substitution\n", 48 | "while True:\n", 49 | " line = f.readline().strip()\n", 50 | " \n", 51 | " if not line:\n", 52 | " break\n", 53 | " \n", 54 | " tokens = line.split()\n", 55 | " \n", 56 | " numHit = tokens[0]\n", 57 | " repId = tokens[1]\n", 58 | " pfams = tokens[2].split(';')[:-1]\n", 59 | " \n", 60 | " for i in range(len(pfams)):\n", 61 | " pfam = pfams[i]\n", 62 | " \n", 63 | " if pfam_clan.get(pfam):\n", 64 | " pfams[i] = pfam_clan[pfam]\n", 65 | " \n", 66 | " pfam_string = ';'.join(pfams)\n", 67 | " \n", 68 | " lines.append(f'{numHit}\\t{repId}\\t{pfam_string};')\n", 69 | "\n", 70 | "# close file\n", 71 | "f.close()" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 7, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "fon = \"pfamOrClan-uniprot-numHits_repId_pfamOrClan.tsv\"\n", 81 | "fo = open(f'../purity/{fon}', 'w')\n", 82 | "\n", 83 | "for line in lines:\n", 84 | " fo.write(f'{line}\\n')\n", 85 | "\n", 86 | "fo.close()" 87 | ] 88 | } 89 | ], 90 | "metadata": { 91 | "kernelspec": { 92 | "display_name": "Python 3", 93 | "language": "python", 94 | "name": "python3" 95 | }, 96 | "language_info": { 97 | "codemirror_mode": { 98 | "name": "ipython", 99 | "version": 3 100 | }, 101 | "file_extension": ".py", 102 | "mimetype": "text/x-python", 103 | "name": "python", 104 | "nbconvert_exporter": "python", 105 | "pygments_lexer": "ipython3", 106 | "version": "3.10.6" 107 | }, 108 | "orig_nbformat": 4 109 | }, 110 | "nbformat": 4, 111 | "nbformat_minor": 2 112 | } 113 | --------------------------------------------------------------------------------