Exponential Phase Model (30–210)
# Load required libraries
library(plotly)
# 1) Full Data + Subset for Exponential Phase
time <- c(0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300)
od <- c(0.35, 0.260, 0.447, 0.619, 0.704, 0.838, 0.991, 1.112, 1.168, 1.238, 1.339)
# Adjust OD by subtracting the blank measurement
blank_od <- 0.0071
od_adj <- od - blank_od
# Full dataset on ln(OD)
ln_od_all <- log(od_adj)
# Exponential subset: time=30..210
# Indices 2..8 => 30, 60, 90, 120, 150, 180, 210
time_sub <- time[2:8]
od_sub <- od_adj[2:8]
ln_od_sub <- log(od_sub)
# 2) Fit Linear Model on 30..210 min
model_ln <- lm(ln_od_sub ~ time_sub)
# Extract slope, intercept, R^2 for annotation
slope_ln <- coef(model_ln)[2]
intercept_ln <- coef(model_ln)[1]
r2_ln <- summary(model_ln)$r.squared
# 3) Prepare for Plot
# Define a new time vector for predictions: from 30..210
time_pred <- seq(30, 210, length.out = 100)
pred_ln <- predict(model_ln, newdata = data.frame(time_sub = time_pred), interval = "confidence")
# Calculate y-axis range to match base plot
all_y <- c(ln_od_all, pred_ln[, "upr"], pred_ln[, "lwr"]) # Include data, upper, and lower CI
yrange <- extendrange(all_y) # Adds default padding like base plot
# 4) Create Interactive Plot with Plotly
p <- plot_ly() %>%
# Add all data points (0..300)
add_markers(
x = time,
y = ln_od_all,
marker = list(
size = 10,
color = "#3498DB",
line = list(color = "#2C3E50", width = 1)
),
name = "Data Points",
hovertemplate = "Time: %{x} min<br>ln(OD): %{y:.2f}"
) %>%
# Add confidence band as a filled area
add_ribbons(
x = time_pred,
ymin = pred_ln[, "lwr"],
ymax = pred_ln[, "upr"],
fillcolor = "rgba(230, 126, 34, 0.2)", # Semi-transparent orange
line = list(color = "transparent"),
name = "Confidence Interval",
hoverinfo = "skip" # Disable hover for the band
) %>%
# Add regression line
add_lines(
x = time_pred,
y = pred_ln[, "fit"],
line = list(color = "#E67E22", width = 3.5, dash = "dash"),
name = "Linear Fit"
) %>%
# Customize layout
layout(
title = list(
text = "Exponential Phase Model (30–210)",
font = list(size = 20, family = "sans", color = "#000000")
),
xaxis = list(
title = "Time (min)",
titlefont = list(size = 16, family = "sans"),
tickfont = list(size = 14, family = "sans"),
gridcolor = "#DDE4E6"
),
yaxis = list(
title = "ln(OD)",
titlefont = list(size = 16, family = "sans"),
tickfont = list(size = 14, family = "sans"),
range = yrange, # Fixed range matching base plot
fixedrange = TRUE, # Prevent zooming on y-axis
gridcolor = "#DDE4E6"
),
showlegend = TRUE,
legend = list(
x = 0.02,
y = 0.98,
font = list(size = 13, family = "sans"),
bgcolor = "rgba(0,0,0,0)"
),
paper_bgcolor = "#FAFAFA",
plot_bgcolor = "#FAFAFA",
shapes = list(
list(
type = "rect",
x0 = 120 - 30,
x1 = 120 + 30,
y0 = max(ln_od_all) - 0.15,
y1 = max(ln_od_all) - 0.05,
fillcolor = "rgba(0,0,0,0)",
line = list(color = "rgba(0,0,0,0)")
)
),
annotations = list(
list(
x = 120,
y = max(ln_od_all) - 0.1,
text = paste("R² =", format(r2_ln, digits = 3)),
showarrow = FALSE,
font = list(size = 14, family = "sans", color = "#555555")
)
)
)
# Display the interactive plot
p
Growthcurver Model Code
library(growthcurver)
# 1) Data
data <- data.frame(
time = c(0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300),
od = c(0.35, 0.260, 0.447, 0.619, 0.704, 0.838, 0.991, 1.112, 1.168, 1.238, 1.339)
)
# 2) Fit Logistic Model with Growthcurver
gc_fit <- SummarizeGrowth(data$time, data$od)
# 3) Plot with Custom Axis Labels and Title
plot(
gc_fit,
xlab = "Time (min)",
ylab = "OD600",
main = "Growth Curve (Logistic Model)",
pch = 16, # solid circles for data points
colData = "black",
colModel = "red",
lwdModel = 2 # thicker logistic curve
)
