3

I am trying to implement tryCatch with a while loop in R, but have been running into issues. I have tried to implement a number of the proposed solutions (which revolve around for loops), but with no success.

Essentially I am querying an API with R and looping through a number of relevant parameters (longitudes and latitudes to be precise). The reason why I need a tryCatch block is because sometimes the URL request will fail, which in turn stops the script running. What I want to be able to do is to ignore the error, increase the looping counter by 1 and continue extraction.

The while loop I have set up is (FYI - length refers to length of dataframe being looped over):

i <- 1
while(i <= length) {
x_cord <- geocode_area$X[i]
y_cord <- geocode_area$Y[i]
target <- getUrl(x_cord,y_cord)
dat <- fromJSON(target)
geocode_area$Block[i] <- dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK
print(paste(i/length*100,"% completed",sep=""))
print(dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK)
i <- i + 1 
}

The getUrl() function is defined as:

getUrl <- function(x,y) {
root <- "http://geocoding.geo.census.gov/geocoder/geographies/coordinates?"
u <- paste0(root,"x=", x,"&y=", y,"&benchmark=4&vintage=4&format=json")
return(URLencode(u))
}

The input data.frame to the while loop looks like so (note I have thrown in the character strings to simulate an error to test that tryCatch is working):

          X                 Y          Block
1 -122.425891675136 37.7745985956747     0
2  -122.42436302145 37.8004143219856     0
3 -122.426995326766 37.8008726327692     0
4 -122.438737622757 37.7715411720578     0
5               abc            zsads     0

I have tried a number of the SO and other solutions, but the results do not seem to be working properly. Can anyone help?

Thanks!

Jack

6
  • It would probably be helpful if you included a few example parameters fro your data frame. Commented Sep 30, 2015 at 19:42
  • Hi. It is a pretty simple data.frame (if I understand you correctly). I have updated the question with the head of the input df. Thanks! Commented Sep 30, 2015 at 19:49
  • 1
    Why you using while?? Seems like for (i in 1:length) tryCatch({...}) is doing job. Commented Sep 30, 2015 at 20:24
  • Hi there. I changed to a for loop and now it works fine, in fact I could get away with just a try instead of tryCatch. Although I am still interested to know why it wouldn't work with a while loop? Thanks all, very useful! Commented Sep 30, 2015 at 20:53
  • I wrote out an answer below in detail, and realized it was for try not tryCatch. Oops. Commented Sep 30, 2015 at 20:57

2 Answers 2

2

As a general note - your code is kind of weird. I would recommend either a for loop, or possibly better, a function that does this stuff. But you can make your loop work.

# A minimal working version
library(RJSONIO)
options(stringsAsFactors = FALSE)

# Create a data frame with the example data
geocode_area <- data.frame(X = c("-122.425891675136","-122.42436302145","-122.426995326766","-122.438737622757","abc"),
                           Y = c("37.7745985956747","37.8004143219856","37.8008726327692","37.7715411720578","zsads"),
                           Block = c(0,0,0,0,0))

# Your old function, unchanged
getUrl <- function(x,y) {

    root <- "http://geocoding.geo.census.gov/geocoder/geographies/coordinates?"
    u <- paste0(root,"x=", x,"&y=", y,"&benchmark=4&vintage=4&format=json")
    return(URLencode(u))
}

# Getting the length parameter
length <- nrow(geocode_area)
i <- 1
while(i <= length) {

    x_cord <- geocode_area$X[i]
    y_cord <- geocode_area$Y[i]
    target <- getUrl(x_cord,y_cord)

    # Here be new code
    # Do a try(), with silent = TRUE, which suppresses outputs to STDERR
    # In principle, this is dangerous - a better approach is to strip out the offending data before invoking it
    # Errors are, after all, there for a reason
    dat <- try(fromJSON(target),silent = TRUE)

    # Now, we conditionally complete the next steps
    # If the class of dat is not a try-error, perform your normal operations
    # Otherwise, bypass and print a note to the console
    if(class(dat) != "try-error") {

        geocode_area$Block[i] <- dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK
        print(paste(i/length*100,"% completed",sep=""))
        print(dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK)
    } else if (class(dat) == "try-error") {print("Error encountered, bypassing")}
i <- i + 1
}

EDITED TO ADD: Obviously, this uses try() instead of tryCatch(). However, as the poster ended up using try() and this may represent a different way to do it, I thought I'd leave it up.

Sign up to request clarification or add additional context in comments.

Comments

0

With some help from the kind individuals who commented I got to an answer. Essentially avoid the while loop altogether and use a for loop instead.

I am not sure entirely why a while loop would not work, I think that it might be something to do with a difficulty in updating the loop counter in the finally block.

Indeed, for the specific problem I had I did not even need a tryCatch at all. I would have used the error block to set the value I am updating to 0, however it is possible to just reset the input variable to 0 in the for loop. This is required, because otherwise the value of the previous iteration would be kept. It is also worth nothing that I needed to wrap the try expression in {}, because there were multiple expressions.

Code below. I hope this helps someone!

for(i in 1:length) {
try(
{x_cord <- geocode_area$X[i]
y_cord <- geocode_area$Y[i]
target <- getUrl(x_cord,y_cord)
dat <- fromJSON(target)
geocode_area$Block[i] <- dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK
print(paste(i/length*100,"% completed",sep=""))
print(dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK)
dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK <- 0}
)
}

1 Comment

I ended up undeleting the answer I had written originally, since you decided to use try instead of tryCatch anyway. Hopefully the different version makes sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.