You are currently browsing the monthly archive for April 2017.
I’m pleased to announce that readxl 1.0.0 is available on CRAN. readxl makes it easy to bring tabular data out of Excel and into R, for modern .xlsx
files and the legacy .xls
format. readxl does not have any tricky external dependencies, such as Java or Perl, and is easy to install and use on Mac, Windows, and Linux.
You can install it with:
install.packages("readxl")
As well as fixing many bugs, this release:
- Allows you to target specific cells for reading, in a variety of ways
- Adds two new column types:
"logical"
and"list"
, for data of disparate type - Is more resilient to the wondrous diversity in spreadsheets, e.g., those written by 3rd party tools
You can see a full list of changes in the release notes. This is the first release maintained by Jenny Bryan.
Specifying the data rectangle
In an ideal world, data would live in a neat rectangle in the upper left corner of a spreadsheet. But spreadsheets often serve multiple purposes for users with different priorities. It is common to encounter several rows of notes above or below the data, for example. The new range
argument provides a flexible interface for describing the data rectangle, including Excel-style ranges and row- or column-only ranges.
library(readxl)
read_excel(
readxl_example("deaths.xlsx"),
range = "arts!A5:F15"
)
#> # A tibble: 10 × 6
#> Name Profession Age `Has kids` `Date of birth`
#>
#> 1 David Bowie musician 69 TRUE 1947-01-08
#> 2 Carrie Fisher actor 60 TRUE 1956-10-21
#> 3 Chuck Berry musician 90 TRUE 1926-10-18
#> 4 Bill Paxton actor 61 TRUE 1955-05-17
#> # ... with 6 more rows, and 1 more variables: `Date of death`
read_excel(
readxl_example("deaths.xlsx"),
sheet = "other",
range = cell_rows(5:15)
)
#> # A tibble: 10 × 6
#> Name Profession Age `Has kids` `Date of birth`
#>
#> 1 Vera Rubin scientist 88 TRUE 1928-07-23
#> 2 Mohamed Ali athlete 74 TRUE 1942-01-17
#> 3 Morley Safer journalist 84 TRUE 1931-11-08
#> 4 Fidel Castro politician 90 TRUE 1926-08-13
#> # ... with 6 more rows, and 1 more variables: `Date of death`
There is also a new argument n_max
that limits the number of data rows read from the sheet. It is an example of readxl’s evolution towards a readr-like interface. The Sheet Geometry vignette goes over all the options.
Column typing
The new ability to target cells for reading means that readxl’s automatic column typing will “just work” for most sheets, most of the time. Above, the Has kids
column is automatically detected as logical
, which is a new column type for readxl.
You can still specify column type explicitly via col_types
, which gets a couple new features. If you provide exactly one type, it is recycled to the necessary length. The new type "guess"
can be mixed with explicit types to specify some types, while leaving others to be guessed.
read_excel(
readxl_example("deaths.xlsx"),
range = "arts!A5:C15",
col_types = c("guess", "skip", "numeric")
)
#> # A tibble: 10 × 2
#> Name Age
#>
#> 1 David Bowie 69
#> 2 Carrie Fisher 60
#> 3 Chuck Berry 90
#> 4 Bill Paxton 61
#> # ... with 6 more rows
The new argument guess_max
limits the rows used for type guessing. Leading and trailing whitespace is trimmed when the new trim_ws
argument is TRUE
, which is the default. Finally, thanks to Jonathan Marshall, multiple na
values are accepted. The Cell and Column Types vignette has more detail.
"list"
columns
Thanks to Greg Freedman Ellis we now have a "list"
column type. This is useful if you want to bring truly disparate data into R without the coercion required by atomic vector types.
(df <- read_excel(
readxl_example("clippy.xlsx"),
col_types = c("text", "list")
))
#> # A tibble: 4 × 2
#> name value
#> <chr> <list>
#> 1 Name <chr [1]>
#> 2 Species <chr [1]>
#> 3 Approx date of death <dttm [1]>
#> 4 Weight in grams <dbl [1]>
tibble::deframe(df)
#> $Name
#> [1] "Clippy"
#>
#> $Species
#> [1] "paperclip"
#>
#> $`Approx date of death`
#> [1] "2007-01-01 UTC"
#>
#> $`Weight in grams`
#> [1] 0.9
Everything else
To learn more, read the vignettes and articles or release notes. Highlights include:
- General rationalization of sheet geometry, including detection and treatment of empty rows and columns.
- Improved behavior and messaging around coercion and mismatched cell and column types.
- Improved handling of datetimes with respect to 3rd party software, rounding, and the Lotus 1-2-3 leap year bug.
read_xls()
andread_xlsx()
are now exposed, so that files without an.xls
or.xlsx
extension can be read. Thanks Jirka Lewandowski!- readxl Workflows showcases patterns that reduce tedium and increase reproducibility when raw data arrives in a spreadsheet.
I’m planning to submit dplyr 0.6.0 to CRAN on May 11 (in four weeks time). In preparation, I’d like to announce that the release candidate, dplyr 0.5.0.9002 is now available. I would really appreciate it if you’d try it out and report any problems. This will ensure that the official release has as few bugs as possible.
Installation
Install the pre-release version with:
# install.packages("devtools")
devtools::install_github("tidyverse/dplyr")
If you discover any problems, please file a minimal reprex on GitHub. You can roll back to the released version with:
install.packages("dplyr")
Features
dplyr 0.6.0 is a major release including over 100 bug fixes and improvements. There are three big changes that I want to touch on here:
- Databases
- Improved encoding support (particularly for CJK on windows)
- Tidyeval, a new framework for programming with dplyr
You can see a complete list of changes in the draft release notes.
Databases
Almost all database related code has been moved out of dplyr and into a new package, dbplyr. This makes dplyr simpler, and will make it easier to release fixes for bugs that only affect databases.
To install the development version of dbplyr so you can try it out, run:
devtools::install_github("hadley/dbplyr")
There’s one major change, as well as a whole heap of bug fixes and minor improvements. It is now no longer necessary to create a remote “src”. Instead you can work directly with the database connection returned by DBI, reflecting the robustness of the DBI ecosystem. Thanks largely to the work of Kirill Muller (funded by the R Consortium) DBI backends are now much more consistent, comprehensive, and easier to use. That means that there’s no longer a need for a layer between you and DBI.
You can continue to use src_mysql()
, src_postgres()
, and src_sqlite()
(which still live in dplyr), but I recommend a new style that makes the connection to DBI more clear:
con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
DBI::dbWriteTable(con, "iris", iris)
#> [1] TRUE
iris2 <- tbl(con, "iris")
iris2
#> Source: table<iris> [?? x 5]
#> Database: sqlite 3.11.1 [:memory:]
#>
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> <dbl> <dbl> <dbl> <dbl> <chr>
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3.0 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
#> 7 4.6 3.4 1.4 0.3 setosa
#> 8 5.0 3.4 1.5 0.2 setosa
#> 9 4.4 2.9 1.4 0.2 setosa
#> 10 4.9 3.1 1.5 0.1 setosa
#> # ... with more rows
This is particularly useful if you want to perform non-SELECT queries as you can do whatever you want with DBI::dbGetQuery()
and DBI::dbExecute()
.
If you’ve implemented a database backend for dplyr, please read the backend news to see what’s changed from your perspective (not much). If you want to ensure your package works with both the current and previous version of dplyr, see wrap_dbplyr_obj()
for helpers.
Character encoding
We have done a lot of work to ensure that dplyr works with encodings other that Latin1 on Windows. This is most likely to affect you if you work with data that contains Chinese, Japanese, or Korean (CJK) characters. dplyr should now just work with such data.
Tidyeval
dplyr has a new approach to non-standard evaluation (NSE) called tidyeval. Tidyeval is described in detail in a new vignette about programming with dplyr but, in brief, it gives you the ability to interpolate values in contexts where dplyr usually works with expressions:
my_var <- quo(homeworld)
starwars %>%
group_by(!!my_var) %>%
summarise_at(vars(height:mass), mean, na.rm = TRUE)
#> # A tibble: 49 × 3
#> homeworld height mass
#> <chr> <dbl> <dbl>
#> 1 Alderaan 176.3333 64.0
#> 2 Aleen Minor 79.0000 15.0
#> 3 Bespin 175.0000 79.0
#> 4 Bestine IV 180.0000 110.0
#> 5 Cato Neimoidia 191.0000 90.0
#> 6 Cerea 198.0000 82.0
#> 7 Champala 196.0000 NaN
#> 8 Chandrila 150.0000 NaN
#> 9 Concord Dawn 183.0000 79.0
#> 10 Corellia 175.0000 78.5
#> # ... with 39 more rows
This will make it much easier to eliminate copy-and-pasted dplyr code by extracting repeated code into a function.
This also means that the underscored version of each main verb (filter_()
, select_()
etc). is no longer needed, and so these functions have been deprecated (but remain around for backward compatibility).
Over the couple of months there have been a bunch of smaller releases to packages in the tidyverse. This includes:
- forcats 0.2.0, for working with factors.
- readr 1.1.0, for reading flat-files from disk.
- stringr 1.2.0, for manipulating strings.
- tibble 1.3.0, a modern re-imagining of the data frame.
This blog post summarises the most important new features, and points to the full release notes where you can learn more.
(If you’ve never heard of the tidyverse before, it’s an set of packages that are designed to work together to help you do data science. The best place to learn all about it is R for Data Science.)
forcats 0.2.0
forcats has three new functions:
as_factor()
is a generic version ofas.factor()
, which creates factors from character vectors ordered by appearance, rather than alphabetically. This ensures means thatas_factor(x)
will always return the same result, regardless of the current locale.fct_other()
makes it easier to convert selected levels to “other”:x <- factor(rep(LETTERS[1:6], times = c(10, 5, 1, 1, 1, 1))) x %>% fct_other(keep = c("A", "B")) %>% fct_count() #> # A tibble: 3 × 2 #> f n #> #> 1 A 10 #> 2 B 5 #> 3 Other 4 x %>% fct_other(drop = c("A", "B")) %>% fct_count() #> # A tibble: 5 × 2 #> f n #> #> 1 C 1 #> 2 D 1 #> 3 E 1 #> 4 F 1 #> 5 Other 15
fct_relabel()
allows programmatic relabeling of levels:x <- factor(letters[1:3]) x #> [1] a b c #> Levels: a b c x %>% fct_relabel(function(x) paste0("-", x, "-")) #> [1] -a- -b- -c- #> Levels: -a- -b- -c-
See the full list of other changes in the release notes.
stringr 1.2.0
This release includes a change to the API: str_match_all()
now returns NA if an optional group doesn’t match (previously it returned “”). This is more consistent with str_match()
and other match failures.
x <- c("a=1,b=2", "c=3", "d=")
x %>% str_match("(.)=(\\d)?")
#> [,1] [,2] [,3]
#> [1,] "a=1" "a" "1"
#> [2,] "c=3" "c" "3"
#> [3,] "d=" "d" NA
x %>% str_match_all("(.)=(\\d)?,?")
#> [[1]]
#> [,1] [,2] [,3]
#> [1,] "a=1," "a" "1"
#> [2,] "b=2" "b" "2"
#>
#> [[2]]
#> [,1] [,2] [,3]
#> [1,] "c=3" "c" "3"
#>
#> [[3]]
#> [,1] [,2] [,3]
#> [1,] "d=" "d" NA
There are three new features:
- In
str_replace()
,replacement
can now be a function. The function is once for each match and its return value will be used as the replacement.redact <- function(x) { str_dup("-", str_length(x)) } x <- c("It cost $500", "We spent $1,200 on stickers") x %>% str_replace_all("\\$[0-9,]+", redact) #> [1] "It cost ----" "We spent ------ on stickers"
- New
str_which()
mimicsgrep()
:fruit <- c("apple", "banana", "pear", "pinapple") # Matching positions str_which(fruit, "p") #> [1] 1 3 4 # Matching values str_subset(fruit, "p") #> [1] "apple" "pear" "pinapple"
- A new vignette (
vignette("regular-expressions")
) describes the details of the regular expressions supported by stringr. The main vignette (vignette("stringr")
) has been updated to give a high-level overview of the package.
See the full list of other changes in the release notes.
readr 1.1.0
readr gains two new features:
- All
write_*()
functions now support connections. This means that that you can write directly to compressed formats such as.gz
,bz2
or.xz
(and readr will automatically do so if you use one of those suffixes).write_csv(iris, "iris.csv.bz2")
parse_factor(levels = NULL)
andcol_factor(levels = NULL)
will produce a factor column based on the levels in the data, mimicing factor parsing in base R (with the exception that levels are created in the order seen).iris2 <- read_csv("iris.csv.bz2", col_types = cols( Species = col_factor(levels = NULL) ))
See the full list of other changes in the release notes.
tibble 1.3.0
tibble has one handy new function: deframe()
is the opposite of enframe()
: it turns a two-column data frame into a named vector.
df <- tibble(x = c("a", "b", "c"), y = 1:3)
deframe(df)
#> a b c
#> 1 2 3
See the full list of other changes in the release notes.
We’re excited to announce the release of RStudio Connect: version 1.4.6. This is an incremental release which features significantly improved startup time and support for server-side Shiny bookmarks.
Improved Startup & Job Listing Time
We now track R process jobs in the database which allows us to list and query jobs much more quickly. This decreases the startup time of the RStudio Connect service — allowing even the busiest of servers to spin up in a matter of seconds. Additionally, operations that involve listing jobs such as viewing process logs for a particular application should be noticeably faster.
Server-Side Shiny Bookmarks
Shiny v0.14 introduced a feature by which users could bookmark the current state of the application by either encoding the state in the URL or saving the state to the server. As of this release, RStudio Connect now supports server-side bookmarking of Shiny applications.
Other notable changes this release:
- BREAKING: Changed the default for
Authorization.DefaultUserRole
frompublisher
toviewer
. New users will now be created with aviewer
account until promoted. The user roles documentation explains the differences. To restore the previous behavior, setDefaultUserRole = publisher
. Because viewer users cannot be added as collaborators on content, this means that in order to add a remote user as a collaborator on content you must first create their account, then promote them to a publisher account. - Fixed a bug in the previous release that had broken
Applications.ViewerOnDemandReports
andApplications.ViewerCustomizedReports
. These settings are again functional and allow you to manage the capabilities of a viewer of a parameterized report on the server. - Tune the number of concurrent processes to use when building R packages. This is controlled with the
Server.CompilationConcurrency
setting and passed as the value to the make flag-jNUM
. The default is to permit four concurrent processes. Decrease this setting in low memory environments. - The
/etc/rstudio-connect/rstudio-connect.gcfg
file is installed with more restrictive permissions. - Log file downloads include a more descriptive file name by default. Previously, we used the naming convention
<jobId>.log
, which resulted in file names likeGBFCaiPE6tegbrEM.log
. Now, we use the naming conventionrstudio-connect.<appId>.<reportId>.<bundleId>.<jobType>.<jobId>.log
, which results in file names likerstudio-connect.34.259.15.packrat_restore.GBFCaiPE6tegbrEM.log
. - Bundle the admin guide and user guide in the product. You can access both from the Documentation tab.
- Implemented improved, pop-out filtering panel when filtering content, which offers a better experience on small/mobile screens.
- Improvements to the parameterized report pane when the viewer does not have the authority to render custom versions of the document.
- Database performance improvements which should improve performance in high-traffic environments.
Upgrade Planning: The migration of jobs from disk to the database may take a few minutes. The server will be unavailable during this migration which will be performed the first time RStudio Connect v1.4.6 starts. Even on the busiest of servers we would expect this migration to complete in under 5 minutes.
If you haven’t yet had a chance to download and try RStudio Connect we encourage you to do so. RStudio Connect is the best way to share all the work that you do in R (Shiny apps, R Markdown documents, plots, dashboards, etc.) with collaborators, colleagues, or customers.
You can find more details or download a 45 day evaluation of the product at https://www.rstudio.com/products/connect/. Additional resources can be found below.
Shiny 1.0.1 is now available on CRAN! This release primarily includes bug fixes and minor new features.
The most notable additions in this version of Shiny are the introduction of the reactiveVal()
function (like reactiveValues()
, but it only stores a single value), and that the choices of radioButtons()
and checkboxGroupInput()
can now contain HTML content instead of just plain text. We’ve also added compatibility for the development version of ggplot2
.
Breaking changes
We unintentionally introduced a minor breaking change in that checkboxGroupInput
used to accept choices = NULL
to create an empty input. With Shiny 1.0.1, this throws an error; using choices = character(0)
works. We intend to eliminate this breakage in Shiny 1.0.2.
Update (4/20/2017): This has now been fixed in Shiny 1.0.2, currently available on CRAN.
Also, the selected
argument for radioButtons
, checkboxGroupInput
, and selectInput
once upon a time accepted the name of a choice, instead of the value of a choice; this behavior has been deprecated with a warning for several years now, and in Shiny 1.0.1 it is no longer supported at all.
Storing single reactive values with reactiveVal
The reactiveValues
object has been a part of Shiny since the earliest betas. It acts like a reactive version of an environment or named list, in that you can store and retrieve values using names:
rv <- reactiveValues(clicks = 0)
observeEvent(input$button, {
currentValue <- rv$clicks
rv$clicks <- currentValue + 1
})
If you only have a single value to store, though, it’s a little awkward that you have to use a data structure designed for multiple values.
With the new reactiveVal
function, you can now create a reactive object for a single variable:
clicks <- reactiveVal(0)
observeEvent(input$button, {
currentValue <- clicks()
clicks(currentValue + 1)
})
As you can see in this example, you can read the value by calling it like a function with no arguments; and you set the value by calling it with one argument.
This has the added benefit that you can easily pass the clicks
object to another function or module (no need to wrap it in a reactive()
).
More flexible radioButtons
and checkboxGroupInput
It’s now possible to create radio button and checkbox inputs with arbitrary HTML as labels. To do so, however, you need to pass different arguments to the functions. Now, when creating (or updating) either of radioButtons()
or checkboxGroupInput()
, you can specify the options in one of two (mutually exclusive) ways:
- What we’ve always had:
Use thechoices
argument, which must be a vector or list. The names of each element are displayed in the app UI as labels (i.e. what the user sees in your app), and the values are used for computation (i.e. the value is what’s returned byinput$rd
, whererd
is aradioButtons()
input). If the vector (or list) is unnamed, the values provided are used for both the UI labels and the server values. - What’s new and allows HTML:
Use both thechoiceNames
and thechoiceValues
arguments, each of which must be an unnamed vector or list (and both must have the same length). The elements inchoiceValues
must still be plain text (these are the values used for computation). But the elements inchoiceNames
(the UI labels) can be constructed out of HTML, either using theHTML()
function, or an HTML tag generation function, liketags$img()
andicon()
.
Here’s an example app that demos the new functionality (in this case, we have a checkboxGroupInput()
whose labels include the flag of the country they correspond to):
ggplot2
> 2.2.1 compatibility
The development version of ggplot2
has some changes that break compatibility with earlier versions of Shiny. The fixes in Shiny 1.0.1 will allow it to work with any version of ggplot2
.
A note on Shiny v1.0.0
In January of this year, we quietly released Shiny 1.0.0 to CRAN. A lot of work went into that release, but other than minor bug fixes and features, it was mostly laying the foundation for some important features that will arrive in the coming months. So if you’re wondering if you missed the blog post for Shiny 1.0.0, you didn’t.
Full changes
As always, you can view the full changelog for Shiny 1.0.1 (and 1.0.0!) in our NEWS.md file.