39

Is there a way to import a package with another name in R, the way you might with import as in Python, e.g. import numpy as np? I've been starting to use package::function lately to avoid conflicts between, say, Hmisc::summarize and plyr::summarize.

I'd like to be able to instead write h::summarize and p::summarize, respectively. Is this possible in R?

sieste
  • 8,296
  • 3
  • 33
  • 48
shadowtalker
  • 12,529
  • 3
  • 53
  • 96
  • Is that for use in a package? – Roland Jun 24 '14 at 16:05
  • Nope, I just don't want carpal tunnel (`expression()` is my new favorite function) and I also don't like unpredictable errors. Although eventually I do plan to work on packages so if there are separate considerations in that case I'd like to hear about them. – shadowtalker Jun 24 '14 at 16:11
  • 1
    Are you really running into conflicts that often that something like this would be necessary? Or is it just a few of your favorite functions in a couple of packages? – A5C1D2H2I1M1N2O1R2T1 Jun 24 '14 at 16:50
  • It's just an issue I've run into more than once. I also tend to write lots of masking and wrapper functions for personal use that sometimes result in unforseen conflicts down the road. – shadowtalker Jun 24 '14 at 17:06
  • 2
    These are really the *most predictable* errors you could come across. For summarize, you could use `summarise` in plyr and `summarize` in Hmisc. Saving yourself three or four characters to avoid explicitly `Hmisc::`'ing is silly. A better way would be to use `expr` to fill in the rest which also will show you the package in which they reside. I will enjoy my carpal tunnel and write `package::function` a couple times. – rawr Jun 24 '14 at 17:13
  • To the best of my knowledge, there is no way of renaming packages when loading them in R. – Roland Jun 24 '14 at 17:13
  • @Roland please put that as an answer so I can mark it then. – shadowtalker Jun 24 '14 at 17:17
  • I’m working on getting [modules](https://github.com/klmr/modules) to work with conventional packages. Once that’s completed, it will solve this problem in a non-hacky way (e.g. it will work with documentation, unlike Thomas’ solution posted further down). – Konrad Rudolph Mar 07 '15 at 14:03
  • @KonradRudolph I'm so glad that's a thing! Is it just environments underneath? How will it interact with "real" packages? – shadowtalker Mar 07 '15 at 14:12
  • @ssdecontrol At the end everything is just an environment underneath in R. However, package environments have lots of metadata attached, which needs to happen here as well. In that regard, this method is equivalent to normal package loading. Where it differs is that normal package loading attaches them – this doesn’t happen here. – Konrad Rudolph Mar 08 '15 at 13:18
  • @wordsforthewise not really. In fact I now believe this should be possible with the info [here](https://stackoverflow.com/questions/24742927/how-to-manually-create-and-load-namespaces-in-r). – shadowtalker Oct 31 '17 at 23:28
  • @ssdecontrol The 4 lines of code to do the same thing as `import numpy as np` in Python look pretty confusing at first glance. – wordsforthewise Nov 01 '17 at 04:29

7 Answers7

25

This is not quite what you want because it involves changing from :: notation to $ notation, but if you load a package namespace (without attaching it), you can then refer to it by its environment name:

h <- loadNamespace('Hmisc')
p <- loadNamespace('plyr')

> summarize(iris$Sepal.Length, iris$Species, FUN=mean)
Error: could not find function "summarize"

> Hmisc::summarize(iris$Sepal.Length, iris$Species, FUN=mean)
  iris$Species iris$Sepal.Length
1       setosa             5.006
2   versicolor             5.936
3    virginica             6.588

> h$summarize(iris$Sepal.Length, iris$Species, FUN=mean)
  iris$Species iris$Sepal.Length
1       setosa             5.006
2   versicolor             5.936
3    virginica             6.588

> summarise(iris, x = mean(Sepal.Length))
Error: could not find function "summarise"

> plyr::summarise(iris, x = mean(Sepal.Length))
         x
1 5.843333

> p$summarise(iris, x = mean(Sepal.Length))
         x
1 5.843333

Note, however, that you do lose access to documentation files using the standard ? notation (e.g., ? p$summarise does not work). So, it will serve you well as shorthand, but may not be great for interactive use since you'll still have to resort to ? plyr::summarise for that.

Note also that you do not have access to the data objects stored in the package using this approach.

jciloa
  • 1,039
  • 1
  • 11
  • 22
Thomas
  • 43,637
  • 12
  • 109
  • 140
  • 2
    This does not seem to make package data available through the $ operator. – jciloa Jan 18 '21 at 12:11
  • 1
    @jciloa If you’re looking for a unified approach that also works for package data, [the dev version of ‘box’ now supports this](https://github.com/klmr/box/issues/219#issuecomment-950388573). – Konrad Rudolph Oct 31 '21 at 12:35
20

Here's a solution that should only be used for interactive mode. You modify :: so that it can accept character package names, then write a function to register the aliases.

`::` <- function(pkg, name) {
    sym <- as.character(substitute(pkg))
    pkg <- tryCatch(get(sym, envir=.GlobalEnv), error=function(e) sym)
    name <- as.character(substitute(name))
    getExportedValue(pkg, name)
}

pkg.alias <- function(alias, package) {
    assign(alias, package, .GlobalEnv)
    lockBinding(alias, .GlobalEnv)
}

pkg.alias('r', 'reshape2')
r::dcast

But instead of using aliases, you could also redefine :: to find the package that matches your abbreviation:

`::` <- function(pkg, name)  {
    pkg <- as.character(substitute(pkg))
    pkg <- installed.packages()[grepl(paste0('^', pkg), installed.packages())]
    name <- as.character(substitute(name))
    getExportedValue(pkg, name)
}

ggp::ggplot
Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
  • This is what I was looking for. Also a good example of what `substitute()` actually does. – shadowtalker Jun 24 '14 at 18:40
  • Trying to magically figure out whether an argument should be evaluated or not is a baaaaaaad idea. – hadley Jun 24 '14 at 19:31
  • @hadley I've updated my answer so that it can't be used inside functions. – Matthew Plourde Jun 24 '14 at 19:57
  • For use from the command line, I would expect the package content names to show up once I enter `::`. Unfortunately they don't show up. It works with the accepted answer. – jciloa Jan 18 '21 at 13:24
14

Rather than aliasing the package, why not just alias the function?

hsumm <- Hmisc::summarize
dsumm <- dplyr::summarize
psumm <- plyr::summarize

I was starting down an eval(parse()) path, but I ran into trouble and need to get back to work. @Thomas's answer seems to get a similar result in a much smoother way, but here's the non-working draft.

package_alias <- function(package, alias, infix = "..") {
    funs <- ls(paste0("package:", package))
    for (i in seq_along(funs)) {
        assign(paste0(alias, infix, funs[i]),
        value = eval(parse(text = funs[i])), envir = .GlobalEnv)
    }
}

With the idea that you could do something like

package_alias("plyr", "p")

to create p..ddply, etc.

Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
  • 1
    Because I don't want to. See my comment to the other answer; it still fails to be a robust general solution. That said, I'm not looking for a workaround. – shadowtalker Jun 24 '14 at 17:10
  • 1
    If it's the punctuation in your function call that you miss, you could go with `h..suummarize <- Hmisc::summarize` ;) – Gregor Thomas Jun 24 '14 at 17:13
  • 1
    I just want to say that I came back to this question and I like this answer a lot more than when I first saw it. +1 for practicality. – shadowtalker Aug 15 '14 at 06:34
13

Use the namespace package to generate another namespace aliased to the one you are interested in.

library(namespace)
registerNamespace('ggp', loadNamespace('ggplot2'))
data(iris)
ggp::ggplot(iris, ggp::aes(x = Petal.Length, y = Sepal.Length)) + ggp::geom_point()

Note this has the disadvantage of making the package versioning/installation requirements more opaque for scripts.

Andrew M
  • 490
  • 5
  • 11
4

Too long to fit nicely in comment box, so pseudo-answer:

If it's only a few (or few dozen) functions, how about an override wrapper function, e.g.

summarize<-function(whichone='h',//all variables for either "summarize"// ) {
 switch(whichone,
      'h' = Hmisc::summarize(//all the appropriate variables//),
      'p' = plyr:: summarize(//all the appropriate variables//)
       )
}
Carl Witthoft
  • 20,573
  • 9
  • 43
  • 73
  • 3
    Thanks, but I guess the whole point of this question is circumventing the part where you have to *know* which functions conflict. I know you can use `conflicts` but that could get annoying, and it doesn't lead to robust code (preventing *future* overlaps). And FYI this is where the `...` argument is really handy. – shadowtalker Jun 24 '14 at 17:06
4

I'd like to be able to instead write h::summarize and p::summarize, respectively. Is this possible in R?

You could use box:

box::use(
  h = Hmisc,
  p = plyr,
)

h$summarize(…)
p$summarize(…)

But box::use provides a lot more flexibility than just that. It’s your one-stop shop for all your code reuse needs. For example, you could also decide to import all names from one package and rename some if its symbols; for instance:

box::use(
  h = Hmisc,
  plyr[..., p_summarize = summarize],
)

This allows you to use ‘Hmisc’ names by prefixing them with h$ as before, and all names from ‘plyr’ without prefixing them with anything (they’re attached); except for plyr::summarize, which has been attached under the alias p_summarize.

Note, furthermore, that unlike with library attaching happens locally. For example, you can use the above box::use declaration inside a function. ‘plyr’ is then “attached” only inside the function. Outside the function, code is unaffected.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
0

there is an R package, aptly named import check it out. I believe it offers that Python-like capability.

A link to a vignette of the import package

And another link with some introduction

Finally, some more information about advanced usage

GSA
  • 751
  • 8
  • 12
  • A [link to the package or repo](https://github.com/rticulate/import) may have been helpful, and no, it is not new: initial commit nine years ago. As one illustration, it is so old that under 'see also' it still refers to `modules` rather than `box`. – Dirk Eddelbuettel Apr 03 '23 at 12:36