{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "prostate-definition",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Taxonomic profiling\n",
    "\n",
    "############# Merge using BBMap\n",
    "\n",
    "$ bbmerge-auto.sh in1=16S-Sample-01_R1.fastq in2=16S-Sample-01_R2.fastq out=16S-Sample-01.merged.fastq outu=16S-Sample-01.unmerged.fastq rsem extend2=50 k=62 -Xmx3613m \n",
    "\n",
    "$ gzip 16S-Sample-01.merged.fastq\n",
    "\n",
    "############# Filter for quality using Trimmomatic\n",
    "\n",
    "$ TrimmomaticSE -threads 35 -phred33 16S-Sample-01.merged.fastq.gz 16S-Sample-01.trimmed.fastq.gz LEADING:3 TRAILING:3 SLIDINGWINDOW:4:15\n",
    "\n",
    "$ gunzip 16S-Sample-01.trimmed.fastq.gz\n",
    "                \n",
    "############# Chimeras were removed using USEARCH against the SILVA database\n",
    "\n",
    "$ usearch9.2.64_i86linux64 -uchime2_ref 16S-Sample-01.trimmed.fastq -db SILVA_SSU.fasta -notmatched 16S-Sample-01.fastq -strand plus -mode high_confidence\n",
    "\n",
    "$ gzip 16S-Sample-01.fastq\n",
    "\n",
    "############# Phylogenetic assignment and relative quantification\n",
    "\n",
    "$ kraken2 --db oral_microbiome_UNITE/ --threads 40 --output 16S-Sample-01.kraken2 --report 16S-Sample-01.kreport2 --gzip-compressed 16S-Sample-01.fastq.gz\n",
    "\n",
    "$ bracken -d oral_microbiome_UNITE/ -t 40 -i 16S-Sample-01.kreport2 -o 16S-Sample-01.bracken -r 250 -l S \n",
    "\n",
    "$ kreport2mpa.py -r 16S-Sample-01_bracken_species.kreport2 -o 16S-Sample-01.mpa ### Run these for each sample. Generates a mpa file from bracken reports.\n",
    "\n",
    "### Merge the results (.mpa files) of all samples into a table:\n",
    "\n",
    "$ ./merge_metaphlan_tables.py 16S-Sample-01.mpa 16S-Sample-02.mpa … > merged_OTUs_table.tab\n",
    "\n",
    "############# Custom database of the ITS sequences with selected fungi species that had been previously identified in oral samples and the ITS sequences of Entamoeba gingivalis. \n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "close-honduras",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# General procedure used to generate a phyloseq object\n",
    "############# OTUS.csv was obtained from 'merged_OTUs_table.tab' table selecting only for species.This is the table that was used throughout all the analyses described below.\n",
    "### In R\n",
    "\n",
    "library(phyloseq)\n",
    "\n",
    "otus<-read.csv('OTUS.csv', header = TRUE, row.names = 1)  ## Count table\n",
    "otus<-t(otus)\n",
    "taxmat<-read.csv(\"taxmat.csv\", header = TRUE, row.names = 1) ## Taxonomy table\n",
    "samples<-read.csv(\"Sample_data.csv\", header = TRUE, row.names =1) ## Sample information table\n",
    "taxmat<-as.matrix(taxmat)\n",
    "otus<-as.matrix(otus)\n",
    "\n",
    "OTU = otu_table(otus, taxa_are_rows = FALSE)\n",
    "TAX = tax_table(taxmat)\n",
    "SAM = sample_data(samples)\n",
    "\n",
    "physeq = phyloseq(OTU, TAX, SAM) ### generate phyloseq object\n",
    "\n",
    "random_tree = rtree(ntaxa(physeq), rooted=TRUE, tip.label=taxa_names(physeq))\n",
    "\n",
    "physeq = phyloseq(OTU, TAX, SAM, random_tree) ## Phyloseq object to be used in analysis below\n",
    "\n",
    "sample_data(physeq)$group = as.character(sample_data(physeq)$group)\n",
    "get_variable(physeq,\"group\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "looking-lafayette",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure 1a. Barplot representation of temporal changes in frequencies of species in the three groups studied\n",
    "### In R\n",
    "\n",
    "library(phyloseq)\n",
    "library(ape)\n",
    "library(dplyr)\n",
    "library(ggplot2)\n",
    "library(microbiomeSeq)\n",
    "\n",
    "otus<-read.csv('OTUS.csv', header = TRUE, row.names = 1)\n",
    "otus=otus+1\n",
    "otus<-t(otus)\n",
    "taxmat<-read.csv(\"taxmat.csv\", header = TRUE, row.names = 1)\n",
    "samples<-read.csv(\"Sample_data.csv\", header = TRUE, row.names =1)\n",
    "\n",
    "taxmat<-as.matrix(taxmat)\n",
    "otus<-as.matrix(otus)\n",
    "\n",
    "OTU = otu_table(otus, taxa_are_rows = FALSE)\n",
    "TAX = tax_table(taxmat)\n",
    "SAM = sample_data(samples)\n",
    "\n",
    "physeq = phyloseq(OTU, TAX, SAM) ### generate phyloseq object\n",
    "random_tree = rtree(ntaxa(physeq), rooted=TRUE, tip.label=taxa_names(physeq))\n",
    "physeq = phyloseq(OTU, TAX, SAM, random_tree)\n",
    "sample_data(physeq)$group = as.character(sample_data(physeq)$group)\n",
    "get_variable(physeq,\"group\")\n",
    "\n",
    "### Normalize number of reads in each sample \n",
    "\n",
    "physeq <- normalise_data(physeq, norm.method = \"edgernorm\")\n",
    "\n",
    "############# Time series barplot \n",
    "\n",
    "erie_phylum <- physeq %>%\n",
    "  tax_glom(taxrank = \"Species\") %>%                     # agglomerate at species level\n",
    "  transform_sample_counts(function(x) {x/sum(x)} ) %>% # Transform to rel. abundance\n",
    "  psmelt() %>%                                         # Melt to long format\n",
    "  filter(Abundance > 0.1) %>%                  # Filter out low abundance taxa\n",
    "  arrange(Species) \n",
    "\n",
    "phylum_colors <-c(\"maroon1\",\"cornsilk2\",\"magenta1\",\"darkgoldenrod1\",\"lightyellow1\",\"antiquewhite2\",\"yellow1\",\"deeppink1\",\"lavenderblush1\",\"mediumorchid2\",\"lightblue3\",\"springgreen1\",\"aquamarine2\",\"chartreuse3\",\"turquoise4\",\"bisque1\",\"palevioletred1\",\"deepskyblue4\",\"turquoise1\",\"lightblue2\",\"khaki1\",\"cornsilk1\",\"lightskyblue3\",\"magenta2\",\"lightcyan3\",\"deeppink2\",\"yellow3\",\"indianred2\",\"darkseagreen3\",\"lightyellow4\",\"ivory2\",\"olivedrab1\",\"ivory1\",\"cyan1\",\"tan1\",\"coral1\",\"darkorchid1\",\"mediumpurple4\",\"magenta3\",\"honeydew1\",\"gold1\",\"lightsteelblue1\",\"lightsalmon3\",\"indianred4\",\"lightsalmon4\",\"deepskyblue2\",\"antiquewhite3\",\"darkorange1\",\"springgreen2\",\"gold2\",\"orange4\",\"lemonchiffon1\",\"maroon4\",\"ivory4\",\"mediumpurple1\",\"maroon3\",\"chocolate2\",\"purple3\",\"honeydew4\",\"plum2\",\"aquamarine3\",\"darkorchid3\",\"tan3\",\"lemonchiffon3\",\"lemonchiffon4\",\"darkseagreen2\",\"chocolate1\",\"mediumorchid3\",\"seegreen1\",\"brown2\",\"hotpink1\")\n",
    "\n",
    " ggplot(erie_phylum, aes(x = time, y = Abundance, fill = Species)) + \n",
    "     facet_grid(group~.) +\n",
    "     geom_bar(stat = \"identity\") +\n",
    "     scale_fill_manual(values = phylum_colors) +\n",
    "         # Remove x axis title\n",
    "     theme(axis.title.x = element_blank()) + \n",
    "     #\n",
    "     guides(fill = guide_legend(reverse = TRUE, keywidth = 1, keyheight = 1)) +\n",
    "     ylab(\"Relative Abundance (Species > 5%) \\n\") +\n",
    "     ggtitle(\"Species Composition\") \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "motivated-accordance",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure 1b. Violin plot of Shannon alpha-diversity. Using the phyloseq object ‘physeq’\n",
    "### In R\n",
    "\n",
    "ps1 <- prune_taxa(taxa_sums(physeq) > 0, physeq)\n",
    "tab <- microbiome::alpha(ps1, index = \"all\")\n",
    "ps1.meta <- meta(ps1)\n",
    "ps1.meta$Shannon <- tab$diversity_shannon \n",
    "ps1.meta$InverseSimpson <- tab$diversity_inverse_simpson\n",
    "\n",
    "# create a list of pairwise comaprisons\n",
    "ps1.meta$group<-factor(ps1.meta$group)\n",
    "bmi <- levels(ps1.meta$group) # get the variables\n",
    "# make a pairwise list that we want to compare.\n",
    "bmi.pairs <- combn(seq_along(bmi), 2, simplify = FALSE, FUN = function(i)bmi[i])\n",
    "\n",
    "print(bmi.pairs)\n",
    "p1 <- ggviolin(ps1.meta, x = \"group\", y = \"Shannon\",add = c(\"jitter\",\"boxplot\"), fill = \"group\", rotate = TRUE, palette = c(\"#a6cee3\", \"#b2df8a\", \"#fdbf6f\"))\n",
    "print(p1)\n",
    "p1 <- p1 + stat_compare_means(comparisons = bmi.pairs) \n",
    "print(p1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "impressive-stand",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure 1c. Time series profiles of Shannon diversity index\n",
    "### In R\n",
    "library(microbiome)\n",
    "library(ape)\n",
    "library(phyloseq)\n",
    "library(ggplot2)\n",
    "library(Rmisc)\n",
    "\n",
    "otus<-read.csv('OTUS.csv', header = TRUE, row.names = 1)\n",
    "otus=otus+1\n",
    "otus<-t(otus)\n",
    "taxmat<-read.csv(\"taxmat.csv\", header = TRUE, row.names = 1)\n",
    "samples<-read.csv(\"Sample_data.csv\", header = TRUE, row.names =1)\n",
    "taxmat<-as.matrix(taxmat)\n",
    "otus<-as.matrix(otus)\n",
    "\n",
    "OTU = otu_table(otus, taxa_are_rows = FALSE)\n",
    "TAX = tax_table(taxmat)\n",
    "SAM = sample_data(samples)\n",
    "physeq = phyloseq(OTU, TAX, SAM) ### generate phyloseq object\n",
    "random_tree = rtree(ntaxa(physeq), rooted=TRUE, tip.label=taxa_names(physeq))\n",
    "\n",
    "physeq = phyloseq(OTU, TAX, SAM, random_tree)\n",
    "\n",
    "df1<-samples[,2:3]\n",
    "df2 <- alpha(physeq, index = \"Shannon\")\n",
    "rownames(df1) <- c()\n",
    "rownames(df2) <- c()\n",
    "\n",
    "df<-cbind(df2,df1)\n",
    "tgc <- summarySE(df, measurevar=\"diversity_shannon\", groupvars=c(\"group\",\"time\"))\n",
    "pd <- position_dodge(0.1)\n",
    "\n",
    "d<-ggplot(tgc, aes(x=time, y=diversity_shannon, colour=group, group=group, fill=group)) + \n",
    "   geom_errorbar(aes(ymin=diversity_shannon-se, ymax=diversity_shannon+se), colour=\"grey\", width=.3, position=pd) +\n",
    "   geom_line(position=pd) +\n",
    "   geom_point(position=pd, size=3, shape=21) + # 21 is filled circle\n",
    "   xlab(\"Time (months)\") +\n",
    "   ylab(\"Diversity\") +\n",
    "   scale_colour_hue(name=\"Profiles\",    # Legend label, use darker colors\n",
    "                     breaks=c(\"Stable\", \"Progressing\", \"Fluctuating\"),\n",
    "                   labels=c(\"Stable\", \"Progressing\", \"Fluctuating\"),\n",
    "               l=50) +                    # Use darker colors, lightness=40\n",
    "    expand_limits(y=2) +                        # Expand y range\n",
    "  theme_bw() +\n",
    "     theme(legend.justification=c(1,0),\n",
    "          legend.position=c(1,0))    \n",
    " d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "completed-rolling",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure 1d. Tracking rate of change from static timepoints. Using QIIME2.\n",
    "\n",
    "##### Convert OTUS table to biom format\n",
    "\n",
    "$ biom convert -i OTUS.txt -o OTUS_hdf5.biom --table-type=\"OTU table\" --to-hdf5\n",
    "\n",
    "##### In q2\n",
    "\n",
    "##### Import biom table\n",
    "\n",
    "qiime tools import \\\n",
    "  --input-path  OTUS_hdf5.biom \\\n",
    "  --type 'FeatureTable[Frequency]' \\\n",
    "  --input-format BIOMV100Format \\\n",
    "  --output-path feature-table.qza\n",
    "\n",
    "##### ####### First differencing to track rate of change\n",
    "\n",
    "$ qiime diversity alpha --i-table feature-table.qza --p-metric shannon --o-alpha-diversity shannon.qza --verbose\n",
    "\n",
    "$ qiime longitudinal first-differences --m-metadata-file sample-metadata.tsv --m-metadata-file shannon.qza --p-state-column month --p-metric shannon_entropy --p-individual-id-column patient --p-replicate-handling random --o-first-differences shannon-first-differences.qza\n",
    "\n",
    "$ qiime longitudinal volatility --m-metadata-file sample-metadata.tsv --m-metadata-file shannon-first-differences.qza --p-default-group-column condition --p-state-column month --p-individual-id-column patient --o-visualization volatility-first-distances-shannon.qzv\n",
    "\n",
    "### View figure volatility-first-distances-shannon.qzv in QIIME2 View\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "03a47c3e",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure 2. LEfSe analysis was run locally with default settings as follows: \n",
    "############# LEfSe_DNA_kraken.txt is \"merged_OTUs_table.tab\" with its headers modified to be read by LEfSe\n",
    "############# Headers have the following format:\n",
    "\n",
    "|Condition||stable||stable||...\n",
    "|Library||kraken||kraken||...\n",
    "|ID||16S-Sample-01||16S-Sample-02||...\n",
    "|d_Archaea||66||48||...\n",
    "\n",
    "$ python lefse-format_input.py LEfSe_DNA_kraken.txt LEfSe_DNA.in -c 1 -s 2 -u 3 -o 1000000\n",
    "$ python run_lefse.py LEfSe_DNA.in LEfSe_DNA.res -l 2.0\n",
    "$ python lefse-plot_res.py LEfSe_DNA.res LEfSe_DNA.svg \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6218cf16",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Reconstructing ecological networks with the R package SpiecEasi ################\n",
    "\n",
    "##################################################\n",
    "# https://github.com/zdk123/SpiecEasi#installation\n",
    "##################################################\n",
    "\n",
    "\n",
    "### In R\n",
    "\n",
    "library(phyloseq)\n",
    "library(SpiecEasi)\n",
    "library(igraph)\n",
    "\n",
    "\n",
    "### Subset data for stable samples. Do the same for the other two conditions\n",
    "\n",
    "stable=subset_samples(physeq, group==\"stable\")\n",
    "\n",
    "\n",
    "### Reconstructing the ecological network\n",
    "\n",
    "se.mb.stable <- spiec.easi(stable, method='mb', lambda.min.ratio=1e-3,nlambda=10, pulsar.params=list(rep.num=20, ncores=35), verbose = TRUE) ### Lower lambda.min.ratio value if you get error messages\n",
    "\n",
    "ig2.mb <- adj2igraph(getRefit(se.mb.stable), vertex.attr=list(name=taxa_names(stable)))\n",
    "\n",
    "write_graph(ig2.mb, file='stable.gml', format=\"gml\") ############ Save network\n",
    "write_graph(ig2.mb, file='stable.csv', format=\"edgelist\") ############ Save edgelist\n",
    "\n",
    "plot_network(ig2.mb, stable, type='taxa') ### Plotting network\n",
    "\n",
    "\n",
    "#################### Figure 3a,b,c Network cartography #####################\n",
    "\n",
    "library(igraph)\n",
    "library(ggplot2)\n",
    "library(tidyverse)\n",
    "library(rnetcarto)\n",
    "\n",
    "####### Example fluctuating \n",
    "####### See https://cran.r-project.org/web/packages/tsna/vignettes/tsna_vignette.html where it describes the formats of PHStaticEdges and PHVertexAttributes\n",
    "\n",
    "PHStaticEdges <- read.csv('microbiome_StaticEdgelist_fluctuating.csv', stringsAsFactors = FALSE)\n",
    "PHVertexAttributes <- read.csv('microbiome_VertexAttributes_fluctuating.csv', stringsAsFactors = FALSE, header = TRUE)\n",
    "\n",
    "\n",
    "# Make and visualize our static network\n",
    "\n",
    "thenetwork <- network(\n",
    "  PHStaticEdges,\n",
    "  vertex.attr = PHVertexAttributes,\n",
    "  vertex.attrnames = c(\"vertex.id\",\"name\"),\n",
    "  directed = FALSE,\n",
    "  bipartite = FALSE\n",
    ")\n",
    "\n",
    "g <- asIgraph(thenetwork)\n",
    "\n",
    "cartfluctuating<-netcarto(igraph::get.adjacency(g,sparse=FALSE))\n",
    "\n",
    "lapply(cartfluctuating, function(x) write.table( data.frame(x), 'Cartography_fluctuating.csv', append= T, sep=',' ))\n",
    "\n",
    "###### Plot results\n",
    "###### Delete last row of 'Cartography_fluctuating.csv'\n",
    "\n",
    "cartfl<-read.csv('Cartography_fluctuating.csv', header = TRUE)\n",
    "\n",
    "cartfl_2k <- cartfl %>%\n",
    "     select(participation, connectivity, role, name)%>%\n",
    "     drop_na()\n",
    "\n",
    "cartfl_2k %>%\n",
    "     ggplot(aes(participation,connectivity,color=role)) +\n",
    "     geom_text(aes(label = name), size = 3.5) +\n",
    "     geom_point(alpha=0.5, size=2) +\n",
    "     labs(y=\"Within-module connectivity z-score\", x=\"Participation coefficient (P)\")\n",
    "\n",
    "\n",
    "#################### Figure 3d,e,f Temporal network analysis with package tsna #####################\n",
    "\n",
    "############################################################################################################################\n",
    "# https://programminghistorian.org/en/lessons/temporal-network-analysis-with-r#packages-for-temporal-network-analysis\n",
    "# https://cran.r-project.org/web/packages/tsna/vignettes/tsna_vignette.html\n",
    "# https://rpubs.com/vitorks/723233\n",
    "############################################################################################################################\n",
    "\n",
    "library(sna)\n",
    "library(tsna)\n",
    "library(ndtv)\n",
    "\n",
    "######### Reconstruct the static network \n",
    "\n",
    "PHStaticEdges <- read.csv('microbiome_StaticEdgelist_progressing.csv', stringsAsFactors = FALSE)\n",
    "PHVertexAttributes <- read.csv('microbiome_VertexAttributes_progressing.csv', stringsAsFactors = FALSE, header = TRUE)\n",
    "\n",
    "thenetwork <- network(\n",
    "  PHStaticEdges,\n",
    "  vertex.attr = PHVertexAttributes,\n",
    "  vertex.attrnames = c(\"vertex.id\",\"name\"),\n",
    "  directed = FALSE,\n",
    "  bipartite = FALSE\n",
    ")\n",
    "\n",
    "plot(thenetwork)\n",
    "\n",
    "### Import Temporal Network Data\n",
    "\n",
    "PHDynamicNodes <- read.csv('microbiome_DynamicNodes_progressing.csv', header = TRUE, stringsAsFactors = FALSE)\n",
    "PHDynamicEdges <- read.csv('microbiome_DynamicEdges_progressing.csv', header = TRUE, stringsAsFactors = FALSE)\n",
    "\n",
    "### Reconstruct the temporal network\n",
    "\n",
    "dynamicCollabs <- networkDynamic(\n",
    "  thenetwork,\n",
    "  edge.spells = PHDynamicEdges,\n",
    "  vertex.spells = PHDynamicNodes\n",
    ")\n",
    "\n",
    "### Plot formation of edges over time\n",
    "\n",
    "plot(tEdgeFormation(dynamicCollabs, time.interval = 1))\n",
    "\n",
    "\n",
    "### Calculate and graph the rolling betweenness centralization of the network\n",
    "\n",
    "dynamicBetweenness <- tSnaStats(dynamicCollabs, snafun = \"centralization\", start = 0, end = 18, time.interval = 1, aggregate.dur = 2, FUN = \"betweenness\")\n",
    "\n",
    "plot(dynamicBetweenness)\n",
    "\n",
    "\n",
    "dynamicDegree <- tSnaStats( dynamicCollabs, snafun = \"centralization\", start = 0, end = 18, time.interval = 1, aggregate.dur = 2, FUN = \"degree\")\n",
    "\n",
    "plot(dynamicDegree)\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cardiovascular-appreciation",
   "metadata": {},
   "outputs": [],
   "source": [
    "####################  Dynamics of species over time. Figure 4a,b\n",
    "\n",
    "#######################################################################################################################################################\n",
    "# https://cran.r-project.org/web/packages/codyn/vignettes/Community_Stability_Metrics.html\n",
    "# https://cran.r-project.org/web/packages/codyn/vignettes/Temporal_Diversity_Indices.html\n",
    "#######################################################################################################################################################\n",
    "\n",
    "library(codyn)\n",
    "library(ggplot2)\n",
    "library(cowplot)\n",
    "library(ggpubr)\n",
    "\n",
    "########## Generate CODIN table from OTUS.csv in R\n",
    "\n",
    "OTUS1 <- read.csv(\"OTUS_codyn.csv\")\n",
    "\n",
    "codyn_table<-gather(OTUS1, key = \"Sample_ID\", value = \"measurement\", -Species)\n",
    "\n",
    "write.csv(codyn_table, file = \"OTUS_codyn.csv\")\n",
    "\n",
    "codyndata<-read.csv('OTUS_codyn.csv', header = TRUE, row.names = 1)\n",
    "\n",
    "### Species rank clocks (Figure 4a)\n",
    "\n",
    "### We selected the subset of species with >10% frequency in samples selected in Figure 1b.\n",
    "\n",
    "aggdat <- aggregate(abundance ~ species * time * replicate, \n",
    "                    data = subset(codyndata, \n",
    "                                      species == \"Actinomyces_naeslundii\" |\n",
    "                                      species == \"Actinomyces_oris\" |\n",
    "                                      species == \"Actinomyces_sp._oral_taxon_170\" |\n",
    "                                      species == \"Actinomyces_sp._oral_taxon_171\" |\n",
    "                                      species == \"Actinomyces_sp._oral_taxon_448\" |\n",
    "                                      species == \"Aggregatibacter_actinomycetemcomitans\"|\n",
    "                                      species == \"Anaeroglobus_geminatus\" | \n",
    "                                      species == \"Bacteroidetes_bacterium_oral_taxon_272\" |\n",
    "                                      species == \"Bifidobacterium_longum\" | \n",
    "                                      species == \"Brevundimonas_diminuta\" | \n",
    "                                      species == \"Comamonas_testosteroni\"| \n",
    "                                      species == \"Corynebacterium_durum\"| \n",
    "                                      species == \"Dialister_invisus\" |\n",
    "                                      species == \"Dialister_micraerophilus\" |\n",
    "                                      species == \"Dietzia_sp._oral_taxon_368\" |\n",
    "                                      species == \"Eggerthia_catenaformis\" |\n",
    "                                      species == \"Fusobacteria_bacterium_oral_taxon_220\" |\n",
    "                                      species == \"Fusobacterium_naviforme\" |\n",
    "                                      species == \"Fusobacterium_necrophorum\" |\n",
    "                                      species == \"Fusobacterium_nucleatum\" | \n",
    "                                      species == \"Fusobacterium_periodonticum\"| \n",
    "                                      species == \"Gemella_morbillorum\" |\n",
    "                                      species == \"Haemophilus_haemolyticus\" |\n",
    "                                      species == \"Haemophilus_sp._oral_taxon_036\" |\n",
    "                                      species == \"Lactobacillus_casei\" |\n",
    "                                      species == \"Lactobacillus_crispatus\" |\n",
    "                                      species == \"Lactobacillus_fermentum\" |\n",
    "                                      species == \"Lactobacillus_gasseri\" |\n",
    "                                      species == \"Lactobacillus_panis\" |\n",
    "                                      species == \"Lactobacillus_paracasei\" |\n",
    "                                      species == \"Lactobacillus_rhamnosus\" |\n",
    "                                      species == \"Lactococcus_lactis\" |\n",
    "                                      species == \"Neisseria_elongata\" |\n",
    "                                      species == \"Plectosphaerella_sp.\" |\n",
    "                                      species == \"Polyporales_sp.\" |\n",
    "                                      species == \"Prevotella_sp._oral_taxon_300\" |\n",
    "                                      species == \"Prevotella_sp._oral_taxon_314\" |\n",
    "                                      species == \"Schaalia_meyeri\" |\n",
    "                                      species == \"Streptococcus_cristatus\" |\n",
    "                                      species == \"Streptococcus_dysgalactiae\" |\n",
    "                                      species == \"Streptococcus_mutans\" |\n",
    "                                      species == \"Streptococcus_parasanguinis\" |\n",
    "                                      species == \"Streptococcus_salivarius\" |\n",
    "                                      species == \"Streptococcus_sinensis\" |\n",
    "                                      species == \"Streptococcus_sp._oral_taxon_058\" |\n",
    "                                      species == \"Streptococcus_sp._oral_taxon_064\" |\n",
    "                                      species == \"Streptococcus_vestibularis\" |\n",
    "                                      species == \"Tannerella_forsythia\" |\n",
    "                                      species == \"Treponema_denticola\" |\n",
    "                                      species == \"Veillonella_sp._oral_taxon_158\" |\n",
    "                                      species == \"Xanthomonas_sp._oral_taxon_037\") ,\n",
    "                    FUN = mean)\n",
    "\n",
    "\n",
    "ggplot(aggdat, aes(time, abundance, color = species)) + \n",
    "     geom_line(size = 1) + coord_polar() + theme_bw() + facet_wrap(~replicate) +\n",
    "     ggtitle(\"Dominant species abundances\"\n",
    "\n",
    "\n",
    "### Mean rank shifts (Figure 4b)\n",
    "\n",
    "KNZ_rankshift <- rank_shift(df=codyndata, time.var = \"time\", species.var = \"species\", abundance.var = \"abundance\", replicate.var = \"replicate\")\n",
    "\n",
    "KNZ_rankshift$time <- abs(as.numeric((substr(KNZ_rankshift$year_pair, 3,9))))\n",
    "\n",
    "ggplot(KNZ_rankshift, aes(time, MRS, color=replicate)) + \n",
    " geom_line(size= 1) + theme_bw()\n",
    "\n",
    "### Rate of community change (Figure 4c and d)\n",
    "\n",
    "rate.res <- rate_change(codyndata, time.var= \"time\", species.var= \"species\", abundance.var= \"abundance\", replicate.var = \"replicate\")\n",
    "\n",
    "write.csv(rate.res, file = 'Rate_of_community_ change.csv')\n",
    "\n",
    "\n",
    "comm.res <- rate_change_interval(codyndata, time.var = \"time\",species.var = \"species\", abundance.var = \"abundance\",replicate.var = \"replicate\")\n",
    "\n",
    "ggplot(comm.res, aes(interval, distance, color = replicate)) + facet_wrap(~replicate) + \n",
    " geom_point() + theme_bw() + stat_smooth(method = \"lm\", se = F, size = 1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a57974e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure 5 a,b,c and Figure S5. Cluster different species' trajectories using the Dirichlet process Gaussian process mixture model (DPGP) software\n",
    "\n",
    "### First obtain the mean count for each species at each time point\n",
    "### Format of input is, where the first row represent the time points\n",
    "\n",
    "         |0   |1   |2   |3   |4   |5   |6    |7\n",
    "species_0|1.49|0.36|2.44|0.15|2.14|4.58|1.60|0.73\n",
    "species_1|1.39|0.41|2.64|0.06|1.71|4.54|1.72|0.83\n",
    "species_2|1.63|0.56|2.92|0.25|2.13|4.22|1.95|0.88\n",
    "species_3|1.44|0.47|2.51|0.07|2.24|4.78|1.61|1.04\n",
    "….\n",
    "\n",
    "### In R\n",
    "\n",
    "Data<-read.table('condition_means.txt', header=TRUE, row.names=1) ### Condition: stable, progressing or fluctuating.\n",
    "\n",
    "### Standardized to zero mean and unit variance centering with 'scale()'.\n",
    "\n",
    "center_scale <- function(x) {\n",
    "    scale(x, scale = TRUE)\n",
    "}\n",
    "centered<-center_scale(Data)\n",
    "write.table(centered, file = \"condition_centered.txt\", sep='\\t') ## This file is the input for the next step\n",
    "\n",
    "### In DPGP bin/ folder.  DPGP can be obtained at:\n",
    "### https://github.com/PrincetonUniversity/DP_GP_cluster\n",
    "\n",
    "### Before proceding to the analsys you should remove all 0 rows\n",
    "\n",
    "$ bin/DP_GP_cluster.py -i condition_centered.txt  -o ./stable --true_times --optimizer scg -a 0.5 -c MPEAR -n 1000 --save_cluster_GPs  -p svg –plot\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "loose-cowboy",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure 5d,e,f. Measurements of stability, variance ratio, and synchrony. Community stability metrics\n",
    "### In R\n",
    "\n",
    "library(codyn)\n",
    "library(knitr)\n",
    "\n",
    "stability <- community_stability(codyndata, time.var = \"time\", abundance.var = \"abundance\", replicate.var = \"replicate\")\n",
    "write.csv(stability, file = 'Stability.csv')\n",
    "\n",
    "### Species covariance \n",
    "\n",
    "variance_ratio <- variance_ratio(df = codyndata, species.var = \"species\", time.var = \"time\", abundance.var = \"abundance\", bootnumber = 1000, replicate.var = \"replicate\")\n",
    "write.csv(variance_ratio, file = 'Variance_ratio.csv')\n",
    "\n",
    "variance_ratio_avgrep <- variance_ratio(codyndata, time.var = \"time\",species.var = \"species\", abundance.var = \"abundance\", bootnumber = 1000, replicate.var = \"replicate\", average.replicates = FALSE)\n",
    "write.csv(variance_ratio_avgrep, file = 'Variance_ratio_avgrep.csv')\n",
    "\n",
    "### Species synchrony\n",
    "\n",
    "synchrony_Loreau <- synchrony(df = codyndata, time.var = \"time\", species.var = \"species\", abundance.var = \"abundance\", replicate.var = \"replicate\")\n",
    "\n",
    "write.csv(synchrony_Loreau, file = 'Species_synchrony_Loreau.csv')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "important-iraqi",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure 6. Phylodiversity accumulation and model fitting in the three datasets.\n",
    "### In R\n",
    "### Figure 5a,b,c\n",
    "\n",
    "library(\"ape\")\n",
    "library(\"ggplot2\")\n",
    "library(\"parallel\")\n",
    "source(\"assembly_model_functions.r\")\n",
    "\n",
    "tree_raw <- read.tree(\"ssu-otus-align.nwk\") ### Tree from the aligment of the sequences in the database\n",
    "otutable_raw <- read.table(\"OTUS.txt\", sep = '\\t', header = T,   row.names = 1)\n",
    "metadata_raw <- read.table(\"sample-metadata.txt\", stringsAsFactors = F,  sep='\\t', header = T, row.names = 1)\n",
    "\n",
    "\n",
    "inputs <- prep_check_inputs(\n",
    "     otutable = otutable_raw,\n",
    "     metadata = metadata_raw,\n",
    "     md_order_col=4,\n",
    "     tree = tree_raw,\n",
    "     distmat=NULL, rarefy=TRUE, rare_depth=500,\n",
    "     merge_tree_0dists=TRUE, drop_unobserved_otus=TRUE,\n",
    ")\n",
    "\n",
    "stable_inputs <- subset_inputs(\n",
    "     inputs_list = inputs,\n",
    "     sub_tf = inputs$metadata$group == \"stable\",\n",
    "     name=\"stable\"\n",
    ")\n",
    "\n",
    "progressing_inputs <- subset_inputs(\n",
    "     inputs_list = inputs,\n",
    "     sub_tf = inputs$metadata$group == \"progressing\",\n",
    "     name=\"progressing\"\n",
    ")\n",
    "\n",
    "fluctuating_inputs <- subset_inputs(\n",
    "     inputs_list = inputs,\n",
    "     sub_tf = inputs$metadata$group == \"fluctuating\",\n",
    "     name=\"fluctuating\"\n",
    ")\n",
    "\n",
    "results_stable <- pd_assemb_workflow(\n",
    "     inputs_i = stable_inputs,\n",
    "     n_dispersions=1000,\n",
    "     n_neutral_sim=1000,\n",
    "     ncores = 40\n",
    ")\n",
    "\n",
    "results_progressing <- pd_assemb_workflow(\n",
    "     inputs_i = progressing_inputs,\n",
    "     n_dispersions=1000,\n",
    "     n_neutral_sim=1000,\n",
    "     ncores = 40\n",
    ")\n",
    "\n",
    "results_fluctuating <- pd_assemb_workflow(\n",
    "     inputs_i = fluctuating_inputs,\n",
    "     n_dispersions=1000,\n",
    "     n_neutral_sim=1000,\n",
    "     ncores = 40\n",
    ")\n",
    "\n",
    "plot_dispersion_ests_violin(list(results_stable, results_progressing,results_fluctuating))\n",
    "\n",
    "### Figure 6d. Testing against alternative “individual null”. Example ‘progressing’ \n",
    "### In R\n",
    "\n",
    "source(\"alt_null_functions.r\") ## This r function is included in the submission.\n",
    "Nperm <- 5000\n",
    "\n",
    "# define m, which is midpoint sample index. See paper for more details.\n",
    "m <- round(ncol(progressing_inputs$otutable)/2)\n",
    "\n",
    "# get vector of nperm null PDs\n",
    "ind_nuls <- replicate(nperm, indiv_null(progressing_inputs$otutable, progressing_inputs$tree, nsamp=m))\n",
    "\n",
    "# get empirical PD\n",
    "emp <- one_sample_pd(progressing_inputs$cum_otutable[,m], ids=rownames(progressing_inputs$cum_otutable), tree=progressing_inputs$tree)\n",
    "\n",
    "# calculate P-value\n",
    "pval <- (sum(ind_nuls < emp) + 1) / length(ind_nuls)\n",
    "pval"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "adopted-eight",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure S2 ARIMA\n",
    "### Augmented Dickey-Fuller Test of stationarity \n",
    "### In R\n",
    "\n",
    "library(tseries)\n",
    "library(astsa)\n",
    "library(aTSA)\n",
    "\n",
    "x<-read.csv('stable.csv', header = TRUE) ### stable.csv contains the observed values of CAL\n",
    "y<-x[,4]  ### select columns with the average values\n",
    "y<-y[!is.na(y)] ### remove NAs\n",
    "adf.test(y, alternative = 'stationary') ## p > 0.05 is non-stationary\n",
    "\n",
    "\n",
    "### We transformed the series into stationary on the values for non-stationary series by subtracting CALt-1 from CALt for all values t. This technique is called differencing and can be done with the ‘diff’ function of the aTSA package.\n",
    "\n",
    "\n",
    "### Stationary time-series. We applied the ARIMA model for stationary series directly. \n",
    "\n",
    "x<-read.csv('boxplot_stable.csv', header = TRUE)\n",
    "y<-x[,4]  ### select columns with the average values\n",
    "y<-y[!is.na(y)]\n",
    "y<-ts(y)\n",
    "plot(y)\n",
    "gtemp=y\n",
    "sarima.for(gtemp,5,1,1,1) ## ARIMA model is (1,1,1)\n",
    "\n",
    "### Non-stationary time-series\n",
    "\n",
    "x<-read.csv('boxplot_progressing.csv', header = TRUE)\n",
    "y<-x[,4]  ### select columns with the average values\n",
    "y<-y[!is.na(y)]\n",
    "y=diff(y,differences = 1) ## We transformed the series into stationary on the values for non-stationary series by subtracting CALt-1 from CALt for all values t. This technique is called differencing\n",
    "y<-ts(y)\n",
    "plot(y)\n",
    "gtemp=y\n",
    "sarima.for(gtemp,5,0,1,1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "facial-contents",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure S3a. Alpha diversity \n",
    "### In R\n",
    "\n",
    "library(microbiomeSeq)\n",
    "library(phyloseq)\n",
    "\n",
    "otus<-read.csv('OTUS.csv', header = TRUE, row.names = 1)\n",
    "otus = t(otus)\n",
    "taxmat<-read.csv(\"taxmat.csv\", header = TRUE, row.names = 1)\n",
    "samples<-read.csv(\"pitlatrine2.csv\", header = TRUE, row.names =1)\n",
    "\n",
    "taxmat<-as.matrix(taxmat)\n",
    "otus<-as.matrix(otus)\n",
    "\n",
    "OTU = otu_table(otus, taxa_are_rows = FALSE)\n",
    "TAX = tax_table(taxmat)\n",
    "SAM = sample_data(samples)\n",
    "\n",
    "physeq = phyloseq(OTU, TAX, SAM) ### generate phyloseq object\n",
    "\n",
    "random_tree = rtree(ntaxa(physeq), rooted=TRUE, tip.label=taxa_names(physeq))\n",
    "\n",
    "physeq = phyloseq(OTU, TAX, SAM, random_tree)\n",
    "\n",
    "\n",
    "sample_data(physeq)$group = as.character(sample_data(physeq)$group)\n",
    "get_variable(physeq,\"group\")\n",
    "\n",
    "p <- plot_anova_diversity(physeq, method = c(\"richness\", \"fisher\"), grouping_column = \"condition\", pValueCutoff = 0.05)\n",
    "print(p)\n",
    "\n",
    "############# Figure S3b. Alpha diversity \n",
    "p <- plot_anova_diversity(physeq, method = c(\"shannon\"), grouping_column = \"grouptime\", pValueCutoff = 0.05)\n",
    "print(p)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3688a48",
   "metadata": {},
   "outputs": [],
   "source": [
    "############# Figure S4. Ordination and β-dispersion. \n",
    "### In R\n",
    "\n",
    "library(microbiome) # data analysis and visualisation\n",
    "library(phyloseq) # also the basis of data object. Data analysis and visualisation\n",
    "library(RColorBrewer) # nice color options\n",
    "library(ggpubr) # publication quality figures, based on ggplot2\n",
    "library(dplyr) # data handling\n",
    "library(ape)\n",
    "library(vegan)\n",
    "\n",
    "otus<-read.csv('OTUS.csv', header = TRUE, row.names = 1)\n",
    "otus = t(otus)\n",
    "taxmat<-read.csv(\"taxmat.csv\", header = TRUE, row.names = 1)\n",
    "samples<-read.csv(\"Sample_data.csv\", header = TRUE, row.names =1)\n",
    "samples$time=factor(samples$time)\n",
    "\n",
    "taxmat<-as.matrix(taxmat)\n",
    "otus<-as.matrix(otus)\n",
    "\n",
    "\n",
    "OTU = otu_table(otus, taxa_are_rows = FALSE)\n",
    "TAX = tax_table(taxmat)\n",
    "SAM = sample_data(samples)\n",
    "\n",
    "physeq = phyloseq(OTU, TAX, SAM) ### generate phyloseq object\n",
    "\n",
    "random_tree = rtree(ntaxa(physeq), rooted=TRUE, tip.label=taxa_names(physeq))\n",
    "\n",
    "physeq = phyloseq(OTU, TAX, SAM, random_tree)\n",
    "\n",
    "\n",
    "ps1=physeq\n",
    "ps1.rel <- microbiome::transform(ps1, \"compositional\") ### Normalized counts\n",
    "        \n",
    "######################## Ordination\n",
    "\n",
    "### For Bray-Curtis, Jaccard substitute the method\n",
    "\n",
    "ordu.wt.uni <- ordinate(ps1.rel , \"PCoA\", \"unifrac\", weighted=T)\n",
    "\n",
    "wt.unifrac <- plot_ordination(ps1.rel, \n",
    "                              ordu.wt.uni, color=\"group\") \n",
    "wt.unifrac <- wt.unifrac + ggtitle(\"Weighted UniFrac\") + geom_point(size = 3)\n",
    "wt.unifrac <- wt.unifrac + theme_classic() + scale_color_brewer(\"Location\", palette = \"Set2\")\n",
    "print(wt.unifrac)\n",
    "\n",
    "print(wt.unifrac + stat_ellipse())\n",
    "\n",
    "\n",
    "############################## Permanova Unifrac ##############################\n",
    "\n",
    "metadf <-as.data.frame(samples)\n",
    "unifrac.dist <- UniFrac(ps1.rel, \n",
    "                        weighted = TRUE, \n",
    "                        normalized = TRUE,  \n",
    "                        parallel = FALSE, \n",
    "                        fast = TRUE)\n",
    "\n",
    "\n",
    "permanova <- adonis2(unifrac.dist ~ group, data = metadf)\n",
    "\n",
    "permanova\n",
    "\n",
    "############## Permanova in the case of Bray-Curtis and Jaccard ################\n",
    "\n",
    "x=otu_table(ps1.rel)\n",
    "\n",
    "bray.dist = vegdist(x, method=\"bray\", binary=FALSE)\n",
    "\n",
    "permanova <- adonis2(bray.dist ~ group, data = metadf)\n",
    "\n",
    "permanova\n",
    "\n",
    "#####\n",
    "\n",
    "x=otu_table(ps1.rel)\n",
    "\n",
    "jaccard.dist = vegdist(x, method=\"jaccard\", binary=FALSE)\n",
    "\n",
    "permanova <- adonis2(jaccard.dist ~ group, data = metadf)\n",
    "\n",
    "permanova\n",
    "\n",
    "\n",
    "\n",
    "############################## Beta-dispersion ###############################################\n",
    "\n",
    "ps.disper <- betadisper(bray.dist, metadf$group,type = \"centroid\", bias.adjust = TRUE)\n",
    "permutest(ps.disper, pairwise = TRUE)\n",
    "\n",
    "ps.disper <- betadisper(jaccard.dist, metadf$group,type = \"centroid\", bias.adjust = TRUE)\n",
    "permutest(ps.disper, pairwise = TRUE)\n",
    "\n",
    "ps.disper <- betadisper(unifrac.dist, metadf$group, type = \"centroid\", bias.adjust = TRUE) \n",
    "permutest(ps.disper, pairwise = TRUE)\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
