Growth curve
Last updated:
This tutorial is for converting your plate reader data into growth curves in R. Since the Cooper lab has two different plate readers with difference version of the software, be sure to check which plate reader software was used before proceeding. I have divided the tutorial based on the old vs newer program.
Note: If doing growth curves on the Tecan, skip to the section on data manipulation from Tecan
The plate reader with the newer program is located by the centrifuge next to the chemical hood while the plate reader with the older program is located by the entrance.
Load libraries and data files
Newer program
Make sure to have a csv file of your plate reader output. You can do this by first downloading the data as an Excel (.xls) file, then clicking “Save as” to change it into a csv file. Click here to download the example csv file if you would like to follow along. Check your file path of your csv file, as this will be different from mine:
file <- "/Users/kubotan/Downloads/new_plate_reader_data.csv" #filepath of your csv file
p <- read.csv(file,header=T,skip=2) #read the csv as a dataframe and skip the first row
Check to make sure your dataframe looks like this when using the head() function:
head(p) #view first few rows of dataframe
## Time Temperature..C. A1 A2 A3 A4 A5 A6 A7
## 1 0:00:00 24.1 0.0834 0.0869 0.0869 0.0867 0.0871 0.0878 0.0874
## 2 0:15:00 36.2 0.0832 0.0866 0.0868 0.0867 0.0871 0.0878 0.0872
## 3 0:30:00 37.0 0.0846 0.0865 0.0937 0.0863 0.0872 0.0876 0.0871
## 4 0:45:00 37.0 0.0848 0.0868 0.0853 0.0865 0.0877 0.0886 0.0869
## 5 1:00:00 37.0 0.0852 0.0866 0.0868 0.0868 0.0879 0.0893 0.0871
## 6 1:15:00 37.0 0.0851 0.0868 0.0868 0.0866 0.0879 0.0884 0.0873
## A8 A9 A10 A11 A12 B1 B2 B3 B4 B5 B6
## 1 0.0875 0.0865 0.0869 0.0874 0.0862 0.0960 0.0990 0.0980 0.0980 0.0986 0.0991
## 2 0.0876 0.0862 0.0865 0.0872 0.0861 0.0944 0.0989 0.0962 0.0963 0.0970 0.0974
## 3 0.0874 0.0861 0.0864 0.0873 0.0860 0.0981 0.0997 0.0975 0.0974 0.0986 0.0981
## 4 0.0875 0.0863 0.0867 0.0873 0.0861 0.1060 0.1021 0.0979 0.0994 0.1041 0.1000
## 5 0.0875 0.0862 0.0866 0.0870 0.0862 0.1093 0.1058 0.1024 0.1023 0.1081 0.1022
## 6 0.0878 0.0865 0.0865 0.0874 0.0864 0.1125 0.1162 0.1070 0.1097 0.1176 0.1072
## B7 B8 B9 B10 B11 B12 C1 C2 C3 C4 C5
## 1 0.0992 0.1083 0.0980 0.0971 0.0987 0.0957 0.0996 0.0988 0.0980 0.1015 0.0975
## 2 0.0969 0.1050 0.0966 0.0953 0.0968 0.0947 0.0968 0.0960 0.0954 0.0979 0.0949
## 3 0.0976 0.1076 0.0973 0.0959 0.0971 0.0952 0.1023 0.0987 0.0981 0.1011 0.0977
## 4 0.0994 0.1147 0.0995 0.0974 0.0994 0.0964 0.1053 0.1013 0.0991 0.1038 0.1003
## 5 0.1015 0.1280 0.1024 0.0999 0.1016 0.0990 0.1103 0.1049 0.1042 0.1083 0.1037
## 6 0.1079 0.1396 0.1096 0.1032 0.1051 0.1015 0.1182 0.1117 0.1110 0.1184 0.1102
## C6 C7 C8 C9 C10 C11 C12 D1 D2 D3 D4
## 1 0.0990 0.0981 0.0983 0.0976 0.0988 0.0997 0.0984 0.0912 0.0936 0.0927 0.0927
## 2 0.0962 0.0956 0.0953 0.0947 0.0958 0.0967 0.0962 0.0909 0.0934 0.0926 0.0924
## 3 0.0991 0.0981 0.0980 0.0970 0.0988 0.0988 0.0983 0.0931 0.0938 0.0930 0.0928
## 4 0.1017 0.1007 0.1003 0.0994 0.1011 0.1014 0.1008 0.0943 0.0948 0.0923 0.0935
## 5 0.1054 0.1042 0.1036 0.1026 0.1048 0.1041 0.1033 0.0953 0.0955 0.0950 0.0945
## 6 0.1112 0.1106 0.1099 0.1089 0.1102 0.1097 0.1076 0.0966 0.0970 0.0964 0.0962
## D5 D6 D7 D8 D9 D10 D11 D12 E1 E2 E3
## 1 0.0926 0.0924 0.0920 0.0926 0.0932 0.0931 0.0941 0.0989 0.0992 0.1021 0.1013
## 2 0.0922 0.0922 0.0921 0.0922 0.0928 0.0933 0.0943 0.0942 0.0963 0.0997 0.0996
## 3 0.0926 0.0933 0.0930 0.0929 0.0932 0.0938 0.0948 0.0949 0.0971 0.0987 0.0987
## 4 0.0937 0.0936 0.0942 0.0938 0.0939 0.0948 0.0959 0.0961 0.0972 0.0985 0.0968
## 5 0.0950 0.0945 0.0955 0.0949 0.0949 0.0958 0.0969 0.0973 0.0972 0.0982 0.0977
## 6 0.0964 0.0959 0.0970 0.0964 0.0966 0.0971 0.0988 0.0988 0.0972 0.0987 0.0982
## E4 E5 E6 E7 E8 E9 E10 E11 E12 F1 F2
## 1 0.1032 0.0991 0.0996 0.1002 0.1016 0.0996 0.1013 0.1363 0.1015 0.0920 0.0936
## 2 0.1003 0.0999 0.0972 0.0975 0.0993 0.0982 0.0999 0.0996 0.1003 0.0909 0.0924
## 3 0.0995 0.1361 0.0963 0.0969 0.0985 0.0976 0.0994 0.0991 0.0998 0.0926 0.0923
## 4 0.0988 0.1012 0.0960 0.0968 0.0980 0.0974 0.0989 0.0987 0.0992 0.0933 0.0926
## 5 0.0988 0.0995 0.0962 0.0968 0.0982 0.0971 0.0992 0.0987 0.0992 0.0942 0.0932
## 6 0.0993 0.1002 0.0964 0.0970 0.0984 0.0975 0.0991 0.0992 0.0997 0.0950 0.0941
## F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 G1
## 1 0.0970 0.0945 0.0927 0.0915 0.0961 0.0929 0.0933 0.0942 0.0937 0.0933 0.0976
## 2 0.0959 0.0938 0.0923 0.0913 0.0992 0.0917 0.0919 0.0930 0.0928 0.0926 0.0962
## 3 0.0959 0.0939 0.0919 0.0915 0.1036 0.0918 0.0922 0.0931 0.0926 0.0923 0.0967
## 4 0.0948 0.0940 0.0926 0.0916 0.1072 0.0922 0.0922 0.0936 0.0930 0.0924 0.0968
## 5 0.0975 0.0947 0.0927 0.0920 0.1112 0.0927 0.0928 0.0945 0.0937 0.0927 0.0968
## 6 0.0990 0.0956 0.0933 0.0925 0.1142 0.0935 0.0935 0.0956 0.0945 0.0933 0.0967
## G2 G3 G4 G5 G6 G7 G8 G9 G10 G11 G12
## 1 0.1000 0.1026 0.1026 0.0999 0.1975 0.1019 0.1036 0.1000 0.0999 0.1001 0.1005
## 2 0.0979 0.1003 0.1015 0.0980 0.2577 0.1013 0.1016 0.0990 0.0985 0.0985 0.0997
## 3 0.0972 0.0990 0.1010 0.0977 0.1038 0.1003 0.1005 0.0978 0.0978 0.0973 0.0983
## 4 0.0972 0.0976 0.1002 0.0973 0.1038 0.0996 0.0999 0.0999 0.0981 0.0975 0.0976
## 5 0.0970 0.0990 0.1004 0.0973 0.1439 0.0995 0.1000 0.0982 0.0979 0.0975 0.0980
## 6 0.0972 0.0992 0.1009 0.0975 0.1046 0.0995 0.1002 0.0979 0.0980 0.0976 0.1004
## H1 H2 H3 H4 H5 H6 H7 H8 H9 H10 H11
## 1 0.0845 0.0866 0.0868 0.0900 0.0870 0.0872 0.0874 0.0873 0.0885 0.0873 0.0868
## 2 0.0842 0.0863 0.0868 0.0902 0.0869 0.0874 0.0879 0.0872 0.0884 0.0872 0.0867
## 3 0.0856 0.0861 0.0870 0.0900 0.0868 0.0876 0.0877 0.0872 0.0885 0.0872 0.0868
## 4 0.0857 0.0864 0.0855 0.0898 0.0868 0.0876 0.0878 0.0874 0.0887 0.0874 0.0871
## 5 0.0860 0.0864 0.0871 0.0895 0.0868 0.0876 0.0878 0.0873 0.0887 0.0875 0.0869
## 6 0.0856 0.0865 0.0871 0.0900 0.0868 0.0877 0.0878 0.0874 0.0886 0.0875 0.0870
## H12
## 1 0.0862
## 2 0.0860
## 3 0.0861
## 4 0.0863
## 5 0.0865
## 6 0.0864
Now, if you inspect the dataframe, there are a few rows and column that we don’t need (such as the last few rows and the temperature column, respectively).
tail(p) #view last few rows of dataframe
## Time
## 95 23:30:00
## 96 23:45:00
## 97 1.00:00:00
## 98
## 99 ~End
## 100 Original Filename: 2021-08-18 G1 growth curve; Date Last Saved: 8/20/2021 4:15:24 PM
## Temperature..C. A1 A2 A3 A4 A5 A6 A7 A8
## 95 37 0.0855 0.0866 0.0872 0.1047 0.0880 0.0892 0.0886 0.0872
## 96 37 0.0852 0.0871 0.0874 0.0872 0.0882 0.0891 0.0871 0.0870
## 97 37 0.0856 0.0869 0.0968 0.0867 0.0884 0.0891 0.0870 0.0873
## 98 NA NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA NA
## A9 A10 A11 A12 B1 B2 B3 B4 B5 B6
## 95 0.0867 0.0868 0.0876 0.0862 0.8622 0.9900 0.9351 0.9237 0.9251 0.8757
## 96 0.0862 0.0869 0.0873 0.0863 0.8981 0.9959 0.9488 0.9353 0.9298 0.8826
## 97 0.0905 0.0869 0.0871 0.0861 0.8745 0.9972 0.9350 0.9203 0.9350 0.8842
## 98 NA NA NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA NA NA
## B7 B8 B9 B10 B11 B12 C1 C2 C3 C4
## 95 0.8937 0.9997 0.9294 1.0335 0.9385 0.9022 0.7500 0.8158 0.9156 0.8685
## 96 0.9010 1.0152 0.9479 1.0459 0.9515 0.9047 0.7482 0.7974 0.8985 0.8542
## 97 0.9049 1.0208 0.9461 1.0432 0.9538 0.9145 0.7470 0.7983 0.9096 0.8711
## 98 NA NA NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA NA NA
## C5 C6 C7 C8 C9 C10 C11 C12 D1 D2
## 95 0.9890 0.9619 1.0404 1.0468 1.0068 1.0282 0.9749 0.7781 0.6198 0.6001
## 96 0.9496 0.9254 0.9802 0.9823 0.9804 0.9846 0.9549 0.7635 0.6223 0.6006
## 97 0.9682 0.9745 1.0399 1.0467 1.0125 1.0332 0.9952 0.7713 0.6244 0.6001
## 98 NA NA NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA NA NA
## D3 D4 D5 D6 D7 D8 D9 D10 D11 D12
## 95 0.6016 0.5969 0.5928 0.5540 0.5627 0.5594 0.5302 0.5856 0.5943 0.5927
## 96 0.6077 0.5963 0.5933 0.5545 0.5631 0.5570 0.5304 0.5859 0.5933 0.5932
## 97 0.6159 0.5970 0.5943 0.5567 0.5636 0.5578 0.5305 0.5878 0.5947 0.5934
## 98 NA NA NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA NA NA
## E1 E2 E3 E4 E5 E6 E7 E8 E9 E10
## 95 0.4411 0.4356 0.5548 0.5163 0.6492 0.7288 0.6303 0.5958 0.6586 0.6583
## 96 0.4397 0.4349 0.5495 0.5175 0.5991 0.7538 0.6150 0.5893 0.6476 0.6444
## 97 0.4416 0.4389 0.5493 0.5239 0.6650 0.8083 0.6322 0.6033 0.6656 0.6583
## 98 NA NA NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA NA NA
## E11 E12 F1 F2 F3 F4 F5 F6 F7 F8
## 95 0.7231 0.7687 0.8092 0.8199 0.8863 0.8426 0.8036 0.7772 0.7154 0.8184
## 96 0.7042 0.7272 0.8061 0.8189 0.8926 0.8328 0.8042 0.7778 0.7192 0.8176
## 97 0.7373 0.7726 0.8024 0.8319 0.8872 0.8387 0.8100 0.7816 0.7214 0.8277
## 98 NA NA NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA NA NA
## F9 F10 F11 F12 G1 G2 G3 G4 G5 G6
## 95 0.8104 0.9478 0.7935 0.8518 0.4752 0.3847 0.3265 0.3343 0.3439 0.3224
## 96 0.8110 0.9510 0.7982 0.8613 0.4512 0.3918 0.3336 0.3484 0.3500 0.3203
## 97 0.8166 0.9790 0.8169 0.8600 0.4572 0.3933 0.3336 0.3479 0.3533 0.3266
## 98 NA NA NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA NA NA
## G7 G8 G9 G10 G11 G12 H1 H2 H3 H4
## 95 0.3738 0.3525 0.3948 0.4085 0.3699 0.3077 0.0890 0.0866 0.0874 0.0890
## 96 0.3896 0.3465 0.3916 0.4529 0.3582 0.3145 0.0881 0.0869 0.0875 0.0891
## 97 0.3757 0.3477 0.3997 0.3942 0.3614 0.3147 0.0868 0.0867 0.0874 0.0889
## 98 NA NA NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA NA NA
## H5 H6 H7 H8 H9 H10 H11 H12
## 95 0.0870 0.0880 0.0881 0.0883 0.0890 0.0883 0.0875 0.0868
## 96 0.0878 0.0878 0.0879 0.0877 0.0889 0.0882 0.0874 0.1111
## 97 0.0981 0.0880 0.0879 0.0879 0.0889 0.0884 0.0874 0.0871
## 98 NA NA NA NA NA NA NA NA
## 99 NA NA NA NA NA NA NA NA
## 100 NA NA NA NA NA NA NA NA
We will remove the unnecessary rows and columns:
p <- head(p,-3) #remove last few rows
p <- p[,-2] #remove temperature column
We will also relabel the 24 hour time point into hh:mm:ss format:
p[97,which(colnames(p)%in%"Time")] <- c("24:00:00") #run for newer program
Older program
Export your data as a .txt file from the older program. Click here to download the example txt file if you would like to follow along. Make sure to check your file path before reading the data file using the read.delim() function:
file <- "/Users/kubotan/Downloads/old_plate_reader_data.txt"
p <- read.delim(file,header=F,skip = 2)
We will need to clean the dataframe:
p <- read.delim(file,header=F,skip = 2)
pcol <- as.character(unlist(p[1,-c(2,99)])) #extract column name except column 2 and 99
p <- p[-c(1,99),-c(2,99)] #for 24 hr; may need adjustment for 48 hr growth curves
colnames(p) <- pcol
rownames(p) <- 1:97 #for 24 hr; use 1:193 for 48 hr
p[,2:97] <- sapply(p[,2:97],as.numeric)
names(p)[names(p) == "Time(hh:mm:ss)"] <- "Time" #rename Time column
p[1:4,which(colnames(p)%in%"Time")] <- c("0:00:00","0:15:00","0:30:00","0:45:00")
Tecan
The Tecan outputs an Excel file in plate format (rather than column format) so you will need to convert this first before proceeding.
I wrote a python script to do this, and you can download it from my Github. Just click the download button on the top right so start your download.
You can run the script either on Beagle (i.e. Cooper Lab server) or locally on your computer. If you are doing the latter, make sure that you have the following python libraries as they are required to run the script:
- os
- pandas
- numpy
- argparse
On Beagle, you may need to load miniconda-3 before running the script:
module load miniconda/miniconda-3
Then run the script by (make sure your filepath correctly points to the script and your input file):
python3 tecan_plate2column_v2.py -i your_tecan_file.xlsx
Optionally, you can designate the output file name by using the -o or –output parameter.
For more info, run:
python3 tecan_plate2column_v2.py --help
Then make sure to remove the temperature (Temp) and cycle number (Cycle) column in R before moving onto the next section.
file <- "/Users/kubotan/Downloads/tecan_plate2column.csv" #filepath of your csv file
p <- read.csv(file,header=T) #read the csv as a dataframe
p <- p[, !(names(df) %in% c("Temp", "Cycle"))]
96-well plate key
Make sure you make your own spreadsheet that tells you which well in your 96-well plate contained which samples. The general format of your spreadsheet should look like this, where the first column is your well and your second column is your sample name:
A1 | Strain1 |
A2 | Strain1 |
A3 | Strain1 |
A4 | Strain2 |
A5 | Strain2 |
A6 | Strain2 |
A7 | Strain3 |
A8 | Strain3 |
A9 | Strain3 |
A10 | blank |
A11 | blank |
A12 | blank |
B1 | Strain1 |
B2 | Strain1 |
B3 | Strain1 |
. . . |
. . . |
H12 | blank |
You do not need a header, and you should denote your blank wells (i.e. your control wells that you will normalize to) as “blank” with a lowercase b. You should have 2 columns and a total of 96 rows in your spreadsheet that starts from A1 and ends with H12. Save this spreadsheet as a csv file. An example of this key spreadsheet can found by clicking here (a download prompt will begin).
Read the key into R:
k <- "/Users/kubotan/Downloads/plate_reader_key.csv"
key <- read.csv(k,header=F) #key to denote what samples are in each well
Graph the growth curves
You will need the following libraries to graph the growth curves.
library(ggplot2)
library(reshape2)
library(RColorBrewer)
Then we will rename the columns with the sample name by using a for loop:
for (i in 2:ncol(p)) {
well <- colnames(p)[i]
num <- which(key[,1]%in%well)
colnames(p)[i] <- as.character(key[num,2])
}
Then we will take the readings from the blank wells and average them:
blank <- p[,which(colnames(p)%in%"blank")]
indx <- sapply(blank, is.factor)
blank[indx] <- lapply(blank[indx], function(x) as.numeric(as.character(x)))
blank_mean <- data.frame(Time=p[,1],Means=rowMeans(blank,na.rm=TRUE))
pdata <- p[,-which(colnames(p)%in%"blank")]
pdata$blank_mean <- blank_mean[,2] #name new column blank_mean with average of all blanks
Then we will take the average of the blank wells and normalize the rest of the wells by subtracting the average from the rest of the wells:
pcal <- pdata
for (i in 2:ncol(pdata)) {
pcal[,i] <- as.numeric(as.character(pdata[,i]))-as.numeric(as.character(pdata$blank_mean))
}
pclean <- pcal[,-which(colnames(pcal)%in%"blank_mean")]
pclean$Time <- p[,1]
Finally, we will convert the Time column into decimals, so that it can be plotted across the x-axis:
pclean$Time <- as.factor(pclean$Time)
pclean$Time_convert <- unlist(lapply(lapply(strsplit(as.character(pclean$Time), ":"), as.numeric), function(x) x[1]+x[2]/60))
pclean2 <- pclean[,!names(pclean) %in% c("Time")]
pclean2 <- pclean2[,!names(pclean2) %in% c("Time(hh:mm:ss)")] #only for older program?
pmelt <- melt(pclean2,id.vars="Time_convert") #melt dataframe
pmelt$strain <- gsub("\\..*","",pmelt$variable) #remove numbers from strain names
Then we can plot our growth curves using ggplot:
ggplot(pmelt,aes(x=Time_convert, y=value, group=variable, color=strain))+
theme_bw() +
geom_line()+
scale_y_continuous(trans = 'log10')+ #use for log scale
xlab("Time (hrs)") + ylab("OD")+
xlim(0,24)+
facet_wrap(~strain)+ #facet_wrap(~strain,ncol=2)
theme(legend.position="none")
Your graph should look something like this:
If you would like an average of all your data points and just show errorbars, first create a function that calculates the average and standard deviation of the OD readings:
data_summary <- function(data, varname, groupnames){
require(plyr)
summary_func <- function(x, col){
c(mean = mean(x[[col]], na.rm=TRUE),
sd = sd(x[[col]], na.rm=TRUE))
}
data_sum<-ddply(data, groupnames, .fun=summary_func,
varname)
data_sum <- plyr::rename(data_sum, c("mean" = varname))
return(data_sum)
}
Then run this function on your dataframe:
df <- data_summary(pmelt,varname = "value",groupnames = c("strain","Time_convert"))
Finally, lets use the R Color Brewer package to color our plot by strain and graph it using ggplot:
gc_avg2 <- ggplot(df, aes(x=Time_convert, y=value, group=strain, color=strain)) +
geom_errorbar(aes(ymin=value-sd, ymax=value+sd), width=.1,position=position_dodge(0.05)) +
geom_line() +
scale_color_manual(values=col)+ #values=cols[2:1]
scale_y_continuous(trans = 'log10')+ #use for log scale
labs(color = "Strains", x="Time (hrs)", y="OD")+
theme_bw()+
theme(legend.position = "top")
Your plot should look something like this:
Statistical analysis
Calculating stats (Growthcurver)
To perform quantitative comparisons between your strains, we will calculate the growth rate, the area under the curve (AUC), and the final OD (carrying capacity) of each strain. For this we will use the Growthcurver package in R.
library(growthcurver)
We will go back to our pdata dataframe and make a new dataframe called gc_p:
gc_p <- pdata
This is so that we can have an identical copy to work with just in case we need to go back to pdata. We also want to use pdata instead of our other dataframes that we cleaned because we want the raw OD values and not the values that already have the mean of the blank wells subtracted from.
Next, rename the blank_mean column to blank. This is done because the Growthcurver package knows to look for a column name “blank” to use as the blank. If we had a different column name, it wouldn’t know where to look.
names(gc_p)[names(gc_p) == 'blank_mean'] <- 'blank'
Convert your time column into decimals:
#loop to convert >24h format
gc_p$Time <- as.factor(gc_p$Time)
gc_p$Time <- unlist(lapply(lapply(strsplit(as.character(gc_p$Time), ":"), as.numeric), function(x) x[1]+x[2]/60))
We are now ready to run calculations. Do this using the following line of code:
gc_out <- SummarizeGrowthByPlate(gc_p,bg_correct = "blank")
Finally, lets clean up some of the strain names and remove the blank row (i.e. the last row):
gc_out$sample <- gsub("\\..*","",gc_out$sample)
gc_out <- head(gc_out, -1) #remove last row (i.e. blank)
Lets save this output of the calculation as a text file:
output_file_name <- "/Users/kubotan/Downloads/growth curve calc.txt" #your output file location
write.table(gc_out, file = output_file_name, quote = FALSE, sep = "\t", row.names = FALSE)
If you ever need to load your calculations into R, you can do this by:
gc_out <- read.table(output_file_name,header=T,sep="\t")
Where output_file_name is where you saved your file. Your output file, if you used the practice data set, should look like this (a download prompt will begin).
Note: Growthcurver calculates more than just the area under the curve (AUC), growth rate, and final OD (carrying capacity). To understand what each abbreviation means and to better understand what each measures, please read the Growthcurver documentation.
A general gist of what each column denotes is:
- k = carrying capacity
- n0 = initial population size
- r = growth rate
- t_mid = time at which the population density reaches 1/2 of carrying capacity (k)
- t_gen = fastest possible generation (doubling time)
- auc_l = area under the logistic curve
- auc_e = empirical area under the curve which is obtained by summing up the area under the experimental curve from the measurements in the input data.
Plotting stats (ggplot)
We are interested in the area under the curve (AUC), growth rate, and the final OD (carrying capacity). We will extract columns with only these stats from the gc_out dataframe using the tidyverse package.
library(tidyverse)
gc_out2 <- gc_out %>%
select(sample,k,r,auc_e) #strain names, carrying capacity, growth rate, and area under the curve
We will also rename the sample column to “Strain”:
names(gc_out2)[names(gc_out2) == 'sample'] <- 'Strain'
Then convert the dataframe into long format in order to be able to plot in ggplot:
gc_long <- melt(gc_out2, id = "Strain")
Then pick colors from Color Brewer:
col <- brewer.pal(8, "Paired")
Finally, plot your stats using ggplot:
ggplot(gc_long, aes(x = Strain, y = value,fill=Strain,color=Strain)) +
geom_point(size=3, alpha=0.5, position=position_jitter(w=0.1, h=0))+
facet_wrap(~variable, scales = "free",strip.position = "left",
labeller = as_labeller(c(k="Carrying Capacity (Final OD)", r="Growth Rate", auc_e="Area Under the Curve (AUC)")))+
scale_fill_manual(values=col[1:8])+
scale_color_manual(values=col[1:8])+
stat_summary(fun.min=function(y)(mean(y)-sd(y)),
fun.max=function(y)(mean(y)+sd(y)),
geom="errorbar", width=0.1, color="black") +
stat_summary(fun=base::mean, geom="point", shape=23, color="black",size=4)+
theme(axis.title.y = element_blank(),
axis.text.x = element_text(angle = 60, vjust = 1, hjust=1),
strip.background = element_blank(),
strip.placement = "outside")
Your plot should look something like this: