Search code examples
rplotlegendmarginspar

Axis and legend problems using hist3D in r


PROGRESS UPDATES AT BOTTOM.

I am trying to get a nice looking 3D bivariate histogram using the hist3D function of the plot3D library. I've got the plot and colours working fine, but can't figure out how to manipulate the margins and axis labels properly, and the legend is also effected.

Currently I am getting rid of the original axis labels and adding a text3D (also from the plot3D library) to replace them, but I can't figure out how to give enough space for the x and y labels. I've worked around this for now putting the x labels in the plot, but ideally I'd like them under. I haven't figured out any such temporary work around for the y axis though. I'm guessing that it's something fixed with par() but I can't figure it out.

Simply, this is what I would like help achieving:

  1. to move the legend further right out of the plot area
  2. increasing the space between x-axis and title to fit labels
  3. removing tick marks from x- and y-axis's.

Any help would be really appreciated. If you think you can get what I'm looking for using different packages, that would be just as good. I think the authors of the plot I am trying to replicate used Matplotlib, but I need this in R.

Below is where I'm at right now, sample data, and code.

Thanks!

enter image description here

library(plot3D)
library(viridis)

mydata <- matrix(sample(1:6,18,replace=TRUE), nrow=6)
rownames(mydata) <- c("biological regulation","biological_process",
                         "cellular aromatic compound metabolic process",
                         "cellular metabolic process",
                         "cellular nitrogen compound metabolic process",
                         "cellular process"    )
colnames(mydata) <- c("Group1","Group2","Group3")
mydata

m <- matrix(rep(seq(1:ncol(mydata)),each=nrow(mydata)), 
            nrow = nrow(mydata))

hist3D(z =mydata, scale = FALSE, expand = 0.1, bty = "g", 
       theta = 5, phi = 5, d = 2, r=20,
       border = "black", shade = 0.2, ltheta = 80, space = 0.8, 
       ticktype = "detailed", zmin=0, zlim=c(0,max(mydata)), 
       col= viridis(ncol(mydata)), colvar = m, colkey = F, 
       xlab = "GO Term", ylab = "", zlab = "Frequency", cex.axis = 1e-9)
#xlabs
text3D(x = seq(0,1,0.2), y = rep(-0.5, 6), z = rep(max(mydata)/2, 6),
       labels = rownames(mydata),
       add = TRUE, adj = 0.5,
       srt = 90, cex = 0.5)
#ylabs
text3D(x = rep(1.4, 3),   y = seq(-.2,0.8,0.5), z = rep(0, 3),
       labels  = colnames(mydata),
       add = TRUE, adj = 1)
#zlabs
text3D(x = rep(-0.18, 7),   y = rep(0,7), z = seq(-0.1, 5.9,1),
       labels  = seq(0,max(mydata)),
       add = TRUE, adj = 1)

legend("topright",
       legend = as.factor(colnames(mydata)), # category labels
       col = viridis(ncol(mydata)),  # color key
       fill = viridis(ncol(mydata)))

PROGRESS UPDATE

I have sorted the text clipping using par(xpd) and the sizes using par(mar), and I got the legend out using inset. Still can't find how to remove the ticks. I think it's something to do with persp().

enter image description here

library(plot3D)
library(viridis)

mydata <- matrix(sample(1:6,18,replace=TRUE), nrow=6)
rownames(mydata) <- gsub("( \\S+) ", "\\1\n", 
                         c("biological regulation","biological process",
                         "cellular aromatic compound metabolic process",
                         "cellular metabolic process",
                         "cellular nitrogen compound metabolic process",
                         "cellular process"))
colnames(mydata) <- c("Group1","Group2","Group3")
mydata

m <- matrix(rep(seq(1:ncol(mydata)),each=nrow(mydata)), 
            nrow = nrow(mydata))

opar <- par(xpd=TRUE, mar=c(7,4,4,4))
hist3D(z =mydata, scale = FALSE, expand = 0.1, bty = "g", 
       theta = 5, phi = 5, d = 2, r=20,
       border = "black", shade = 0.2, ltheta = 80, space = 0.8, 
       ticktype = "detailed", zmin=0, zlim=c(0,max(mydata)), 
       col= viridis(ncol(mydata)), colvar = m, colkey = F, 
       xlab = "", ylab = "", zlab = "Frequency", cex.axis = 1e-9)
#xlabs
text3D(x = seq(0,1,0.2), y = rep(-0.5, 6), z = rep(-0.5, 6),
       labels = rownames(mydata),
       add = TRUE, adj = 1,
       srt = 90, cex = 0.75)
#ylabs
text3D(x = rep(1.4, 3),   y = seq(-.2,0.8,0.5), z = rep(0, 3),
       labels  = colnames(mydata),
       add = TRUE, adj = 1)
#zlabs
text3D(x = rep(-0.18, 7),   y = rep(0,7), z = seq(-0.1, 5.9,1),
       labels  = seq(0,max(mydata)),
       add = TRUE, adj = 1)

legend("topright",
       legend = as.factor(colnames(mydata)), # category labels
       col = viridis(ncol(mydata)),  # color key
       fill = viridis(ncol(mydata)), 
       inset=c(-0.1,0))
par(opar)

Solution

  • So I found out that I can turn all the axes off using axes = F in the hist3d call, and that's good enough for me. I then can add in axes titles at will.

    library(plot3D)
    library(viridis)
    
    mydata <- matrix(sample(1:6,18,replace=TRUE), nrow=6)
    rownames(mydata) <- gsub("( \\S+) ", "\\1\n", 
                             c("biological regulation","biological process",
                               "cellular aromatic compound metabolic process",
                               "cellular metabolic process",
                               "cellular nitrogen compound metabolic process",
                               "cellular process"))
    colnames(mydata) <- c("Group1","Group2","Group3")
    mydata
    
    m <- matrix(rep(seq(1:ncol(mydata)),each=nrow(mydata)), 
                nrow = nrow(mydata))
    
    opar <- par(xpd=TRUE, mar=c(7,4,4,4))
    hist3D(z =mydata, scale = FALSE, expand = 0.1, bty = "g", 
           theta = 5, phi = 5, d = 2, r=20,
           border = "black", shade = 0.2, ltheta = 80, space = 0.8, 
           ticktype = "detailed", zmin=0, zlim=c(0,max(mydata)), 
           col= viridis(ncol(mydata)), colvar = m, colkey = F, axes = F)
    #xlabs
    text3D(x = seq(0,1,0.2), y = rep(-0.5, 6), z = rep(-0.5, 6),
           labels = rownames(mydata),
           add = TRUE, adj = 1,
           srt = 90, cex = 0.75)
    #zlabs
    text3D(x = rep(-0.18, 7),   y = rep(0,7), z = seq(-0.1, 5.9,1),
           labels  = seq(0,max(mydata)),
           add = TRUE, adj = 1)
    #z title
    text3D(x = -0.6,   y = max(mydata)/2 , z = 0,
           labels  = "Frequency",
           add = TRUE, adj = 0.5, srt = 90)
    
    legend("topright",
           legend = as.factor(colnames(mydata)), # category labels
           col = viridis(ncol(mydata)),  # color key
           fill = viridis(ncol(mydata)), 
           inset=c(-0.1,0))
    par(opar)
    

    enter image description here