7

Melting the dataframe t.wide changes how the column "time" (class POSIXct) is printed.

t.wide <- data.frame(product=letters[1:5], 
                     result=c(2, 4, 0, 0, 1), 
                     t1=as.POSIXct("2014-05-26") + seq(0, 10800, length.out=5),
                     t2=as.POSIXct("2014-05-27") + seq(0, 10800, length.out=5),
                     t3=as.POSIXct("2014-05-28") + seq(0, 10800, length.out=5))

library(reshape2)     
t.long <- melt(t.wide, measure.vars=c("t1", "t2", "t3"), value.name="time")
t.long$time
 [1] 1401055200 1401057900 1401060600 1401063300 1401066000 1401141600 1401144300
 [8] 1401147000 1401149700 1401152400 1401228000 1401230700 1401233400 1401236100
[15] 1401238800
attr(,"class")
[1] "POSIXct" "POSIXt" 

Strangely, if print() is called explicitly, the object is printed as expected (timestamps, not their numeric representation).

print(t.long$time)
 [1] "2014-05-26 00:00:00 CEST" "2014-05-26 00:45:00 CEST" "2014-05-26 01:30:00 CEST"
 [4] "2014-05-26 02:15:00 CEST" "2014-05-26 03:00:00 CEST" "2014-05-27 00:00:00 CEST"
 [7] "2014-05-27 00:45:00 CEST" "2014-05-27 01:30:00 CEST" "2014-05-27 02:15:00 CEST"
[10] "2014-05-27 03:00:00 CEST" "2014-05-28 00:00:00 CEST" "2014-05-28 00:45:00 CEST"
[13] "2014-05-28 01:30:00 CEST" "2014-05-28 02:15:00 CEST" "2014-05-28 03:00:00 CEST"

Setting the attributes to the same value as before magically changes how the object is printed.

attributes(t.long$time) <- attributes(t.long$time)
t.long$time
 [1] "2014-05-26 00:00:00 CEST" "2014-05-26 00:45:00 CEST" "2014-05-26 01:30:00 CEST"
 [4] "2014-05-26 02:15:00 CEST" "2014-05-26 03:00:00 CEST" "2014-05-27 00:00:00 CEST"
 [7] "2014-05-27 00:45:00 CEST" "2014-05-27 01:30:00 CEST" "2014-05-27 02:15:00 CEST"
[10] "2014-05-27 03:00:00 CEST" "2014-05-28 00:00:00 CEST" "2014-05-28 00:45:00 CEST"
[13] "2014-05-28 01:30:00 CEST" "2014-05-28 02:15:00 CEST" "2014-05-28 03:00:00 CEST"

Can anyone explain this behavior?

Roland
  • 127,288
  • 10
  • 191
  • 288
Tobias
  • 422
  • 2
  • 6
  • Actually, you've made a mistake at the end of your question: You're assigning the `attributes` of `t.long$time` to `t.long$time`, so the outcome shouldn't change at all, making this behaviour even stranger! – Scott Ritchie Jun 05 '14 at 12:23
  • Could you add the session info? I cannot reproduce the behavior with R 2.15.1 and reshape2_1.2.2 – Zhenglei Jun 05 '14 at 12:45
  • 1
    I can reproduce it with R 3.1.0 and reshape2 1.4. – Roland Jun 05 '14 at 12:49
  • @Roland, I wasn't able to reproduce it with reshape2 1.2.2 but was able with reshape2 1.4. Sounds like a potential bug to me. Otherwise, why on earth it returns `attr(,"class") [1] "POSIXct" "POSIXt"` too when you do `t.long$time` – David Arenburg Jun 05 '14 at 13:30
  • @ScottRitchie, no thats not a mistake. I'd also expect the outcome to be the same, but it isn't. I will post the Sessioninfo as soon as I have access to that machine again. Roland, thanks for cleaning the code. – Tobias Jun 05 '14 at 13:41

1 Answers1

6

UPDATE:

I opened this as Issue #50 on the git repo hadley/reshape2.


UPDATE: FIXED

This issue has been fixed in the development version of reshape2.

Thanks @kevin-ushey!


I believe the reason is because after the reshaping for whatever reason R does not think that t.long$time has attributes. For some reason the OBJECT flag (which indicates the vector has attributes) in the SEXP header for your vector is not being set. When you copy the attributes back to it, the OBJECT flag gets set and the correct print method is dispatched...

# No "OBJ" in SEXP header (the '[NAM(2),ATT]' part below)
 .Internal(inspect( t.long$time ) )
#@10359e548 14 REALSXP g0c6 [NAM(2),ATT] (len=15, tl=0) 1.40106e+09,...

# Now we have "OBJ" in the SEXP header indicating attributes
# So the print method for POSIXct get dispatched...
attributes(t.long$time) <- attributes(t.long$time)
 .Internal(inspect( t.long$time ) )
#@1118d7f50 14 REALSXP g0c6 [OBJ,NAM(2),ATT] (len=15, tl=0) 1.40106e+09,...

From the R Internals document...

The actual autoprinting is done by PrintValueEnv in file print.c. If the object to be printed has the S4 bit set and S4 methods dispatch is on, show is called to print the object. Otherwise, if the object bit is set (so the object has a "class" attribute), print is called to dispatch methods: for objects without a class the internal code of print.default is called.

Check the difference between..

print.default(t.long$time)
# [1] 1401058800 1401061500 1401064200 1401066900 1401069600 1401145200 1401147900 1401150600 1401153300 1401156000 1401231600 1401234300
#[13] 1401237000 1401239700 1401242400
#attr(,"class")
#[1] "POSIXct" "POSIXt" 
print.POSIXct(t.long$time)
# [1] "2014-05-26 00:00:00 BST" "2014-05-26 00:45:00 BST" "2014-05-26 01:30:00 BST" "2014-05-26 02:15:00 BST" "2014-05-26 03:00:00 BST"
# [6] "2014-05-27 00:00:00 BST" "2014-05-27 00:45:00 BST" "2014-05-27 01:30:00 BST" "2014-05-27 02:15:00 BST" "2014-05-27 03:00:00 BST"
#[11] "2014-05-28 00:00:00 BST" "2014-05-28 00:45:00 BST" "2014-05-28 01:30:00 BST" "2014-05-28 02:15:00 BST" "2014-05-28 03:00:00 BST"

Now I can only speculate, but perhaps this is due to some internal code in reshape2 and is related to this warning..

One thing to watch is that if you copy attributes from one object to another you may (un)set the "class" attribute and so need to copy the object and S4 bits as well. There is a macro/function DUPLICATE_ATTRIB to automate this.

Community
  • 1
  • 1
Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184