New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fr layout tree is always changing. How to make a tree to grow? #130

Open
dkholo opened this Issue May 9, 2018 · 4 comments

Comments

Projects
None yet
2 participants
@dkholo
Copy link

dkholo commented May 9, 2018

This is a follow up to issue #1. I need to be able to build a consecutive series of ggraphs that are growing so the older nodes remain in a certain position and we are able to observe the growth of the tree over time. Is this possible?
the code:
p<- ggraph(bigram_graph, layout = "fr") +
geom_edge_link(aes(edge_alpha = n, edge_width = n)) +
geom_node_point(color = "lightblue", size = 5) +
geom_node_text(aes(label = name),size=4, vjust = 1.8, col = "red") +
theme_void()+
theme(plot.title = element_text(size=22, color="darkgrey"), plot.subtitle =element_text(size=14) ) +
labs(title = "Title)", subtitle =label )
so far the tree changes too much.

in issue #1 you have mentioned fixed layout, but I am not sure how to apply it to the data set that changes so some branches can be fixed.

@dkholo

This comment has been minimized.

Copy link
Author

dkholo commented May 11, 2018

I am trying to build the animation of the tree growing.

@ruaridhw

This comment has been minimized.

Copy link
Contributor

ruaridhw commented May 12, 2018

I hope there's an easier way but here's how I would approach this...

As you've realised, Fruchterman Reingold is a stochastic layout which will return new positions every time it is called. The create_layout function is useful here as it means you can call it once and then reuse the node positions in subsequent plots. My approach would be to first create a layout from the fully grown graph. Then you can filter this layout depending on which vertices appear in each "stage" of graph growth. Essentially just call create_layout once and apply subset to the layout of each plot depending on the input stage.

You will need to provide your dataset in a reproducible manner to work with your exact case but here I have created a list of 4 graphs as grow_graphs where each graph is a subgraph of the next.

library(ggraph)
library(tidygraph)
library(igraph)
library(magrittr)

# Create a reproducible dataset
hs_graph <- as_tbl_graph(highschool)
grow_graphs <- lapply(1:4, function(x) make_ego_graph(hs_graph, order = x, nodes = 1) %>% extract2(1))
str(grow_graphs, 1) # List of 4 graphs
#> List of 4
#>  $ :List of 10
#>   ..- attr(*, "class")= chr "igraph"
#>  $ :List of 10
#>   ..- attr(*, "class")= chr "igraph"
#>  $ :List of 10
#>   ..- attr(*, "class")= chr "igraph"
#>  $ :List of 10
#>   ..- attr(*, "class")= chr "igraph"

Use set.seed to make the fr layout reproducible and call create_layout on the largest graph of the growth:

set.seed(101)
final_layout <- create_layout(graph = grow_graphs[[4]], layout = "fr")

Finally, write a function which subsets each layout data frame and plot the graphs:

# Set the plot limits manually otherwise the x and y axes
# will be rescaled for each plot and the smaller graphs are zoomed
xmin <- min(final_layout$x)
xmax <- max(final_layout$x)
ymin <- min(final_layout$y)
ymax <- max(final_layout$y)

plot_graph <- function(graph) {
  graph %>%
    # Use the manual layout and subset `final_layout` data.frame using an ID
    # to match vertices between growth stages.
    # For this example graph, use the vertex attribute "name"
    ggraph(., layout = "manual", node.positions = subset(final_layout, name %in% V(.)$name, x:y)) +
    geom_edge_link(alpha = 0.25) +
    theme_void() +
    # Force wide zoom for all plots
    expand_limits(x = c(xmin, xmax), y = c(ymin, ymax)) +
    # Add some colour according to stage which adds the nodes for the example graphs
    geom_node_point(aes(color = factor(distances(graph, to = 1))), size = 3) +
    scale_color_brewer(palette = "Set1", guide = "none")
}

plot_graph(grow_graphs[[1]])

plot_graph(grow_graphs[[2]])

plot_graph(grow_graphs[[3]])

plot_graph(grow_graphs[[4]])

@dkholo

This comment has been minimized.

Copy link
Author

dkholo commented Jun 14, 2018

This is exactly what I needed. I will definitely try applying this technique to the historic data in a loop.
My primary problem comes from a scheduled execution against the data set that is growing. I need to sore layout somehow and apply it hour later when I will need to build a plot for all existing items plus those that were added in the last hour since the last plot generation. Is there anything that can be done to preserve the layout in this scenario?

@dkholo

This comment has been minimized.

Copy link
Author

dkholo commented Jun 14, 2018

Are there any other layouts that could be used to achieve a better result from the perspective of reducing the tree transformations?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment