/
display-density2d.r
137 lines (127 loc) · 4.42 KB
/
display-density2d.r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#' Display tour path with a density and scatterplot
#'
#' Animate a 2D tour path with density contour(s) and a scatterplot.
#'
#' @param axes position of the axes: center, bottomleft or off
#' @param center if TRUE, centers projected data to (0,0). This pins the
#' center of data cloud and make it easier to focus on the changing shape
#' rather than position.
#' @param half_range half range to use when calculating limits of projected.
#' If not set, defaults to maximum distance from origin to each row of data.
#' @param edges A two column integer matrix giving indices of ends of lines.
#' @param col color to use for points, can be a vector or hexcolors or a factor. Defaults to "black".
#' @param pch shape of the point to be plotted. Defaults to 20.
#' @param cex size of the point to be plotted. Defaults to 1.
#' @param contour_quartile Vector of quartiles to plot the contours at. Defaults to 5.
#' @param palette name of color palette for point colour, used by \code{\link{hcl.colors}}, default "Zissou 1"
#' @param ... other arguments passed on to \code{\link{animate}} and
#' \code{\link{display_density2d}}
#' @importFrom graphics contour
#' @importFrom stats quantile
#' @export
#' @examples
#' animate_density2d(flea[, 1:6])
#' animate(flea[, 1:6], tour_path = grand_tour(), display = display_density2d())
#' animate(flea[, 1:6],
#' tour_path = grand_tour(),
#' display = display_density2d(axes = "bottomleft")
#' )
#' animate(flea[, 1:6],
#' tour_path = grand_tour(),
#' display = display_density2d(half_range = 0.5)
#' )
#' animate_density2d(flea[, 1:6], tour_path = little_tour())
#'
#' animate_density2d(flea[, 1:3], tour_path = guided_tour(holes()), sphere = TRUE)
#' animate_density2d(flea[, 1:6], center = FALSE)
#'
#' # The default axes are centered, like a biplot, but there are other options
#' animate_density2d(flea[, 1:6], axes = "bottomleft")
#' animate_density2d(flea[, 1:6], axes = "off")
#' animate_density2d(flea[, 1:6], dependence_tour(c(1, 2, 1, 2, 1, 2)),
#' axes = "bottomleft"
#' )
#'
#' animate_density2d(flea[, -7], col = flea$species)
#'
#' # You can also draw lines
#' edges <- matrix(c(1:5, 2:6), ncol = 2)
#' animate(
#' flea[, 1:6], grand_tour(),
#' display_density2d(axes = "bottomleft", edges = edges)
#' )
display_density2d <- function(center = TRUE, axes = "center", half_range = NULL,
col = "black", pch = 20, cex = 1,
contour_quartile = c(.25, .5, .75), edges = NULL,
palette = "Zissou 1", ...) {
# If colors are a variable, convert to colors
if (is.factor(col) | !areColors(col)) {
gps <- col
col <- mapColors(col, palette)
}
labels <- NULL
init <- function(data) {
half_range <<- compute_half_range(half_range, data, center)
labels <<- abbreviate(colnames(data), 3)
}
if (!is.null(edges)) {
if (!is.matrix(edges) && ncol(edges) == 2) {
stop("Edges matrix needs two columns, from and to, only.")
}
}
render_frame <- function() {
par(pty = "s", mar = rep(0.1, 4))
blank_plot(xlim = c(-1, 1), ylim = c(-1, 1))
}
render_transition <- function() {
rect(-1, -1, 1, 1, col = "#FFFFFFE6", border = NA)
}
render_data <- function(data, proj, geodesic) {
draw_tour_axes(proj, labels, limits = 1, axes)
# Render projected points
x <- data %*% proj
if (center) x <- center(x)
x <- x / half_range
colrs <- unique(col)
ngps <- length(colrs)
if (ngps == 1) {
xd <- MASS::kde2d(x[, 1], x[, 2])
contour(xd,
col = col,
levels = quantile(xd$z, probs = contour_quartile),
axes = FALSE
)
}
else {
for (i in 1:ngps) {
x.sub <- x[col == colrs[i], ]
xd <- MASS::kde2d(x.sub[, 1], x.sub[, 2])
contour(xd,
col = colrs[i],
levels = quantile(xd$z, probs = contour_quartile),
axes = FALSE, add = TRUE
)
}
}
points(x, col = col, pch = pch, cex = cex)
if (!is.null(edges)) {
segments(
x[edges[, 1], 1], x[edges[, 1], 2],
x[edges[, 2], 1], x[edges[, 2], 2]
)
}
}
list(
init = init,
render_frame = render_frame,
render_transition = render_transition,
render_data = render_data,
render_target = nul
)
}
#' @rdname display_density2d
#' @inheritParams animate
#' @export
animate_density2d <- function(data, tour_path = grand_tour(), ...) {
animate(data, tour_path, display_density2d(...))
}