- Distance Cartogramのことが気になった
- ある標本セットについて2つの距離空間情報があったときに、片方の距離空間情報で描かれている地図をもう片方の距離空間の情報で歪ませる、という話。
- たとえば、個体の物理的存在位置が一つ目の距離空間で、個体の遺伝的距離がもう一つの距離空間にあるとする
- 歪ませた地図表現をCartogramと言うらしい(こちら)
- アルゴリズムも色々と提案されているようだけれど、ちょっと自分でも考えてみたい(アルゴリズムのいい説明サイトも簡単には見つからないようだ)
- 片方の距離空間で地図が描けているときに、もう片方の距離空間で「基準点」間の距離がサンプリングされたら、その基準点に動かして、その基準点の間の点は「補間」する、というのが一番簡単な話だろうか
- もっとも簡単な補間は1次線形補間だろうから(複雑にしたければ、ここでスムージングを考慮してスプライン関数とかにするのだろう)、それでやってみる
- 2次元地図だけでは、ちょっとつまらないので、任意次元を念頭にしてやってみる
- 基準点をとる、というのは、三角測量だから、任意次元でやる、ということはTriangulationで、それはドロネー図を描くこと
- ひとたびドロネー図が描かれれば、元の空間の点は、どれか一つの三角形(三角錐…高次元化)に属するから、その三角形を見つけてやって、三角形の頂点に関して係数を出してやればよい
- 以下のソースは、書き散らし。ぐねぐねした絵を作るために複素関数のカラー表示をまずやって、それを適当に歪ませる。また、歪ませた空間に適当に基準点を取って、そのドロネーを出して、線型補間してある
- もしかすると、はてなブログのランキングサイト「TopHatenaR」の図はarea cartogramなのかも・・・(ブログ間の似ている程度を距離として距離行列を作り、それに基づき2次元にMDSか何かをして、その上で、各ブログの面積に「被リンク」等の重みを入れて歪ませている???(以下がTopHatenaRの地図の部分拡大図)
- 歪ませる前のグネグネ図と歪ませた後のグネグネ図を並置
- 採用点の動きが大きすぎて三角形で対応できなくなったら(移動した後の三角形にオーバーラップや裏返しが発生したら)どうするのか、とか、の問題を無視してある。その場合は、いきなりやらずに、位相を維持するようにソロ―っと動かしたりするのかもしれないけれど、それをどうやるのかは全くわかっていない。おそらくそのあたりがCartogramアルゴリズムの本質なのでしょう
- ボロノイ図の関する関連記事はこちら
- 複素関数のカラー表示に関する関連記事はこちら
my.hsv <- function(z,int0=0.6,sat0=0.3,int1=1,sat1=1){
arg <- Arg(z)
s <- which(arg<0)
arg[s] <- arg[s]+2*pi
r <- Mod(z)
s <- which(r>1)
r[s] <- log(r[s])
r. <- 4*(r%%1)
k <- floor(r.)
r. <- r.-k
inten <- sat <- rep(0,length(r))
s <- which(k==0)
inten[s] <- int1
sat[s] <- sat1-(sat1-sat0)*r.[s]
s <- which(k==1)
inten[s] <- int1-(int1-int0)*r.[s]
sat[s] <- sat0
s <- which(k==2)
inten[s] <- int0
sat[s] <- sat1-(sat1-sat0)*(1-r.[s])
s <- which(k==3)
inten[s] <- int1-(int1-int0)*(1-r.[s])
sat[s] <- sat1
return(cbind(arg,inten,sat))
}
my.hsv2rgb <- function(h,s,v){
hi <- floor(h/(2*pi)*6)
hi[which(hi==6)] <- 0
f <- (h/(2*pi)*6) %%1
p <- v*(1-s)
q <- v *(1-f*s)
t <- v *(1-(1-f)*s)
r <- g <- b <- rep(0,length(h))
s <- which(hi==0)
r[s] <- v[s];g[s] <- t[s]; b[s] = p[s];
s <- which(hi==1)
r[s] <- q[s];g[s] <- v[s]; b[s] = p[s];
s <- which(hi==2)
r[s] <- p[s];g[s] <- v[s]; b[s] = t[s];
s <- which(hi==3)
r[s] <- p[s];g[s] <- q[s]; b[s] = v[s];
s <- which(hi==4)
r[s] <- t[s];g[s] <- p[s]; b[s] = v[s];
s <- which(hi==5)
r[s] <- v[s];g[s] <- p[s]; b[s] = q[s];
return(cbind(r,g,b))
}
judge.inside <- function(x,V){
n <- length(x)
K <- matrix(V[1:n,],ncol=n)
K. <- t(K)-V[n+1,]
tmp <- solve(K.,x-V[n+1,])
all(tmp>=0 & sum(tmp)<=1)
}
judge.inside.2 <- function(x,V){
n <- length(x)
K <- matrix(V[1:n,],ncol=n)
K. <- t(K)-V[n+1,]
tmp <- solve(K.,x-V[n+1,])
c(tmp,1-sum(tmp))
}
x <- seq(from=-4,to=4,len=100)
xx <- as.matrix(expand.grid(x,x))
z <- xx[,1]+1i * xx[,2]
my.f <- function(z){
(z^2-1)*(z-2-1i)^2/(z^2+2+2*1i)
}
w <- my.f(z)
hsv <- my.hsv(w,int0=0.1,sat0=0.1,int1=1,sat1=1)
col <- my.hsv2rgb(hsv[,1],hsv[,3],hsv[,2])
plot(xx,pch=20,col=rgb(col[,1],col[,2],col[,3]))
n.pt <- 20
pt.id <- sample(1:length(xx[,1]),n.pt)
X <- xx[pt.id,]
library(geometry)
delaunay.X <- delaunayn(X)
plot(X)
delaunay.X.2 <- rbind(delaunay.X[,1:2],delaunay.X[,2:3],delaunay.X[,c(3,1)])
segments(X[delaunay.X.2[,1],1],X[delaunay.X.2[,1],2],X[delaunay.X.2[,2],1],X[delaunay.X.2[,2],2])
X. <- X[,1] + 1i * X[,2]
mod.X <- Mod(X.)
arg.X <- Arg(X.)
new.mod.X <- mod.X^2/max(mod.X)
new.arg.X <- arg.X + mod.X * 0.1
X.. <- new.mod.X * (cos(new.arg.X) + 1i * sin(new.arg.X))
X. <- X
delaunay.X <- delaunayn(X)
plot(X.)
delaunay.X.2 <- rbind(delaunay.X[,1:2],delaunay.X[,2:3],delaunay.X[,c(3,1)])
segments(X.[delaunay.X.2[,1],1],X.[delaunay.X.2[,1],2],X.[delaunay.X.2[,2],1],X.[delaunay.X.2[,2],2])
X.. <- cbind(Re(X..),Im(X..))
par(mfcol=c(1,2))
plot(X.)
plot(X..)
par(mfcol=c(1,1))
par(mfcol=c(1,2))
plot(X.)
segments(X.[delaunay.X.2[,1],1],X.[delaunay.X.2[,1],2],X.[delaunay.X.2[,2],1],X.[delaunay.X.2[,2],2])
plot(X..)
segments(X..[delaunay.X.2[,1],1],X..[delaunay.X.2[,1],2],X..[delaunay.X.2[,2],1],X..[delaunay.X.2[,2],2])
par(mfcol=c(1,1))
new.xx <- matrix(NA,length(xx[,1]),length(xx[1,]))
for(i in 1:length(delaunay.X[,1])){
tmp.v <- delaunay.X[i,]
V <- X[tmp.v,]
tmp <- t(apply(xx,1,judge.inside.2,V))
tmp.more.0 <- apply(tmp>=0,1,all)
insiders <- which(tmp.more.0)
if(length(insiders) > 0){
new.xx[insiders,] <- tmp[insiders,] %*% X..[tmp.v,]
}
}
xlim <- ylim <- range(c(c(xx),c(X..)))
par(mfcol=c(1,2))
plot(xx,pch=20,col=rgb(col[,1],col[,2],col[,3]),xlim=xlim,ylim=ylim)
plot(new.xx,pch=20,col=rgb(col[,1],col[,2],col[,3]),xlim=xlim,ylim=ylim)
par(mfcol=c(1,1))