I am currently creating a 3D scatterplot using the plot3D package in R, and I wanted to add data labels to my data points. However, some of my data points have the same values with each other, and I wanted to find a solution similar to ggrepel
that would offset the data labels from the points so that the labels for those points would be legible. Sample code below:
library(plot3D)
names <- c("A", "B", "C", "D", "E")
x <- c(1,1,2,3,4)
y <- c(1,1,3,4,5)
z <- c(1,1,4,5,6)
scatter3D(x, y, z)
text3D(x,y,z, names, add = TRUE, cex = 1)
The labels for A and B are currently superimposed on top of each other.
I tried to use the directlabels
package as well, and it doesn't seem to recognize the text3D or the plot3D objects. Any help would appreciated.
The plotrix::thigmophobe
function works out directions to try to stop labels from overlapping in 2D plots. rgl
doesn't have anything equivalent, and since you can rotate a plot, you'll always be able to rotate labels on top of each other. However, the function below makes an attempt to place labels for one particular view so that they don't overlap.
thigmophobe.text3d <- function(x, y = NULL, z = NULL, texts, ...) {
xyz <- xyz.coords(x, y, z)
# Get the coordinates as columns in a matrix in
# homogeneous coordinates
pts3d <- rbind(xyz$x, xyz$y, xyz$z, 1)
# Apply the viewing transformations and convert
# back to Euclidean
pts2d <- asEuclidean(t(par3d("projMatrix") %*%
par3d("modelMatrix") %*%
pts3d))
# Find directions so that the projections don't overlap
pos <- plotrix::thigmophobe(pts2d)
# Set adjustments for the 4 possible directions
adjs <- matrix(c(0.5, 1.2,
1.2, 0.5,
0.5, -0.2,
-0.2, 0.5),
4, 2, byrow = TRUE)
# Plot labels one at a time in appropriate directions.
for (i in seq_along(xyz$x))
text3d(pts3d[1:3, i], texts = texts[i],
adj = adjs[pos[i],], ...)
}
There are some problems with the function above: it is based on rgl::text3d
rather than plot3D::text3D
, so the optional arguments are different; it plots labels one at a time, which can be inefficient if you have a lot of labels, it doesn't do error checking, etc.
Edited to add:
The unreleased version 0.99.20 of rgl
adds a thigmophobe3d
function to do this. You'll have to get it from https://r-forge.r-project.org/R/?group_id=234 or the Github mirror https://github.com/rforge/rgl for now.