##' Get general information on a bill
##'
##' This function is a wrapper for the Votes.getBill() method of the PVS API Votes class which grabs the general information on a bill. The function sends a request with this method to the PVS API for all bill IDs given as a function input, extracts the XML values from the returned XML file(s) and returns them arranged in one data frame.
##' @usage Votes.getBill(billId,...)
##' @param billId a character string or list of character strings with the bill ID(s) (see references for details)
##' @param ... further arguments that are passed on to internal functions. Currently the argument separate can be defined: separate is a vector of character strings defining subnodes that should be returned separately (e.g., "sponsors").
##' @return If separate is not specified, a data frame with a row for each bill and columns with variables describing the bill. If separate is specified, a list containing several data frames, one for each subnode mentioned in separate and additionally one data frame containing all remaining nodes not mentioned in separate. The returned data frame contains a row for each bill and columns with the following variables describing the bill:\cr bill.billnumber,\cr bill.parentbill,\cr bill.title,\cr bill.officialtitle,\cr bill.dateintroduced,\cr bill.type,\cr bill.categories.category*.categoryId,\cr bill.categories.category*.name,\cr bill.billtextLink,\cr bill.sponsors.sponsor*.candidateId,\cr bill.sponsors.sponsor*.name,\cr bill.sponsors.sponsor*.type,\cr bill.committeeSponsors.committeeSponsor*.committeeId,\cr bill.committeeSponsors.committeeSponsor*.name,\cr bill.actions.action*.actionId,\cr bill.actions.action*.level,\cr bill.actions.action*.stage,\cr bill.actions.action*.outcome,\cr bill.actions.action*.statusDate,\cr bill.actions.action*.rollNumber,\cr bill.actions.action*.yea,\cr bill.actions.action*.nay,\cr bill.actions.action*.voiceVote,\cr bill.amendments.amendment*.billNumber,\cr bill.amendments.amendment*.actionId,\cr bill.amendments.amendment*.title,\cr bill.amendments.amendment*.statusDate.
##' @references http://api.votesmart.org/docs/Votes.html\cr
##' Use Votes.getByBillNumber(), Votes.getBillsByCategoryYearState(), Votes.getBillsByYearState(), Votes.getBillsByOfficialYearOffice(), Votes.getBillsByOfficialCategoryOffice(), Votes.getByOfficial(), Votes.getBillsBySponsorYear(), Votes.getBillsBySponsorCategory() or Votes.getBillsByStateRecent() to get a list of bill IDs.\cr
##' See also: Matter U, Stutzer A (2015) pvsR: An Open Source Interface to Big Data on the American Political Sphere. PLoS ONE 10(7): e0130501. doi: 10.1371/journal.pone.0130501
##' @author Ulrich Matter <ulrich.matter-at-unibas.ch>
##' @examples
##' # First, make sure your personal PVS API key is saved as an option
##' # (options("pvs.key" = "yourkey")) or in the pvs.key variable:
##' \dontrun{pvs.key <- "yourkey"}
##' # get information about certain bills
##' \dontrun{billinfo <- Votes.getBill(list(2819,6427))}
##' \dontrun{billinfo}
##' # let some variables with subnodes be returned separately (here: "sponsors" and "actions")
##' \dontrun{billinfo2 <- Votes.getBill(billId=list(2819,6427,6590),
##' separate=c("sponsors","actions"))}
##' \dontrun{billinfo2}
##' # check the sponsors of the requested bill (argument of separate)...
##' \dontrun{billinfo2$sponsors}
##' # ... and the usual variables describing the bill (nodes not mentioned in separate)
##' \dontrun{billinfo2$main}
##' @export
Votes.getBill <-
function (billId, ...) {
# FETCH AND EXTRACT DATA FROM API -----------------
# internal function
Votes.getBill.basic <-
function (.billId, ...) {
request <- "Votes.getBill?"
inputs <- paste("&billId=",.billId, sep="")
output <- pvsRequest10(request,inputs,...)
# mark output with billId differently depending on if argument "separate" was defined (class of output is different)
if (class(output)=="data.frame") {
output$billId <-.billId
} else { # class must be "list", hence separate was defined
for (i in 1:length(output)) output[[i]]["billId"] <- .billId
}
return(output)
}
# process all requests
output.list <- lapply(billId, Votes.getBill.basic, ...)
# CLEAN DATA -----------------------
# Different handling, if seperate was defined. Detecting this is not straightforward, because of possible wrong requests (warning message --> empty data fram returned)
# Hence, check if any of the returned list entries is itself a list
checkclass <- sapply(1:length(output.list), function(j) {
class(output.list[[j]])=="list"
})
# if not, proceed as usual:
if (!any(checkclass)) {
output.list <- redlist(output.list)
output <- bind_rows(output.list)
return(output)
} else { # if there are some lists, proceed differently
# combine all list entries of the same type in a df and these dfs in a list
nelements <- 1:length(checkclass)
listelements <- nelements[c(checkclass)]
nonlistelements <- nelements[c(!checkclass)]
nodenames <- names(output.list[[listelements[1]]] )
# first process the elements that contain a list
output <- lapply(nodenames, function(node) {
nodes <- lapply(listelements, function(e) {
output.list[[e]][[node]]
})
bind_rows(nodes)
})
for (i in 1:length(nodenames)) names(output)[i] <- nodenames[i]
# then the remaining, from error messages
output.listerr <- lapply(nonlistelements, function(e){
output.list[[e]]
})
output.err <- do.call("rbind",output.listerr)
output$missingData <- output.err
}
return(output)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.