my circos

  • 要素を円周上に並べ、関連のある要素を円の内側に弧を描くデータ視覚化手法がある。circos
  • きれいだけれど、簡易に描きたい
  • 特に、データ構造のみの情報で描きたい
  • このようなデータ構造は色々考えられるが、自分の用途は次のようなもの
    • 木グラフがある。木の周りをぐるりと回ると、それは周回グラフになる。それを円周に配置する
    • 木の枝を辿って根から遠い方に進み、先端で折り返して戻ってきて、枝の生え際に帰ってくることになるが、この枝の生え際を複数回通過することを、「同一視」として弧で結ぶことにする。これにより、木の周回というデータ構造を表す用途に使える
  • 今、周回グラフがあるとする。それは円周上に等間隔で配置できる
  • 周回グラフ上のところどころに、対になるものがあったときに、その間に弧を描きたい
  • たとえば (0,4,1,2,10,3,10,1,4,5,6,7,8,4,9) というような要素列で1周とすると、途中に1が2回、10が2回、4が3回登場する。
  • 今、単位円周上の2点が、角 \alpha \le \betaで指定されているとき、その2点間に弧を引きたい
  • その弧は単位円周と直交するものとすれば、以下のようにその弧は指定できる
    • \theta = \beta-\alphaとする。\frac{\alpha+\beta}{2}=\phiと置く(これは2点の中間方向)
    • 弧を含む円の半径は\tan{\frac{\theta}{2}}
    • 弧を含む円の中心までの距離はr = \frac{1}{\cos{\frac{\theta}{2}}}
    • 弧を含む円の中心の座標は(r \cos{\phi}, r\sin{\phi})
    • 弧は、角\frac{\pi}{2} + \betaから\frac{3\pi}{2} + \alphaまで
  • Rで関数にする
# Yamada-cirq

my.cirq <- function(x,N=1000){
	n <- length(x)
	theta <- (0:(n-1))/n * 2*pi
	X <- cbind(cos(theta),sin(theta))
	d <- as.matrix(dist(x))
	diag(d) <- 1
	pairs <- which(d==0,arr.ind=TRUE)
	pairs <- unique(t(apply(pairs,1,sort)))

	alphas <- theta[pairs[,1]]
	betas <- theta[pairs[,2]]
	
	rs <- 1/cos((betas-alphas)/2)
	
	ctrs <- rs * cbind(cos((alphas+betas)/2),sin((alphas+betas)/2))
	
	Rs <- tan((betas-alphas)/2)
	
	phis <- cbind(betas+pi/2, alphas+3*pi/2)
	Theta <- (0:(N-1))/N * 2 * pi
	plot(cos(Theta),sin(Theta),type="l")
	points(X,pch=20)
	for(i in 1:length(pairs[,1])){
		Phi <- seq(from = phis[i,1],to=phis[i,2],length=N)
		arc <- Rs[i] * rbind(cos(Phi),sin(Phi)) + ctrs[i,]
		points(t(arc),type="l")
	}
	
}

x <- c(0,4,1,2,10,3,10,1,4,5,6,7,8,4,9)

my.cirq(x)