n <- 55
eps <- 0.02
u <- seq(eps, 1 - eps, length.out = n)
v <- seq(eps, 1 - eps, length.out = n)
grid <- expand.grid(u = u, v = v)
# Independence density
z_indep <- matrix(1, nrow = n, ncol = n)
# Clayton copula density
theta <- 5
cop_clayton <- claytonCopula(param = theta, dim = 2)
z_clayton <- matrix(
dCopula(as.matrix(grid), copula = cop_clayton),
nrow = n, ncol = n
)
z_sqrt <- sqrt(z_clayton)
# Helper: build closed mesh for the gap
# between z_low and z_high
make_gap_mesh <- function(u, v, z_low, z_high) {
nu <- length(u)
nv <- length(v)
# vertex indexing (0-based for plotly mesh3d)
idx_top <- function(i, j) (j - 1) * nu + i - 1
idx_bot <- function(i, j) nu * nv + (j - 1) * nu + i - 1
# vertices
xg <- rep(u, times = nv)
yg <- rep(v, each = nu)
x <- c(xg, xg)
y <- c(yg, yg)
z <- c(as.vector(z_high), as.vector(z_low))
ii <- integer(0)
jj <- integer(0)
kk <- integer(0)
add_tri <- function(a, b, c) {
ii <<- c(ii, a)
jj <<- c(jj, b)
kk <<- c(kk, c)
}
# top and bottom faces
for (i in 1:(nu - 1)) {
for (j in 1:(nv - 1)) {
# top
a <- idx_top(i, j)
b <- idx_top(i + 1, j)
c <- idx_top(i, j + 1)
d <- idx_top(i + 1, j + 1)
add_tri(a, b, c)
add_tri(b, d, c)
# bottom (reverse orientation)
a2 <- idx_bot(i, j)
b2 <- idx_bot(i + 1, j)
c2 <- idx_bot(i, j + 1)
d2 <- idx_bot(i + 1, j + 1)
add_tri(a2, c2, b2)
add_tri(b2, c2, d2)
}
}
# wall at v = min(v)
for (i in 1:(nu - 1)) {
t1 <- idx_top(i, 1)
t2 <- idx_top(i + 1, 1)
b1 <- idx_bot(i, 1)
b2 <- idx_bot(i + 1, 1)
add_tri(t1, b1, t2)
add_tri(t2, b1, b2)
}
# wall at v = max(v)
for (i in 1:(nu - 1)) {
t1 <- idx_top(i, nv)
t2 <- idx_top(i + 1, nv)
b1 <- idx_bot(i, nv)
b2 <- idx_bot(i + 1, nv)
add_tri(t1, t2, b1)
add_tri(t2, b2, b1)
}
# wall at u = min(u)
for (j in 1:(nv - 1)) {
t1 <- idx_top(1, j)
t2 <- idx_top(1, j + 1)
b1 <- idx_bot(1, j)
b2 <- idx_bot(1, j + 1)
add_tri(t1, t2, b1)
add_tri(t2, b2, b1)
}
# wall at u = max(u)
for (j in 1:(nv - 1)) {
t1 <- idx_top(nu, j)
t2 <- idx_top(nu, j + 1)
b1 <- idx_bot(nu, j)
b2 <- idx_bot(nu, j + 1)
add_tri(t1, b1, t2)
add_tri(t2, b1, b2)
}
list(x = x, y = y, z = z, i = ii, j = jj, k = kk)
}
gap_mesh <- make_gap_mesh(u, v, z_indep, z_sqrt)
surf_contours <- list(
x = list(show = TRUE, color = "black", width = 1),
y = list(show = TRUE, color = "black", width = 1),
z = list(show = FALSE)
)
# Plot
p <- plot_ly()
# LEFT: independence copula
p <- add_surface(
p,
x = ~u, y = ~v, z = ~z_indep,
scene = "scene",
colorscale = list(c(0, 1), c("tomato", "tomato")),
showscale = FALSE,
opacity = 1,
contours = surf_contours,
name = "Independence density"
)
p <- add_surface(
p,
x = ~u, y = ~v, z = ~z_indep,
scene = "scene",
colorscale = list(c(0, 1), c("royalblue", "royalblue")),
showscale = FALSE,
opacity = 1,
contours = surf_contours,
name = "sqrt(c(u,v))"
)
# RIGHT: gray filled gap first
p <- add_trace(
p,
type = "mesh3d",
x = gap_mesh$x,
y = gap_mesh$y,
z = gap_mesh$z,
i = gap_mesh$i,
j = gap_mesh$j,
k = gap_mesh$k,
scene = "scene2",
color = "gray70",
opacity = 0.8,
flatshading = TRUE,
hoverinfo = "skip",
showlegend = FALSE
)
# RIGHT: red independence surface
p <- add_surface(
p,
x = ~u, y = ~v, z = ~z_indep,
scene = "scene2",
colorscale = list(c(0, 1), c("tomato", "tomato")),
showscale = FALSE,
opacity = 1,
contours = surf_contours
)
# RIGHT: blue sqrt Clayton density
p <- add_surface(
p,
x = ~u, y = ~v, z = ~z_sqrt,
scene = "scene2",
colorscale = list(c(0, 1), c("royalblue", "royalblue")),
showscale = FALSE,
opacity = 1,
contours = surf_contours
)
p <- layout(
p,
showlegend = FALSE,
scene = list(
domain = list(x = c(0.00, 0.48), y = c(0, 1)),
xaxis = list(title = "u"),
yaxis = list(title = "v"),
zaxis = list(title = "density", range = c(0, 6)),
camera = list(eye = list(x = 1.6, y = 1.6, z = 0.9))
),
scene2 = list(
domain = list(x = c(0.52, 1.00), y = c(0, 1)),
xaxis = list(title = "u"),
yaxis = list(title = "v"),
zaxis = list(title = "density", range = c(0, 6)),
camera = list(eye = list(x = 1.6, y = 1.6, z = 0.9))
)
)
p