# An R flaw: unexpected attribute droppings

February 6, 2014
By

(This article was first published on Odd Hypothesis, and kindly contributed to R-bloggers)

Today I was putting some code together that made plots from slices of a 3-dimensional `array` object `aa`. A couple of the dimensions in `aa` had names defined by named vectors. For example:

``> aa = array(runif(2*3*4),              dim=c(2,3,4),              dimnames=list(id  = c(good='id1', evil='id2'),                            x   = c(1,2,3),                            var = c(up='a', dn='b', lt='c', rt='d')))> str(aa) num [1:2, 1:3, 1:4] 0.0138 0.2942 0.7988 0.3465 0.8751 ... - attr(*, "dimnames")=List of 3  ..\$ id : Named chr [1:2] "id1" "id2"  .. ..- attr(*, "names")= chr [1:2] "good" "evil"  ..\$ x  : chr [1:3] "1" "2" "3"  ..\$ var: Named chr [1:4] "a" "b" "c" "d"  .. ..- attr(*, "names")= chr [1:4] "up" "dn" "lt" "rt"``

Thus, I could access “aliases” for dimension names in `id` and `var` by:

``> names(dimnames(aa)\$id) "good" "evil"> names(dimnames(aa)\$var) "up" "dn" "lt" "rt"``

The code I wrote would iterate over the 3rd dimension, using the resulting 2D `array`’s to produce a series of plots using `matplot()`. To make legends more readable, I made use of the `names` attribute for `dimnames` as above. In the first version, I used `apply()` to do the iterating:

``> apply(aa, 3, function(xy) {    x = as.numeric(dimnames(xy)\$x)    matplot(x, y=t(xy))    legend('topleft', legend=names(dimnames(xy)\$id), fill=1:nrow(xy))    NULL  })``

This worked perfectly fine, however, later I decided it would be more informative to use the names in the iterating dimension for a plot title. So I refactored a bit to use `sapply()`:

``> sapply(1:dim(aa), function(k) {    xy = aa[,,k]    x = as.numeric(dimnames(xy)\$x)    matplot(x, y=t(xy))    legend('topleft', legend=names(dimnames(xy)\$id), fill=1:nrow(xy))    title(main=names(dimnames(aa)\$var[k]))    NULL  })``

I was a little surprised that this threw an error indicating that the names associated with `dimnames(aa)\$id` were non-existant:

`` Error in legend("topleft", legend = names(dimnames(xy)\$id), fill = 1:nrow(xy)) :   'legend' is of length 0 ``

Upon inspection, it seems that it is R’s default behavior to drop attributes on `dimnames` when an `array` is subsetted.

``> str(aa[,,1]) num [1:2, 1:3] 0.0138 0.2942 0.7988 0.3465 0.8751 ... - attr(*, "dimnames")=List of 2  ..\$ id: chr [1:2] "id1" "id2"  ..\$ x : chr [1:3] "1" "2" "3"``

Adding a `drop=FALSE` to the indexing doesn’t work. The only fix I could come up with was to reassign the additional attributes after subsetting:

``> sapply(1:dim(aa), function(k) {    xy = aa[,,k]    # !! recover additional dimname attributes     #    dropped by subsetting !! #    dimnames(xy) = dimnames(aa)[names(dimnames(aa)) %in% names(dimnames(xy))]    x = as.numeric(dimnames(xy)\$x)    matplot(x, y=t(xy))    legend('topleft', legend=names(dimnames(xy)\$id), fill=1:nrow(xy))    title(main=names(dimnames(aa)\$var[k]))    NULL  })``

To the greater R community, I ask – is this behavior a flaw, or was it done on purpose? If the latter, I pleadingly ask WHYYYYyyyyyyyy!

Written with StackEdit.

To leave a comment for the author, please follow the link and comment on their blog: Odd Hypothesis.

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...

If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.

# Never miss an update! Subscribe to R-bloggers to receive e-mails with the latest R posts.(You will not see this message again.)

Click here to close (This popup will not appear again)