11

How can I create a 3D histogram with R?

For example, I have two variables to be counted for the number of times they fall in a defined two dimensional bin. So I have two variables in the X and Y axis, while the Z axis is the count of the two variables.

Jin
  • 12,748
  • 3
  • 36
  • 41
emanuele
  • 2,519
  • 8
  • 38
  • 56
  • This question would fit better on CrossValidated. I have flagged it for moderator attention. – Andrie Oct 07 '11 at 08:43
  • I have to admit that I don't understand the closing. IMHO this question may easily be answered software-related (which I understand to be the topic here): e.g. have a look at package hexbin or ggplot's `stat_bin2d` / `stat_binhex`. You get 2 spatial coordinates which is all your screen or paper can do plus a 3rd, colour-coded dimension. That being said, it may rather be worth closing as duplicate of http://stackoverflow.com/questions/2405575/how-does-one-plot-a-3d-stacked-histogram-in-r (where, however the 3 dimensions were discussed purely spatially). – cbeleites unhappy with SX Oct 07 '11 at 11:58
  • 1
    By the way: I'd call two variables X and Y and their counts in Z rather a 2d histogram. – cbeleites unhappy with SX Oct 07 '11 at 12:01
  • @cbeleites: Yes, the question has been reopened (see revisions). If this is a duplicate then we should close it as such. If the other question is missing details, feel free to add an answer over there. – Bobby Oct 07 '11 at 12:52
  • Have you considered a heatmap instead? The pheatmap package can make them quite nicely. – rmccloskey Mar 13 '15 at 20:58

3 Answers3

7

have a look at package hexbin to calculate and display, or e.g. ggplot's stat_bin2d / stat_binhex for display. You get 2 spatial coordinates which is all your screen or paper can do plus a 3rd, colour-coded dimension.

Note that How does one plot a 3D stacked histogram in R? is quite a duplicate of this question (but the 3rd dimension was discussed spatially there).

Community
  • 1
  • 1
cbeleites unhappy with SX
  • 13,717
  • 5
  • 45
  • 57
1

The rgl package has a function hist3d (not actually in the doc, but you can call it and also see the code).

Though this hist3d is, for me displaying a 2-dimensional histograms (input = x,y) in 3 dimensions.

If that is what you want here is the code (from rgl):

> hist3d
function(x,y=NULL,nclass="auto",alpha=1,col="#ff0000",scale=10)
  {
  save <- par3d(skipRedraw=TRUE)
  on.exit(par3d(save))
  xy <- xy.coords(x,y)
  x <- xy$x
  y <- xy$y
  n<-length(x)
  if (nclass == "auto") { nclass<-ceiling(sqrt(nclass.Sturges(x))) }
  breaks.x <- seq(min(x),max(x),length=(nclass+1))
  breaks.y <- seq(min(y),max(y),length=(nclass+1))
  z<-matrix(0,(nclass),(nclass))
  for (i in 1:nclass) 
    {
    for (j in 1:nclass) 
      {
      z[i, j] <- (1/n)*sum(x < breaks.x[i+1] & y < breaks.y[j+1] & 
                            x >= breaks.x[i] & y >= breaks.y[j])
      binplot.3d(c(breaks.x[i],breaks.x[i+1]),c(breaks.y[j],breaks.y[j+1]),
                 scale*z[i,j],alpha=alpha,topcol=col)
      }
    }
}

I built my own hist3d to return 3-dimensional histogram (for example to use on Red Green Blue):

my_hist3d <- function(x,y=NULL,z=NULL, nclass="auto",alpha=1,col="#ff0000",scale=10)
  {

  xyz <- xyz.coords(x,y,z)
  x <- xyz$x
  y <- xyz$y
  z <- xyz$z

  n<-length(x)

  if (nclass == "auto") { nclass<-ceiling(sqrt(nclass.Sturges(x))) }

  breaks.x <- seq(min(x),max(x),length=(nclass+1))
  breaks.y <- seq(min(y),max(y),length=(nclass+1))
  breaks.z <- seq(min(z),max(z),length=(nclass+1))


  h = array(1:(nclass^3), dim=c(nclass,nclass,nclass))

  for (i in 1:nclass) 
    {
    for (j in 1:nclass) 
      {
        for (k in 1:nclass) 
          {
              h[i,j,k] <- (1/n)*sum(x < breaks.x[i+1] & y < breaks.y[j+1] & x >= breaks.x[i] & y >= breaks.y[j] & z < breaks.z[k+1] & z >= breaks.z[k])
          }
      }
    }

  return(h)
}

The variable returned (h) is a three-dimensional matrix of size nclass^3 (nclass is the number of bins in each dimension).

Timothée HENRY
  • 14,294
  • 21
  • 96
  • 136
1

You can use the next function based on tucson function to plot a histogram in 3d.

my_hist3d <- function(x, y, freq=FALSE, nclass="auto") {
  n<-length(x)
  if (nclass == "auto") { nclass<-ceiling(sqrt(nclass.Sturges(x))) }
  breaks.x <- seq(min(x),max(x),length=(nclass+1))
  breaks.y <- seq(min(y),max(y),length=(nclass+1))
  h <- NULL
  for (i in 1:nclass) 
    for (j in 1:nclass) 
      h <- c(h, sum(x <= breaks.x[j+1] & x >= breaks.x[j] & y <= breaks.y[i+1] & y >= breaks.y[i] ) )
  if (freq) h <- h / n
  xx <- as.factor(round(mean(breaks.x[1:2])+(0:(nclass-1))*diff(breaks.x[1:2]), 1))
  yy <- as.factor(round(mean(breaks.y[1:2])+(0:(nclass-1))*diff(breaks.y[1:2]), 1))
  res <- cbind(expand.grid(xx,yy), h)
  colnames(res) <- c(deparse(substitute(x)),deparse(substitute(y)),'Frequency')
  formu <- as.formula(paste("Frequency ~ ", paste(colnames(res)[1:2], collapse= "+")))
  cloud(formu, res, panel.3d.cloud=panel.3dbars, col.facet='lightblue', 
       xbase=1, ybase=1, scales=list(arrows=FALSE, col=1), 
        par.settings = list(axis.line = list(col = "transparent")))
}

library(latticeExtra)

height <- rbeta(2000, 2, 5)
weight <- rgamma(2000, 10)
my_hist3d(height, weight, nclass=10)
Freddy
  • 401
  • 4
  • 12