1

I'm trying to generate latitude and longitude in R using the localgeo package from function1 in my own package, however, I can't figure out how to do it without explicitly loading the package.

How can I enable a function within package1 easy access to package2's hidden environments and their objects?

### fails
data <- data.frame(City = c("New York", "Miami", "Los Angeles"), 
State = c("NY", "FL", "CA")
data <- cbind(data, localgeo::geocode(data[["City"]], data[["State"]]))
Error in UseMethod("tbl_vars") : 
  no applicable method for 'tbl_vars' applied to an object of class "NULL"
### works
library(localgeo)

data <- data.frame(City = c("New York", "Miami", "Los Angeles"), 
State = c("NY", "FL", "CA")
data <- cbind(data, geocode(data[["City"]], data[["State"]]))

I assume the problem is the function localgeo::geocode() looks like

function (city, state) 
{
    data.frame(city = as.character(city), state = as.character(state), 
        stringsAsFactors = FALSE) %>% left_join(.localgeo$geo_db, 
        by = c("city", "state")) %>% select(lon, lat)
}
<environment: namespace:localgeo>

and I don't know how to make .localgeo available to my function.


Updates: It seems that using Depends: localgeo in the DESCRIPTION file of my package not only "loads" but "attaches" localgeo and thus I can run the localgeo::geocode() without a problem. Of course,

Unless there is a good reason otherwise, you should always list packages in Imports not Depends. That’s because a good package is self-contained, and minimises changes to the global environment (including the search path). The only exception is if your package is designed to be used in conjunction with another package. For example, the analogue package builds on top of vegan. It’s not useful without vegan, so it has vegan in Depends instead of Imports. Similarly, ggplot2 should really Depend on scales, rather than Importing it. Namespace

Is it possible to access hidden environments in package2 in my package1 without "attaching" package2?


To those seeking an MWE, the challenge: solve this MWE

Community
  • 1
  • 1
nko_jd
  • 43
  • 4
  • The [package readme](https://github.com/hrbrmstr/localgeo) says *"This is a ridiculously small package and is really just a function interface over the `cities.rda` file in the data directory. So, just grab that if you want to wrap your own work around it."* So, maybe just grab that `.rda` file and include it as part of your package's data. Seems like the issue you're having is that `localgeo` imports `dplyr`, and you don't. You could use `dplyr` or use `merge` for your own version of the `geocode` function. – Gregor Thomas Apr 22 '19 at 18:29
  • Thanks, @Gregor, I am sure that by putting `cities.rda` in my `data/` and rewriting `geocode()` as a function inside my own package, this can work--so real life use case solvable. However, I still don't know how to easily access hidden environments and their objects from package2 in my package1. Also, my package already includes `Import: dplyr`. Thanks! – nko_jd Apr 24 '19 at 16:03

2 Answers2

0

If you are creating a package that calls functions from other packages, you want a few things.

  1. Your package directory should have a subdirectory named "R". Your functions go in a file in that "R" subdirectory.
  2. Your code should make qualified function calls. Your failing code is actually correct: localgeo::geocode().
  3. I'm guessing you're missing a part in your DESCRIPTION file in your package directory. That's where you specify package dependencies that must be loaded along with yours, using an Imports: node. A package I developed depends on several other packages. Your code doesn't call the library() function explicitly. You just say in the DESCRIPTION file what you need. When you load or build your own package, the DESCRIPTION file will include the other packages, too, and your qualified function calls will work.

Here's the node from my DESCRIPTION file as an example.

Imports: 
    stats,
    utils,
    ggplot2,
    plyr
Jai Jeffryes
  • 511
  • 5
  • 12
  • Apologies for the mixup, @jai-jeffryes! When I restarted R and computer, steps 1-3 plus `devtools::load_all(".")` was insufficient. Something extra (or different from `Imports: localgeo`) is still needed. Thanks! – nko_jd Apr 24 '19 at 16:04
  • Now I’m really curious. Is there enough on this thread to reproduce the issue? I’m starting to want to see that problem on my computer. The answer is out there somewhere. – Jai Jeffryes Apr 25 '19 at 03:23
  • It would be cool if the package build were reproducible. Do you have this package uploaded on GitHub? I'm curious to clone it and see the issue. I expect Imports: localgeo to work (which also assumes localgeo is installed!). I haven't experienced before the problems with .onAttach, etc., and I think it would be interesting to demonstrate that on my environment. – Jai Jeffryes Apr 26 '19 at 16:55
  • the challenge: [solve this MWE](https://gitlab.com/mwes/MWE.HiddenEnvironment.localgeo.Import) – nko_jd May 01 '19 at 18:01
  • @nko_jd. I see your post. No ETA for you, but I expect to be able to get to taking a clone of your MWE repo and attempting to reproduce your issue. I'll get back on this thread once I've done that. – Jai Jeffryes May 02 '19 at 19:19
0

The problem is that localgeo is buggy. It loads some data when it is attached, but using it the way you do, the package never gets attached, so the data never gets loaded. That's why the bug goes away when you call library(localgeo): that attaches it.

The fix is pretty simple. The function .onAttach in https://github.com/hrbrmstr/localgeo/blob/master/R/zzz.R should be renamed to .onLoad.

I'd suggest following @Gregor's advice, and don't bother with localgeo, but you could also submit an issue to the localgeo author at https://github.com/hrbrmstr/localgeo/issues or even a patch via a "pull request" at https://github.com/hrbrmstr/localgeo/pulls.

user2554330
  • 37,248
  • 4
  • 43
  • 90
  • are you saying that "there is no easy way to access hidden environments like `.localgeo` and their objects like `.localgeo$geo_db` in package2 when writing package1 unless package2 has use `.onAttach()` or package1 does `Depends: package2`"? – nko_jd Apr 24 '19 at 16:22
  • No, not at all. I'm saying the package is buggy, and the environment never got created. If it had been created, what you were doing would have worked. You can work around the bug by calling `localgeo:::.onAttach("foo", "bar")`, but I'd still recommend that you should follow @Gregor's advice. – user2554330 Apr 24 '19 at 20:42