I am using a UDF in an r-markdown script to plot data from stored lists. When I run my functions body, everything works out just fine, but when I try to execute the function with defined arguments, that I have verified to work in the body, all my logic that checks list length returns FALSE
.
Here is an example data set I made:
library(dplyr)
library(plotly)
plotdataframe <- list()
dataframerows <- list()
AllExplVarCoeffs <- list()
AllExplVarNames <- list()
NrmPolcts <- list()
AllExplVarCoeff <- list()
AllExplVarName <- list()
NrmPolct <- list()
for (i in 1:10)
{
for (j in 1:8)
{
for(n in 1:16)
{
if (n == 3 || n == 8 || n == 4 && j == 5 || n == 9 && j == 5)
{
AllExplVarName <-NULL
AllExplVarCoeff <- NULL
NrmPolct <- NULL
}else
{
set.seed(10)
AllExplVarName <-c(1,2,3,4,5,6,7,8,9,10)
AllExplVarCoeff <- runif(10, min=-1, max=1)
NrmPolct <- c(.015,.005,.33,.32,.225,.025,.03,.05,0 ,0)
padvarcnt <-(length(AllExplVarCoeff)-length(NrmPolct))
for (l in seq_len(padvarcnt))
{
padval = l*0
NrmPolCt1 <- c(NrmPolCt,padval)
}
NrmPolct1 <- as.numeric(unlist(NrmPolct))
AllExplVarNames <- cbind(AllExplVarNames,AllExplVarName)
AllExplVarCoeffs <- cbind(AllExplVarCoeffs,AllExplVarCoeff)
NrmPolcts <- cbind(NrmPolcts,NrmPolct1)
dataframerows <- cbind(AllExplVarNames,AllExplVarCoeffs,NrmPolcts)
assign(paste("plotdataframe",i, j, n, sep="_"),cbind(plotdataframe,dataframerows))
plotdataframe <- list()
dataframerows <- list()
AllExplVarCoeffs <- list()
AllExplVarNames <- list()
NrmPolcts <- list()
assign(paste("AllExplVarNames",i, j, n, sep="_"),cbind(AllExplVarNames,AllExplVarName))
assign(paste("AllExplVarCoeffs",i ,j ,n, sep="_"),cbind(AllExplVarCoeffs,AllExplVarCoeff))
assign(paste("NrmPolcts",i, j, n, sep="_"),cbind(NrmPolcts,NrmPolct1))
AllExplVarCoeffs <- list()
AllExplVarNames <- list()
NrmPolcts <- list()
}
}
}
}
The NULL
entries represent cases in my real data where the value for "n" would return an empty set.
My function is defined thus (please ignore the ugly plots, i'm pressed for time so I did not make this look nice):
DrawTestExVar <- function(x,j)
{
print(paste("x=",x))
print(paste("j=",j))
StCrPltData <- ls(pattern=paste0("plotdataframe_",x,"_",j))
SCPD <- mget(StCrPltData)
for(n in 1:16)
{ print(paste("n=",n))
print(paste0('plotdataframe_',x,'_',j,'_',n))
if (length(unlist((SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n))]))) != 0)
{
n1=n
j1=j
print(n1)
plot1 <- plot_ly(as.data.frame(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))])) %>%
add_trace(x=~unlist(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))][[1]][,'AllExplVarName']), y=~unlist(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))][[1]][,'AllExplVarCoeff']), yaxis="y", type="scatter", mode="markers", name="Coef Values") %>%
add_bars(x=~unlist(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))][[1]][,'AllExplVarName']), y=~unlist(SCPD[c(paste0('plotdataframe_',x,'_',j,'_',n1))][[1]][,'NrmPolct1']), yaxis="y2", name="% Polcy Count")
print(plot1)
} else
{
print("Next")
}
}
}
but when I execute the function: DrawTestExVar(5,3)
I get noting but the length = 0 response:
> DrawTestExVar(5,3)
[1] "x= 5"
[1] "j= 3"
[1] "n= 1"
[1] "plotdataframe_5_3_1"
[1] "Next"
[1] "n= 2"
[1] "plotdataframe_5_3_2"
[1] "Next"
[1] "n= 3"
[1] "plotdataframe_5_3_3"
[1] "Next"
[1] "n= 4"
[1] "plotdataframe_5_3_4"
[1] "Next"
[1] "n= 5"
[1] "plotdataframe_5_3_5"
[1] "Next"
[1] "n= 6"
[1] "plotdataframe_5_3_6"
[1] "Next"
[1] "n= 7"
[1] "plotdataframe_5_3_7"
[1] "Next"
[1] "n= 8"
[1] "plotdataframe_5_3_8"
[1] "Next"
[1] "n= 9"
[1] "plotdataframe_5_3_9"
[1] "Next"
[1] "n= 10"
[1] "plotdataframe_5_3_10"
[1] "Next"
[1] "n= 11"
[1] "plotdataframe_5_3_11"
[1] "Next"
[1] "n= 12"
[1] "plotdataframe_5_3_12"
[1] "Next"
[1] "n= 13"
[1] "plotdataframe_5_3_13"
[1] "Next"
[1] "n= 14"
[1] "plotdataframe_5_3_14"
[1] "Next"
[1] "n= 15"
[1] "plotdataframe_5_3_15"
[1] "Next"
[1] "n= 16"
[1] "plotdataframe_5_3_16"
[1] "Next"
I thought it was relatively straightforward; select the lists from the global environment with names that match the input pattern, then filter out the "n" values that return a length 0 list and plot the remainders in a loop. I have constructed two other functions to plot from stored data that work just fine, so I am confident the issue lies within the if else
loop where the issue seems to be stemming from how I defined or am using my arguments. None of my digging into r function documentation has revealed what I am doing wrong though, and none of the attempts I have made to make the calls more explicit have worked.
Thoughts?
Update 1: After printing some troubleshooting statements, it is apparent that the error actually lies within the arguments being read or applied. When I print()
the values for x and j when running the DrawTestExVar(5,3), x=5 and j=3, as needed. print()
ing the value for n in the loop shows it incrementing appropriately and being applied to the paste commands correctly, but all the print(length(list))
return lengths of 0.
CodePudding user response:
The answer lies within the way function is built and how it accesses data. The list references
StCrPltData <- ls(pattern=paste0("plotdataframe_",x,"_",j))
and
SCPD <- mget(StCrPltData)
need to occur outside of the function so it can actually access the dataframes. Furthermore, StCrPltData can be removed entirely by using its definition in the function call. The function arguments should look like
DrawTestExVar <- function(x,j,SCPD)
and to call the function
DrawTestExVar(5,3,mget(ls(pattern=paste0("plotdataframe_",5,"_",3))))
Running this gives the plots (which I will not show because they are very ugly), and the troubleshooting prints:
> DrawTestExVar(5,3,mget(ls(pattern=paste0("plotdataframe_",5,"_",3))))
[1] "x= 5"
[1] "j= 3"
[1] "n= 1"
[1] "plotdataframe_5_3_1"
[1] 1
[1] "n= 2"
[1] "plotdataframe_5_3_2"
[1] 2
[1] "n= 3"
[1] "plotdataframe_5_3_3"
[1] "Next"
[1] "n= 4"
[1] "plotdataframe_5_3_4"
[1] 4
[1] "n= 5"
[1] "plotdataframe_5_3_5"
[1] 5
[1] "n= 6"
[1] "plotdataframe_5_3_6"
[1] 6
[1] "n= 7"
[1] "plotdataframe_5_3_7"
[1] 7
[1] "n= 8"
[1] "plotdataframe_5_3_8"
[1] "Next"
[1] "n= 9"
[1] "plotdataframe_5_3_9"
[1] 9
[1] "n= 10"
[1] "plotdataframe_5_3_10"
[1] 10
[1] "n= 11"
[1] "plotdataframe_5_3_11"
[1] 11
[1] "n= 12"
[1] "plotdataframe_5_3_12"
[1] 12
[1] "n= 13"
[1] "plotdataframe_5_3_13"
[1] 13
[1] "n= 14"
[1] "plotdataframe_5_3_14"
[1] 14
[1] "n= 15"
[1] "plotdataframe_5_3_15"
[1] 15
[1] "n= 16"
[1] "plotdataframe_5_3_16"
[1] 16
which follow the expected output, showing the function to be working as desired.