I want to get diagram similar to picture below, but code I use creates different diagram. With rbind I added some hierarchy to a diagram. In data frame col0 there is a string with names of animals. In col1 string is split into individual animals & col2 is adding latin name for a animal. col1 data are always changing and in col2 data constant (there always be feline or canis names in that column).
library(igraph)
# I create my dataframe with animals
df <- data.frame(col0 = c("Cat Dog Wolf", "Cat Dog Wolf", "Cat Dog Wolf"),
col1 = c( "Cat", "Dog", "Wolf"),
col2 = c( "Feline", "Canis", "Canis2"))
# Add extra lines for hierarchy
# These lines work with current graph for a new one these should be replace or deleted
df <-rbind(df, data.frame(col0 = "Cat Dog Wolf", col1 = "Feline", col2 ="Animal"))
df <-rbind(df, data.frame(col0 = "Cat Dog Wolf", col1 = "Canis", col2 = "Animal"))
df <-rbind(df, data.frame(col0 = "Cat Dog Wolf", col1 = "Canis2", col2 = "Canis"))
##########
df <-df[c('col2', 'col1')]
names(df) <-c('from', 'to')
abc <-union(df$to, df$from)
###########
g <-graph.data.frame(df, directed = TRUE, vertices = abc)
plot(g, vertex.size = 20, vertex.label.dist = 0.5, vertex.color = c("blue",
"red", "green", "white", "orange" ),
edge.arrow.size = 0.5, layout = layout.reingold.tilford(g))
This is the graph that the above code outputs, but it's not quite what I want:
I want a similar diagram to what's shown below:
I think that I understand what you want, but I will restate the problem
so that you can confirm whether or not I understood. I think that what
you want to do is this:
Find all of the leaves in the tree, i.e. the nodes with no descendants.
Each leaf will have one parent. Rename the parent with the name of the
leaf, then delete the leaf from the graph. The following code implements that.
## Assume that we have created the graph g using your code
g2 = g # Keep original graph intact
SourceNodes = sapply(strsplit(attr(E(g2), "vnames"), "\\|"), "[", 1)
DestNodes = sapply(strsplit(attr(E(g2), "vnames"), "\\|"), "[", 2)
## Leaf nodes are nodes that are destinations, but not sources
## Also need the node numbers for later deletion
(LeafNodes = DestNodes[which(!(DestNodes%in% SourceNodes ))])
[1] "Cat" "Dog" "Wolf"
(LeafNumbers = match(LeafNodes, attr(V(g), "name")))
[1] 1 2 3
## Find the parents of the leaves
(UpOne = SourceNodes[match(LeafNodes, DestNodes)])
[1] "Feline" "Canis" "Canis2"
## Rename the UpOne nodes (parents of leaves)
vertex_attr(g2)$name[match(UpOne, vertex_attr(g2)$name)] = LeafNodes
## Now delete the leaf nodes and plot
g2 = delete_vertices(g2, LeafNumbers)
plot(g2, vertex.size = 20, vertex.label.dist = 0.5,
vertex.color = c("red", "green", "white", "orange" ),
edge.arrow.size = 0.5, layout = layout.reingold.tilford(g2))
Result
Related
I am trying to make a pie chart in R using plotly. I have a tibble (df) with 4 columns - (1) an observation (x), (2) value of the observation (y), (3) category of the observation (cat), and (4) color of each observation (colors). Colors are unique for each category (every observation within the same category will share the same color). I need each segment of the pie chart to represent each observation with the size of the segment corresponding to the value of the observation. I also need the segments to be colored by their unique category color. I have been able to build such a pie chart.
I am, however, struggling with how to customize the legend. Using showlegend=TRUE shows each observation with it's color. I need the legend to showcase each unique category with its distinct color. I would really appreciate it if someone could help me out with this.
Here is some dummy code that models this problem -
# Load packages
library(tidyverse)
library(plotly)
# Initialize variables
df = NULL
x = c("apple", "John", "dog", "lion", "strawberry", "Liz",
"cat", "peach", "banana", "elephant", "pear", "tiger")
y = c(1, 1, 3, 5, 4, 3, 6, 4, 1, 2, 1, 6)
cat = c("fruit", "person", "animal", "animal", "fruit", "person",
"animal", "fruit", "fruit", "animal", "fruit", "animal")
colors = NULL
# Define colors
for (i in 1:length(cat)) {
if (cat[i] == "fruit") {
color = "#FFD700"
} else if (cat[i] == "animal") {
color = "#FB8072"
} else {
color = "#D3D3D3"
}
colors = c(colors, color)
}
# Create data frame
df = as_tibble(cbind(x, y, cat, colors))
# Sort data frame
df = df[order(df$cat, df$x), ]
# Define colors for pie chart
pie_colors = as.character(df$colors)
# Define margins for pie chart
margins = list(l=50, r=50, b=125, t=125)
# Build the pie chart
pie_plt = plot_ly(data=df,
values=~y,
labels=~x,
type="pie",
textinfo="label+percent",
sort=FALSE,
marker=list(colors=pie_colors,
line=list(color="black", width=1))) %>%
layout(autosize=FALSE, margin=margins, showlegend=TRUE)
# Show pie chart:
pie_plt
It looks like DiagrammeR has changed their create_nodes and create_edges functions than it looks on the doc.
Also the $dot_code attribute is not there anymore. I can't find the replacement for this.
Here is the example code that they had on the doc, but it is not working.
The following example is found in their official DiagrammeR web.
###
# Create a graph with both nodes and edges
# defined, and, add some default attributes
# for nodes and edges
###
library(DiagrammeR)
# Create a node data frame
nodes <-
create_nodes(nodes = c("a", "b", "c", "d"),
label = FALSE,
type = "lower",
style = "filled",
color = "aqua",
shape = c("circle", "circle",
"rectangle", "rectangle"),
data = c(3.5, 2.6, 9.4, 2.7))
edges <-
create_edges(from = c("a", "b", "c"),
to = c("d", "c", "a"),
rel = "leading_to")
graph <-
create_graph(nodes_df = nodes,
edges_df = edges,
node_attrs = "fontname = Helvetica",
edge_attrs = c("color = blue",
"arrowsize = 2"))
graph
#> $nodes_df
#> nodes label type style color shape data
#> 1 a lower filled aqua circle 3.5
#> 2 b lower filled aqua circle 2.6
#> 3 c lower filled aqua rectangle 9.4
#> 4 d lower filled aqua rectangle 2.7
#>
#> $edges_df
#> from to rel
#> 1 a d leading_to
#> 2 b c leading_to
#> 3 c a leading_to
#>
#> $graph_attrs
#> [1] NULL
#>
#> $node_attrs
#> [1] "fontname = Helvetica"
#>
#> $edge_attrs
#> [1] "color = blue" "arrowsize = 2"
#>
#> $directed
#> [1] TRUE
#>
#> $dot_code
#> [1] "digraph {\n\ngraph [rankdir = LR]\n\nnode [fontnam...
#>
#> attr(,"class")
#> [1] "dgr_graph"
# View the graph in the RStudio Viewer
render_graph(graph)
look into the help of the DiagrammeR package, the website is indeed not up-to-date.
Look at the function create_graph() in the help that shows how the syntax changed.
something like this should do the same:
###
library(DiagrammeR)
# Create a node data frame (ndf) where the labels
# are equivalent to the node ID values (this is not
# recommended); the `label` and `type` node
# attributes will always be a `character` class
# whereas `id` will always be an `integer`
nodes <-
create_node_df(
n = 4,
type = "lower",
label = c("a", "b", "c", "d"),
style = "filled",
fillcolor = "blue",
shape = c("circle", "circle",
"rectangle", "rectangle"),
data = c(3.5, 2.6, 9.4, 2.7))
# Create an edf with additional edge
# attributes (where their classes will
# be inferred from the input vectors)
edges <-
create_edge_df(
from = c(1, 2, 3),
to = c(4, 3, 1),
rel = "leading_to")
# With `create_graph()` we can
# simply create an empty graph (and
# add in nodes and edges later
# with other functions)
graph <-
create_graph(
nodes_df = nodes,
edges_df = edges) %>%
set_edge_attrs(
edge_attr = color,
values = "green") %>%
set_edge_attrs(
edge_attr = arrowsize,
values = 2) %>%
set_node_attrs(
node_attr = fontname,
values = "Helvetica")
graph
render_graph(graph)
The Bad News
For anyone viewing this zombie thread, as of this posting, the information posted on Rich Iannone's documentation page for DiagrammeR is still out of date: http://rich-iannone.github.io/DiagrammeR/graph_creation.html.
The Good News
However, the vignettes for the Diagrammer package contain updated information. As shown in the package vignette named Creating Simple Graphs from NDFs/EDFs, you can view and export GraphViz dot code with a function named generate_dot().
I try to plot a bipartite network with the edges of the same color than one of their nodes.
For example, let's take an movie/actor bipartite graph as an exemple, with 7 movies and 15 actors, and each actor has a nationality.
I want to have the edge between an actor and a movie of the same color than the nationality of the actor.
NG1 <- 7
NG2 <- 15
Nat <- sample(x = c("French", "English", "Italian", "American", "Chinese"), size = NG2, replace = T)
G <- graph.empty(NG1+NG2)
[Here, head(Nat) returns "Italian" "English" "American" "French" "French" "French"]
The code to create the edgelist:
E1 <- sample(x=1:NG1, size = 30, replace = T)
E2 <- sample(x=(NG1+1):(NG1+NG2), size = 30, replace = T)
EL <- c(rbind(E1, E2))
G <- add_edges(G, EL, nat = Nat[E2-NG1])
[Here, head(EL) returns 1 14 3 13 2 15]
The different aes arguments:
GROUP <- c(rep("Movie", NG1), rep("Act", NG2))
COL <- c(rep("Movie", NG1), Nat)
TXT <- c(as.character(1:NG1), letters[1:NG2])
And now the ggraph instructions:
ggraph(G, layout = 'kk') +
geom_node_point(aes(col = COL, shape = GROUP, size = 7)) +
geom_edge_link(aes(col = nat)) +
geom_node_text(aes(label = TXT), size = 4)
As you can see in the bottom, actor a, which is Italien has a blue node, but is connected with a pink edge with movie 7... How can I specify the color palette for nodes (here 6 colors) and edges (the 5 first colors of the nodes)?
I hope that I have made clear.
After two hours, I finally found a solution !
I used the function gg_color_hue defined here to emulate the 6 colors used for the nodes and then:
+ scale_edge_colour_manual(values = cols[1:5])
There is dataset with code below. And I need get a graph like in the picture, without changing frame. I tried use rbind to add more hierarchy to data frame in favor to get diagram like in picture. col0 and col1 data is changing debending on data while col2 remains always the same.
df <- data.frame(col0 = c("Cat Dog Wolf", "Cat Dog Wolf", "Cat Dog Wolf"),
col1 = c( "Cat", "Dog", "Wolf"),
col2 = c( "Feline", "Canis", "Canis2"))
df <-rbind(df, data.frame(col0="Cat Dog Wolf", col1 = "Canis2", col2 = "Canis"))
df <-df[c('col1', 'col2')]
names(df) <-c('from', 'to')
abc <-union(df$to, df$from)
g <-graph.data.frame(df, directed = TRUE, vertices = abc)
plot(g, vertex.size = 20, vertex.label.dist = 0.5, vertex.color = "blue",
edge.arrow.size = 0.5, layout = layout.reingold.tilford(g))
You need three edges taken from only two columns ("From" and "To"). But you have three columns in df so you have to choose from them. I created a new column with the names from col1 and col2 pasted together. Then, I chose the first two vertex from the top and rbind the third one.
df <- data.frame(col0 = "Cat Dog Wolf",
col1 = c( "Cat", "Dog", "Wolf"),
col2 = c( "Feline", "Canis", "Canis2"))
df$col1_2 <- paste(df$col2,df$col1)
df <- rbind(df[1:2,c(1,4)],data.frame(col0=df[2,4],col1_2=df[3,4]))
names(df) <-c('from', 'to')
abc <-union(df$to, df$from)
g <-graph.data.frame(df, directed = TRUE, vertices = abc)
plot(g, vertex.size = 20, vertex.label.dist = 0.5, vertex.color = c("lightblue","red","green","white"),
edge.arrow.size = 0.5, layout = layout.reingold.tilford(g))
I have diagram and want to add variety of colors to the nodes, so I added this code line from grviz that change node color from the value he has node = "[fillcolor = red]Canis" but it didn't change anything in diagram.
The rest code for diagram:
df <- data.frame(col1 = c( "Cat", "Dog", "Bird"),
col2 = c( "Feline", "Canis", "Avis"),
stringsAsFactors=FALSE)
uniquenodes <- unique(c(df$col1, df$col2))
library(DiagrammeR)
nodes <- create_node_df(n=length(uniquenodes), nodes = seq(uniquenodes), type="number", label=uniquenodes, nodes = "[fillcolor = red]Canis")
edges <- create_edge_df(from=match(df$col1, uniquenodes), to=match(df$col2, uniquenodes), rel="related")
g <- create_graph(nodes_df=nodes, edges_df=edges, attr_theme = NULL)
render_graph(g)