'Heatmap returning error: 'x' must be a numeric matrix, but x is a numeric matrix

I am trying to create a heatmap of species abundances across six sites. I have a matrix of sites vs species, of numeric abundance data.

However when I run my code, R returns an error that my matrix is non-numeric. Can anyone figure this one out? I am stumped.

Exported dataframe link: log_mean_wide

Working:

lrc <- rainbow(nrow(log_mean_wide), start = 0, end = .3)
lcc <- rainbow(ncol(log_mean_wide), start = 0, end = .3)


logmap <- heatmap(log_mean_wide, col = cm.colors(256), scale = "column", 
               RowSideColors = lrc, ColSideColors = lcc, margins = c(5, 10),
               xlab = "species", ylab = "Site", 
               main = "heatmap(<Auckland Council MCI data 1999, habitat:bank>, ..., scale = \"column\")")

error message: Error in heatmap(log_mean_wide, Rowv = NA, Colv = NA, col = cm.colors(256), : 'x' must be a numeric matrix

log_heatmap <- heatmap(log_mean_wide, Rowv=NA, Colv=NA, col = cm.colors(256), scale="column", margins=c(5,10)) #same error

is.numeric(log_mean_wide) #[1] FALSE
is.character(log_mean_wide) #[1] FALSE
is.factor(log_mean_wide) #[1] FALSE
is.logical(log_mean_wide) #[1] FALSE
is.integer(log_mean_wide) #[1] FALSE

?!?!

dims <- dim(log_mean_wide)
log_mean_matrix <- as.numeric(log_mean_wide) 
dim(log_mean_matrix) <- dims

Error: (list) object cannot be coerced to type 'double'

str(log_mean_wide) shows species as numeric, site as character- why does this not work then?

storage.mode(log_mean_wide) <- "numeric" 

Error in storage.mode(log_mean_wide) <- "numeric" : (list) object cannot be coerced to type 'double'



Solution 1:[1]

There are two issues:

  1. The first column log_mean_wide$Site is non-numeric.
  2. heatmap only accepts a matrix as input data (not a data.frame).

To address these issues, you can do the following (mind you, there is a lot of clutter in the heatmap):

# Store Site information as rownames
df <- log_mean_wide;
rownames(df) <- log_mean_wide[, 1];

# Remove non-numeric column
df <- df[, -1];

# Use as.matrix to convert data.frame to matrix
logmap <- heatmap(
    as.matrix(df),
    col = cm.colors(256),
    scale = "column",
    margins = c(5, 10),
    xlab = "species", ylab = "Site",
    main = "heatmap(<Auckland Council MCI data 1999, habitat:bank>, ..., scale = \"column\")")

enter image description here

Solution 2:[2]

This is an old question but since I spent some time figuring out what the issue was, I will add an answer here. Drawing a heatmap, specifically adding an annotation column may fail if the annotation data is a tibble.

Reproducible example:

test = matrix(rnorm(200), 20, 10)
test[1:10, seq(1, 10, 2)] = test[1:10, seq(1, 10, 2)] + 3
test[11:20, seq(2, 10, 2)] = test[11:20, seq(2, 10, 2)] + 2
test[15:20, seq(2, 10, 2)] = test[15:20, seq(2, 10, 2)] + 4
colnames(test) = paste("Test", 1:10, sep = "")
rownames(test) = paste("Gene", 1:20, sep = "")
annotation_col = data.frame(
  CellType = factor(rep(c("CT1", "CT2"), 5)), 
  Time = 1:5
)
rownames(annotation_col) = paste("Test", 1:10, sep = "")
pheatmap::pheatmap(test, annotation_col = 
                     annotation_col)

The above works. However, if you instead were using a tibble, you would get an error

pheatmap::pheatmap(test, annotation_col = 
                     dplyr::as_tibble(annotation_col))

Error in cut.default(a, breaks = 100) : 'x' must be numeric

NOTE

I think it would have been better for this error to specify that we needed a data.frame instead of something else. That might have been more specific.

See this issue.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Maurits Evers
Solution 2