Plotting Arbitrary Functions by Group in R

Viewed 39

I have a dataset (test_df) that looks like:

Species TreatmentA TreatmentB X0 L K
Apple Hot Cloudy 1 2 3
Apple Cold Cloudy 4 5 6
Orange Hot Sunny 7 8 9
Orange Cold Sunny 10 11 12

I would like to display the effect of the treatments by using the X0, L, and K values as coefficients in a standard logistic function and plotting the same species across various treatments on the same plot. I would like a grid of plots with the logistic curves for each species on it's own plots, with each treatment then being grouped by color within every plot. In the above example, Plot1.Grid1 would have 2 logistic curves corresponding to Apple Hot and Apple Cold, and plot1.Grid2 would have 2 logistic curves corresponding to Orange Hot and Orange Cold.

The below code will create a single logistic function curve which can then be layered, but manually adding the layers for multiple treatments is tedious.

testx0 <- 1
testL <- 2
testk <- 3
days <- seq(from = -5, to = 5, by = 1)

functionmultitest <- function(x,testL,testK,testX0) {
    (testL)/(1+exp((-1)*(testK) *(x - testX0)))
}

ggplot()+aes(x = days, y = functionmultitest(days,testL,testk,testx0))+geom_line()

The method described in (https://statisticsglobe.com/draw-multiple-function-curves-to-same-plot-in-r) works for dataframes with few species or treatments, but it becomes very tedious to individually define the curves if you have many treatments/species. Is there a way to programatically pass the list of coefficients and have ggplot handle the grouping?

Thank you!

1 Answers

Your current code shows how to compute the curve for a single row in your data frame. What you can do is pre-compute the curve for each row and then feed to ggplot.

Setup:

# Packages
library(ggplot2)

# Your days vector
days <- seq(from = -5, to = 5, by = 1)

# Your sample data frame above
df = structure(list(Species = c("Apple", "Apple", "Orange", "Orange"
), TreatmentA = c("Hot", "Cold", "Hot", "Cold"), TreatmentB = c("Cloudy", 
"Cloudy", "Sunny", "Sunny"), X0 = c(1L, 4L, 7L, 10L), L = c(2L, 
5L, 8L, 11L), K = c(3L, 6L, 9L, 12L)), class = "data.frame", row.names = c(NA, 
-4L))

# Your function
functionmultitest <- function(x,testL,testK,testX0) {
  (testL)/(1+exp((-1)*(testK) *(x - testX0)))
}

We'll "expand" each row of your data frame with the days vector:

# Define first a data frame of days:
days_df = data.frame(days = days)

# Perform a cross join
df_all = merge(days_df, df, all = T)

At this point, you will have a data frame where each original row is duplicated for as many days you have.

Now, just as you did for one row, we'll compute the value of the function for each row and store in the df_all as result:

df_all$result = mapply(functionmultitest, df_all$days, df_all$L, df_all$K, df_all$X0)

I'm not sure how you intended to handle treatmentA and treatmentB, so I'll just combine for illustration purposes:

    df_all$combined_treatment = paste0(df_all$TreatmentA, "-", df_all$TreatmentB)

We can now feed this data frame to ggplot, set the color to be combined_treatment, and use the facet_grid function to split by species

ggplot(data = df_all, aes(x = days, y = result, color = combined_treatment))+
geom_line() + 
facet_grid(Species ~ ., scales = "free")

The result is as follows:

enter image description here

Related