R convert string into argument for a function - r

I am trying to make plots using a function in which arguments are values of dataframes.
seniorPlot <- function(validityDate, seniorTotal, color){
par(new = T)
plot(validityDate,seniorTotal,
type = "l",
lwd = 2.5,
xlim = c(date_debut$validityDate,date_fin$validityDate),
ylim = c(1,nmax$seniorTotal),
col = color,
xlab = "",
ylab = "",
xaxt = "n",
yaxt = "n",
bty = "n",
)
}
For the purpose, the threee arguments of the function are results several dataframes 'seniorList' and the seniors df named with the senior initials ('AM', 'FB', 'GM'…)
To describe, you can see the senior dataframes below:
seniorList <- data.frame(seniorValidation=c('AM', 'FB', 'GM'),seniorTotal=c(72, 154, 137))
AM <- data.frame(validationDate=c('2022-01-25', '2022-01-26'), color=c('brown','brown')
FB <- data.frame(validationDate=c('2022-01-20', '2022-01-30'), color=c('green','green')
GM <- data.frame(validationDate=c('2022-01-24', '2022-01-28'), color=c('blue','blue')
Obviously, there is more than 3 lines in the seniorList, so I want to do a loop, using the value of the first column of seniorList (ie. the senior name) to call the write dataframe.
And, here is the issue : how can I convert the result of noquote(paste(noquote(seniorList[i,1]),'$validityDate', sep = '')) to the result '2022-01-25' (if i = 1)
for (i in 1:nrow(seniorList)) {
seniorPlot(validityDate = noquote(paste(noquote(seniorList[i,1]),'$validityDate', sep = '')),
seniorTotal = noquote(paste(noquote(seniorList[i,1]),'$seniorTotal', sep = '')),
color = noquote(paste(noquote(seniorList[i,1]),'$color', sep = '')))
}
Thank you for your help, I hope my english is easy to understand.
noquote(paste(noquote(seniorList[i,1]),'$validityDate', sep = '')) give AM$validityDate and not its result

It's unclear what exactly the plot should look like but this shows how use "tidy" data easily with ggplot2.
DF <- rbind(cbind(AM, data.frame(seniorTotal = 72, seniorValidation = "AM")),
cbind(FB, data.frame(seniorTotal = 154, seniorValidation = "GB")),
cbind(GM, data.frame(seniorTotal = 137, seniorValidation = "GM")))
DF$validationDate <- as.Date(DF$validationDate)
#this is how your data should look like:
print(DF)
library(ggplot2)
ggplot(data = DF, aes(x = validationDate, y = seniorTotal, color = seniorValidation)) +
geom_line()

Related

Create an R function that normalizes data based on input values

I don't make to many complicated functions and typically stick with very basic ones. I have a question, how do I create a function that takes a dataset and normalizes based on desired normalization method and boxplots the output? Currently norm_method is different between the norm methods, was wondering if there is a way to call this in the start of function to pull through the correct method? Below is the code I created, but am stuck how to proceed.
library(reshape2) # for melt
library(cowplot)
demoData;
# target_deoData will need to be changed at some point
TestFunc <- function(demoData) {
# Q3 norm (75th percentile)
target_demoData <- normalize(demoData ,
norm_method = "quant",
desiredQuantile = .75,
toElt = "q_norm")
# Background normalization without spike
target_demoData <- normalize(demoData ,
norm_method = "neg",
fromElt = "exprs",
toElt = "neg_norm")
boxplot(assayDataElement(demoData[,1:10], elt = "q_norm"),
col = "red", main = "Q3",
log = "y", names = 1:10, xlab = "Segment",
ylab = "Counts, Q3 Normalized")
boxplot(assayDataElement(demoData[,1:10], elt = "neg_norm"),
col = "blue", main = "Neg",
log = "y", names = 1:10, xlab = "Segment",
ylab = "Counts, Neg. Normalized")
}
You might want to consider designing your normalize() and assayDataElement() functions to take ..., which provides more flexibility.
In lieu of that, given the examples above, you could make a simple configuration list, and elements of that configuration are passed to your normalize() and assayDataElement() functions, like this:
TestFunc <- function(demoData, method=c("quant", "neg")) {
method = match.arg(method)
method_config = list(
"quant" = list("norm_args" = list("norm_method" = "quant", desired_quantile = 0.75, "toElt" = "q_norm"),
"plot_args" = list("col"="red", main="Q3", ylab = "Counts, Q3 Normalized")),
"neg" = list("norm_args" = list("fromElt" = "exprs", "toElt" = "neg_norm"),
"plot_args" = list("col"="blue", main="Neg", ylab = "Counts, Neg Normalized"))
)
mcn = method_config[[method]][["norm_args"]]
mcp = method_config[[method]][["plot_args"]]
# normalize the data
target_demoData = do.call(normalize, c(list(data = demoData[1:10]), mcn))
# get the plot
boxplot(assayDataElement(
demoData[1:10], elt=mcp[["toElt"]],col = mcp[["col"],main = mcp[["main"]],
log = "y", names = 1:10, xlab = "Segment",ylab = mcp[["ylab"]]
)
}
Again, using this approach is not as flexible as ... (and consider splitting into two functions.. one that returns normalized data, and a second function that generates the plot..

Extension to answered question: R - Defining a function which recognises arguments not as objects, but as being part of the call

I've followed the excellent answer, as described here: https://stackoverflow.com/a/59987272/7493594
But how can I make it work with ggadjustedcurves?
myfun <- function(TimeVar, EventVar, CoxVar, CoxData){
TimeVar <- as.name(TimeVar)
EventVar <- as.name(EventVar)
CoxVar <- as.name(CoxVar)
CoxModel <- eval(bquote(coxph(Surv(.(TimeVar), .(EventVar)) ~.(CoxVar), data = .(CoxData))))
ggadjustedcurves(CoxModel,
variable = CoxVar,
xlab = "Years",
ylab = "Survival",
ggtheme = theme_survminer(),
size = 2, palette = "lancet",
data = CoxData)
I guess you're after something like this?
library(survminer)
library(survival)
myfun <- function(TimeVar, EventVar, CoxVar, CoxData) {
TimeVar <- as.name(TimeVar)
EventVar <- as.name(EventVar)
CoxVar_char <- CoxVar # Need to store `CoxVar` as string
CoxVar <- as.name(CoxVar)
CoxData <- as.name(CoxData)
CoxModel <- eval(bquote(
coxph(Surv(.(TimeVar), .(EventVar)) ~.(CoxVar), data = .(CoxData))))
ggadjustedcurves(
CoxModel,
variable = CoxVar_char, # `variable` needs to be a string
xlab = "Years",
ylab = "Survival",
ggtheme = theme_survminer(),
size = 2, palette = "lancet",
data = eval(CoxData)) # Eval `CoxData` as symbol
}
myfun("stop", "event", "size", "bladder")

hist() not showing all columns

I'm importing a df and then running hist() on the df:
df <- read.table("https://leicester.figshare.com/ndownloader/files/23581310", sep = ",", header = TRUE, stringsAsFactors = FALSE)
hist(df)
but it doesn't show the histograms of all 124 columns - only a subset. I'm not sure why? How do I get a histogram of all the columns in a df? I want to be able to run hist() on the entire data frame because it also shows the number of values/missing values at the bottom of each histogram.
I wonder how you could at all use hist in a data frame without Vectorizeing it. Best would be you use a different device such as the png.
png('foo.png', 2560, 1440)
par(mfrow=c(12, 11))
Vectorize(hist)(df)
dev.off()
Update
We can get nice titles and labels with nobs and missings using lapply and a misfun for convenience.
misfun <- \(z) paste(
paste(c('n', 'm'), table(factor(as.double(is.na(z)), levels=0:1)), sep=':'),
collapse=' ')
png('foo2.png', 2560, 1440)
par(mfrow=c(12, 11))
lapply(names(df), \(x) hist(df[[x]], main=x, xlab=misfun(df[x])))
dev.off()
Data:
df <- read.table("https://leicester.figshare.com/ndownloader/files/23581310", sep = ",", header = TRUE, stringsAsFactors = FALSE)
If all you are only looking for are the number of missing values in each column but don't really need the histograms, you can do:
colSums(sapply(df, is.na))
If you need this as an image, then it will be much clearer to draw it with text rather than hist:
df2 <- data.frame(col = paste(names(df), colSums(sapply(df, is.na)),
sep = '\n \nMissing = '),
x = (seq(ncol(df)) - 1) %% 12,
y = 12 - (seq(ncol(df)) - 1) %/% 12)
plot(df2$x, df2$y, type = 'n', xaxt = 'n', yaxt = 'n', xlab = '', ylab = '',
bty = 'n')
text(df2$x, df2$y, label = df2$col, cex = 0.5)

How to plot a fringe in zoo object time series to highlight a period?

library(zoo)
dat<-data.frame(
prec<-rnorm(650,mean=300),
temp<-rnorm(650,mean = 22),
pet<-rnorm(650,mean = 79),
bal<-rnorm(650,mean = 225))
colnames(dat)<-c("prec","temp","pet","bal")
dat<-ts(dat,start = c(1965,1),frequency = 12)
plot.zoo(dat)
rect(xleft=1975,xright = 1982,ybottom=0,ytop=800,col= '#FFFF0022',border = "transparent")
rect(xleft=1990,xright = 2000,ybottom=0,ytop=800,col= '#00BFFF22',border = "transparent")
rect(xleft=2010,xright = 2015,ybottom=0,ytop=500,col= '#FF000022',border = "transparent")
But I only get something either out of boundaries or not in the proper x axis This is my result so far
Use a panel function. Also using xblocks can simplify this further:
plot.zoo(dat, panel = function(x, y, ...) {
lines(x, y, ...)
year <- as.integer(x)
xblocks(x, year %in% 1975:1982, col = '#FFFF0022')
xblocks(x, year %in% 1990:2000, col = '#00BFFF22')
xblocks(x, year %in% 2010:2015, col = '#FF000022')
})

How to return a value if an error-free R function does not do so

My goal is to assign a plot produced by the pyramid package to a list. Later, I will have that plot and others inserted from the list into a document. But the pyramid function appears not to return a value. How can I assign the pyramid plot to an object?
install.packages("pyramid") # functions to draw a population pyramid
library(pyramid)
# create a mock data frame to comparing this plot to a counterpart from plotrix
df <- data.frame(level1 = c(9,9,4,3,34,28), levelsame = c(9,9,4,3,34,28),
title = c("Dir", "Exec. Dir", "Mgr", "Sr. Mgr", "Mgt Princ", "EVP+"))
# assign the plot (hopefully) to an object
empty <- pyramid(df, Laxis = seq(1,35,5), AxisFM = "g", Csize = 0.8, Cgap = .5, Llab = "",
Rlab = "", Clab = "Title", GL = F, Lcol = "blue", Rcol = "blue",
Ldens = -1, main = "Distribution of Levels")
> empty
NULL
Likewise, if I assign the pyramid call to my list, nothing happens. There is no value for the list returned by pyramid.
plotlist2[["pyramid"]] <- pyramid(df, Laxis = seq(1,35,5), AxisFM = "g", Csize = 0.8, Cgap = .5, Llab = "",
Rlab = "", Clab = "Title", GL = F, Lcol = "blue", Rcol = "blue",
Ldens = -1, main = "Distribution of Levels")
> plotlist2[1]
[[1]]
NULL
I fear I am blundering in some obvious mis-understanding, so I welcome being set aright. Thank you.
You can use the recordPlot() function to save the current plot to a variable.
In your case you could do:
#print the plot
pyramid(df, Laxis = seq(1,35,5), AxisFM = "g", Csize = 0.8, Cgap = .5, Llab = "",
Rlab = "", Clab = "Title", GL = F, Lcol = "blue", Rcol = "blue",
Ldens = -1, main = "Distribution of Levels")
#save the current printed plot
pyrPlot<-recordPlot()
#plot it again
pyrPlot
You might have to enable the displaylist using dev.control(displaylist ="enable") for this to work depending on the graphical device you are using

Resources