Ari Lamstein

A Tale of Two Bugs

Today I am happy to announce that a new version of choroplethr is now on CRAN. To get it type the following:

[code lang=”r”]
> install.packages("choroplethr")
> packageVersion("choroplethr")
[1] ‘3.5.2’
[/code]

The new version is 3.5.2. This version fixes two fairly pernicious bugs that were introduced in the last update to choroplethr. For reference, he is a detailed description of the bugs and their fixes.

Bug #1

Shortly after the last update to choroplethr users started reporting a bug that was preventing them from using the package at all:

[code lang=”r”]
> library(choroplethr)
>
> data(df_pop_state)
> state_choropleth(df_pop_state)
Error in FUN(X[[i]], …) : attempt to apply non-function
[/code]

You can read more about the bug here.  What most surprised me about the bug is that it made its way into CRAN at all. As you can see here, CRAN has systems in place that are designed to prevent this exact situation from occurring. And this code is fairly basic, to the point of appearing in the first vignette of the package. Even worse, I was unable to reproduce it locally. What happened?

It turns out that a recent update to ggplot2 (v2.1.0) places some new restrictions on how you can use it. In particular, you can no longer initialize R6 class variables with ggplot2 objects. If you do, the code will work locally (i.e. when you build the project from source), but will fail when run in the binary version of the package (which is what you normally get from CRAN).

In more detail, recall that choropelthr uses an object-oriented system. This allows you to easily make a map with sensible defaults. Some of those defaults are ggplot2 objects, such as a default projection or type of polygon to use. You can see this in the code below:

Screen Shot 2016-04-02 at 11.03.55 AM

To get around this new limitation I now initialize those values to NULL in the class definition and set them to “real” default values in the constructor of the class. You can see the diff here.

Note that I was only able to debug this with help from Hadley Wickham. I’m so appreciative of his help with the choroplethr package that I’m happy to say:

[bctt tweet=”Thanks @hadleywickham for all your help with the choroplethr package #rstats”]

Bug #2

This bug was even more pernicious than the last – in fact, I’m not sure if anyone fully understands the cause of it. But something was preventing users from using the functions in choroplethr that use the acs package. Here’s an example:

[code lang=”r”]
>library(choroplethr)
>
> get_state_demographics()
Error in (function (classes, fdef, mtable) : unable to find an inherited method for function ‘geography’ for signature ‘"matrix"’
[/code]

I originally thought that this might be related to the recent update of the acs package, but I am now less sure about that. In fact, it now seems at least possible that the change is due to something changing in recent versions of R itself.

My fix was simply to force users to load the acs library every time they load the choroplethr library. You can see the diff here – that’s the impact of moving a package from “Imports” to “Depends”. I am not a fan of this solution for a number of reasons. But at some point I realized that “making the package work” was more important than getting a clean fix to the problem. For a discussion of Imports vs. Depends in R packages, see Hadley Wickham’s discussion of it here.

Ari Lamstein

Ari Lamstein

I currently work as a Staff Data Science Engineer at a marketing analytics consultancy. I have 20 years experience developing software in areas such as data science, web development and video games. I have also worked as a technical trainer and independent consultant.

Thanks for visiting!

Sign up to stay up to date with the latest blog posts: