I am writing some code in R to handle errors/warnings.
The condition object i get back is a list of a message as string and a call object, representing the function call, that caused the error. I want to have a string that is the same as if i simply used print() on the call object. However using as.character() or paste() gives back a vector of multiple strings representing the function name and parameters.
Is there an easy way to do this or do i have to build the string myself?
Use deparse:
x <- call("sum",1:10)
as.character(x)
[1] "sum" "1:10"
deparse(x)
[1] "sum(1:10)"
Related
I am working with netCDF-files and have the following problem:
I created 70 objects of "ncdf4" class. They are named ncin1950 - ncin2019.
In the next step I need to extract certain information (so called "consecutive_dry_days_index_per_time_period") from the single objects which is regulary done by the following command, using ncin1950 as an example:
cdd.array1950 <- ncvar_get(ncin1950,"consecutive_dry_days_index_per_time_period")
This works perfectly fine.
Since I do not want to apply this command for every single object and thereby 70 times, I tried to use a loop:
for (i in 1950:2019) {
assign(paste0("cdd.array",i), ncvar_get(paste("ncin",i,sep = ""),"consecutive_dry_days_index_per_time_period"))
}
This did not work due to this:
error in ncvar_get(paste("ncin", i, sep = ""), "consecutive_dry_days_index_per_time_period") :
first argument (nc) is not of class ncdf4!
I think the reason for this is the fact that paste() automatically creates results of the class "character":
> class(paste("ncin",1950,sep = ""))
[1] "character"
while
> class(ncin1950)
[1] "ncdf4"
So the question is, how can I keep the "ncdf4" class in the for-loop while using the paste()-function or anything similar which concatenates?
You need get() to use a string to reference an object, ncvar_get(get(paste("ncin",i,sep = "")). Or use mget() to get the whole list of objects at once, then lapply().
Or, best of all, rearrange you upstream workflow so that you're creating a list of objects, rather than cluttering your workspace with 70 different objects. Then you can operate on the list with a for loop, or lapply, or fancier methods (e.g. purrr::map()). This is more idiomatic and will simplify your life in the long run ...
Why can't R find this variable?
assign(paste0('my', '_var'), 2)
get(paste0('my', '_var')) ## isn't this returning an object?
save(get(paste0('my', '_var')), file = paste0('my', '_var.RDATA'))
This throws the error:
Error in save(paste0("my", "_var"), file = paste0("my", "_var.RDATA")) :
object ‘paste0("my", "_var")’ not found
From the help page, the save() function expects "the names of the objects to be saved (as symbols or character strings)." Those values are not evaulated, ie you can't put in functions that will eventually return strings or raw values themselves. Use the list= parameter if you want to call a function to return a string the the name of a variable.
save(list=paste0('my', '_var'), file = paste0('my', '_var.RDATA'))
Though using get/assign is often not a good practice in R. They are usually better ways so you might want to rethink your general approach.
And finally, if you are saving a single object, you might want to consider saveRDS() instead. Often that's the behavior people are expecting when they use the save() function.
The documentation for save says that ... should be
the names of the objects to be saved (as symbols or character strings).
And indeed if you type save into the console you can see that the source has the line
names <- as.character(substitute(list(...)))[-1L]
where substitute captures its argument and doesn't evaluate it. So as the error suggests, it is looking for an object with the name paste0('my', '_var'), not evaluating the expressions supplied.
There has been discussion on how to get a variable from a string. Indeed, get works for, say, the data.table function: get("data.table") returns data.table. However,
> get("data.table::data.table")
Error in get("data.table::data.table") :
object 'data.table::data.table' not found
Is there a way to do this that preserves the reference to the package name? I.e., I do NOT want to simply do a split on "::" and get the second half of the string.
You could just use the envir argument to get the function from the namespace.
get("data.table", envir = getNamespace("data.table"))
Or more simply as #joran notes, getFromNamespace() can be used.
getFromNamespace("data.table", "data.table")
I am using OpenCPU and R to create a web API that takes in some inputs and returns a topoJSON file from a database, as well as some other information. OpenCPU automatically pushes the output through toJSON, which results in JSON output that has quoted JSON in it (i.e., the topoJSON). This is obviously not ideal--especially since it then gets incredibly cluttered with backticked quotes (\"). I tried using fromJSON to convert it to an R object, which could then be converted back (which is incredibly inefficient), but it returns a slightly different syntax and the result is that it doesn't work.
I feel like there should be some way to convert the string to some other type of object that results in toJSON calling a different handler that tells it to just leave it alone, but I can't figure out how to do that.
> s <- '{"type":"Topology","objects":{"map": "0"}}'
> fromJSON(s)
$type
[1] "Topology"
$objects
$objects$map
[1] "0"
> toJSON(fromJSON(s))
{"type":["Topology"],"objects":{"map":["0"]}}
That's just the beginning of the file (I replaced the actual map with "0"), and as you can see, brackets appeared around "Topology" and "0". Alternately, if I just keep it as a string, I end up with this mess:
> toJSON(s)
["{\"type\":\"Topology\",\"objects\":{\"0000595ab81ec4f34__csv\": \"0\"}}"]
Is there any way to fix this so that I just get the verbatim string but without quotes and backticks?
EDIT: Note that because I'm using OpenCPU, the output needs to come from toJSON (so no other function can be used, unfortunately), and I can't do any post-processing.
To it seems you just want the values rather than vectors. Set auto_unbox=TRUE to turn length-one vectors into scalar values
toJSON(fromJSON(s), auto_unbox = TRUE)
# {"type":"Topology","objects":{"map":"0"}}
That does print without escaping for me (using jsonlite_1.5). Maybe you are using an older version of jsonlite. You can also get around that by using cat() to print the result. You won't see the slashes when you do that.
cat(toJSON(fromJSON(s), auto_unbox = TRUE))
You can manually unbox the relevant entries:
library(jsonlite)
s <- '{"type":"Topology","objects":{"map": "0"}}'
j <- fromJSON(s)
j$type <- unbox(j$type)
j$objects$map <- unbox(j$objects$map)
toJSON(j)
# {"type":"Topology","objects":{"map":"0"}}
Trying to get into Julia after learning python, and I'm stumbling over some seemingly easy things. I'd like to have a function that takes strings as arguments, but uses one of those arguments as a regular expression to go searching for something. So:
function patterncount(string::ASCIIString, kmer::ASCIIString)
numpatterns = eachmatch(kmer, string, true)
count(numpatterns)
end
There are a couple of problems with this. First, eachmatch expects a Regex object as the first argument and I can't seem to figure out how to convert a string. In python I'd do r"{0}".format(kmer) - is there something similar?
Second, I clearly don't understand how the count function works (from the docs):
count(p, itr) → Integer
Count the number of elements in itr for which predicate p returns true.
But I can't seem to figure out what the predicate is for just counting how many things are in an iterator. I can make a simple counter loop, but I figure that has to be built in. I just can't find it (tried the docs, tried searching SO... no luck).
Edit: I also tried numpatterns = eachmatch(r"$kmer", string, true) - no go.
To convert a string to a regex, call the Regex function on the string.
Typically, to get the length of an iterator you an use the length function. However, in this case that won't really work. The eachmatch function returns an object of type Base.RegexMatchIterator, which doesn't have a length method. So, you can use count, as you thought. The first argument (the predicate) should be a one argument function that returns true or false depending on whether you would like to count a particular item in your iterator. In this case that function can simply be the anonymous function x->true, because for all x in the RegexMatchIterator, we want to count it.
So, given that info, I would write your function like this:
patterncount(s::ASCIIString, kmer::ASCIIString) =
count(x->true, eachmatch(Regex(kmer), s, true))
EDIT: I also changed the name of the first argument to be s instead of string, because string is a Julia function. Nothing terrible would have happened if we would have left that argument name the same in this example, but it is usually good practice not to give variable names the same as a built-in function name.