Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reshape2 calls melt.data.frame function incorrectly if the reshape package was loaded #63

Open
wdesouza opened this issue Dec 10, 2014 · 7 comments

Comments

@wdesouza
Copy link

If the reshape package is loaded at the same environment that the package reshape2 then reshape2::melt function will incorrectly call reshape::melt.data.frame function instead of reshape2::melt.data.frame. An example below:

df <- data.frame(a=1, b=2, c=3)
library(reshape2)
reshape2::melt(df, id.vars = "a", variable.name = "NAME")
library(reshape)
reshape2::melt(df, id.vars = "a", variable.name = "NAME")

The output is different between function calls because variable.name argument is defined as variable_name on reshape package. This issue might break package that uses reshape2 instead of reashape package.

@jhuovari
Copy link

This issue is also affecting tidyr. I can reproduce the issue in: tidyverse/tidyr#29 and it seems that it comes from the call to reshape2::melt on gather_

Modified example from the tidyr issue:

stocks <- data.frame(
    time = as.Date('2009-01-01') + 0:9,
    X = rnorm(10, 0, 1),
    Y = rnorm(10, 0, 2),
    Z = rnorm(10, 0, 4)
  )

names(reshape2::melt(stocks, measure.vars = c("X","Y","Z"),
                        variable.name = "stock", value.name = "price", na.rm = FALSE))

[1] "time" "stock" "price"

library(reshape)
names(reshape2::melt(stocks, measure.vars = c("X","Y","Z"),
                        variable.name = "stock", value.name = "price", na.rm = FALSE))

[1] "time" "variable" "value"

@odeleongt
Copy link

This is not a problem with either reshape2 or reshape, it is an expected consequence of calling a generic function (i.e. reshape2::melt) in a context where the conflicting name (i.e. reshape::melt.data.frame) is found before the expected name (i.e. reshape2:::melt.data.frame).

According to ?UseMethod the dispatch mechanism looks first in the environment in which the generic was called. So, if reshape is in found in search() (i.e. it was explicitly attached), the reshape::melt.data.frame method will be used (because it is exported from reshape) and the method from reshape2 will never be available (since it is not exported). When the method is not found in the search path, the dispatch will look in the NAMESPACE in which the generic is registered (i.e. reshape2), thus finding the correct method.

If your code depends on using reshape (interactively), consider just loading it (i.e. using reshape::<needed-function> each time).

If your problem is with a package, the problem goes deeper since [it] is bad practice for package code to alter the search path using library, require or attach and this often does not work as intended (as documented in Writing R Extensions).

@saurfang
Copy link

ditto @odeleongt
This is exactly the expected behavior. If you load reshape2 and reshape in sequence, R warns you about this:

library(reshape2)
library(reshape)
Attaching package:reshapeThe following objects are masked frompackage:reshape2:

    colsplit, melt, recast

You can see reshape2's colsplit melt recast have now been masked and will resolve to reshape implementation instead. If this is caused by your code, you can either call reshape::<function> when you need reshape or load reshape first rather than second. If this is caused by some packages that depends on reshape, that's a bit troublesome considering the two implementations are not fungible. Package should really import rather than depend to avoid polluting the user namespace. You can painfully use reshape2::<function> to make sure you are calling the correct function.

@jonathon-love
Copy link

You can painfully use reshape2:: to make sure you are calling the correct function.

this isn't actually correct. if reshape has been library()ed, calling reshape2::melt() on a data frame will not use reshape2::melt.data.frame(), but i think will call the reshape::melt.data.frame() instead.

we just got caught out with this, because we call reshape2::melt() from our package, but if the user has previously called library(reshape) then our package breaks.

we can't work around this by calling reshape2::melt.data.frame() because that's not exporting from the reshape2 package.

for example, value.name is ignored in the second call:

data("airquality")

melted <- reshape2::melt(airquality, value.name='BRUCE')
print(names(melted))

library('reshape')

melted <- reshape2::melt(airquality, value.name='BRUCE')
print(names(melted))

@jonathon-love
Copy link

a solution would be to add melt.data.frame() to the exports in NAMESPACE.

this would allow people to call reshape2::melt.data.frame() directly, without the unwanted reshape2::melt() -> reshape::melt.data.frame() redirection.

happy to submit a PR if people see this as a good solution.

i can't think of a better one.

with thanks

@odeleongt
Copy link

Seeing as neither reshape nor reshape2 are under active development, instead of exposing the reshape2:::melt.data.frame method you could explicitly call it as I did there, with three colons, right? Or use tidyr::gather.

@jonathon-love
Copy link

with three colons

ah, i did not know about the 3 colons.

with thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants