2016-07-29 62 views
1

我正在觀察用戶可以長大或摺疊的d3js樹的變化。對樹的更新由閃亮的ui作爲扁平json返回到服務器(r)並映射到數據幀。刪除R中沒有兒童的兄弟姐妹

我想找到沒有在所有的兒童,或僅兄弟姐妹兄弟姐妹有孩子和修剪他們

這裏有這樣一個數據幀

x=data.frame(cyl=c(4,4,4,6,6,8),vs=c(0,1,1,0,1,NA),am=c(NA,0,1,rep(NA,3)))

的例子。在此例如我想從這個樹在ggplot/8的下方,以修剪和ggplot/4/0

tree

+0

你想修剪哪裏?這是關於R還是關於D3.js? – altocumulus

+0

這是一個問題。我想過濾一個基於樹特性的數據幀 – yonicd

+0

好的。我刪除了d3標籤,因爲標籤應該表明問題的內容,而不是周圍的內容。 – altocumulus

回答

0

首先,您需要以更高效的方式表示您的樹。您當前的表示(每行似乎代表樹中的一個分支)使其很難處理。一個更好的表示將是 - 每個節點的一行,並帶有一個node_id(見下文)。你爲整棵樹建立這張桌子。您爲「可見性」添加矢量/列,然後每次在節點上展開/摺疊時都不需要重新創建/過濾數據集(稍後解釋)。所以你定樹的基本表示會看起來像:

tree = data.frame(
     node_id = 1:10, 
     node_data = c("ggplot",4,6,8,0,1,0,1,0,1), 
     parent_id = c(NA,1,1,1,2,2,3,3,6,6), 
     visible = rep(T,10) 
    ) 

現在,真的有一棵樹往往是創建一個asjacency矩陣有益的工作。所以如果你有N個節點(在我們的例子中是10),那麼你得到一個N * N的二進制矩陣,其中A(i,j)= 1,如果i是j的父親。你可以從上面使用下面的代碼創建鄰接矩陣:

A = matrix(0,nrow = nrow(tree),ncol=nrow(tree)) 
A[cbind(tree$parent_id,tree$node_id)] = 1 

現在,你真正需要的是一個「decendency矩陣」,一個矩陣B,其中B(I,J)= 1當且僅當j是我的一個派生人。你可以通過將A乘以自身(矩陣乘法)並且將A的冪加起來,如果對於樹A ^(d + 1)= 0有d個級別,所以不需要超出那個。所以:

B = A + A%*%A + A%*%A%*%A #that should be enough here, more generally you'd need some looping to add enough powers of A 
B0 = 0+ (B>0) 

現在。修剪樹的節點i,你需要以下條件:

prune_at = function(node_id,decenedency,current_visibility) { 
    to_prune = which(decendency[node_id,]>0) 
    new_visibility = current_visibility 
    new_visibility[to_prune] = F 
    new_visibility 
} 

# for example: 
pruned = prune_at(2,B0,tree$visibility) 

要展開可見節點,這樣你會看到它的孩子:

expand_at = function(node_id,adjacency,current_visibility) { 
    new_visibility = current_visibility 
    if(current_visibility[node_id]==T) { 
     to_expand = which(adjacency[node_id,]==1) 
     new_visibility[to_expand] = T 
    } 
    new_visibility 
} 

#example 
expand_at(2,A,pruned) 

所以,在所有的 - 你創建這些曾經代表對於整個數據集。那麼所有你需要的就是使用「可見性」向量,從一個操作轉換到另一個操作,說明哪些節點可見。

我希望它是有道理的。