Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to dynamically assign border color using geom_node_circle?

I’m trying to change the borders of nodes in ggraph using geom_node_circle. I want to set the border colors based on a mapping between the names of the nodes and the colors that I supply for the names. I know that the parameter to change the border is colour.

Make graph for example:

df <- data_frame(group = c("animals","animals","pets","pets","pets","wild animals","wild animals"),
                 subgroup = c("pets","wild animals","rabbit","dog","cat","polar bear","panda bear"))

df <- as.data.frame(table(df))
df <- filter(df, Freq > 0)

vertices <- df %>%
  dplyr::distinct(subgroup, Freq) %>%
  dplyr::add_row(subgroup = "animals", Freq = 0)

graph <- graph_from_data_frame(df, vertices = vertices)

I know how to change all of the borders to a single new color (red):

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

ggraph(graph, layout = "circlepack", weight = Freq) +
  geom_node_circle(aes(fill =depth),colour = "red") +
  coord_fixed() +
  geom_node_label(aes(label = name), repel = TRUE, size = 5) 

But, I don’t know how to assign the border based on the mapping between name in graph and my colors.

Attempt A

Make map and apply to ggraph:

my_colors <- c("black","black","red","black","black","black","black","black")
names(my_colors) <- c("animals","pets","wild animals","rabbit","dog","cat","polar bear","panda bear")

ggraph(graph, layout = "circlepack", weight = Freq) +
  geom_node_circle(aes(fill =depth),colour = my_colors) +
  coord_fixed() +
  geom_node_label(aes(label = name), repel = TRUE, size = 5) 

Returns

Error in `check_aesthetics()`:
! Aesthetics must be either length 1 or the same as the data (2888): colour
Run `rlang::last_error()` to see where the error occurred.

Attempt B

Add color column to original df and apply to ggraph:

df$my_colors <- cbind(df, ifelse(df$subgroup=="wild animals", "red", "black")

ggraph(graph, layout = "circlepack", weight = Freq) +
  geom_node_circle(aes(fill =depth),colour = df$my_colors) +
  coord_fixed() +
  geom_node_label(aes(label = name), repel = TRUE, size = 5) 

Returns the same error as before.

When I look at the graph, I can see that my_colors isn’t there:

create_layout(graph, 'circlepack', weight = Freq)
Non-leaf weights ignored
           x          y         r circular  leaf depth         name Freq .ggraph.orig_index .ggraph.index
1  0.0000000  0.0000000 2.3440385    FALSE FALSE     0      animals    0                  8             1
2  0.7244867 -0.8650770 1.2156595    FALSE FALSE     1         pets    1                  4             2
3 -0.7805260  0.9319910 1.1283791    FALSE FALSE     1 wild animals    1                  7             3
4  0.2584208 -0.4098895 0.5641896    FALSE  TRUE     2          cat    1                  1             4
5  1.3517237 -0.6890459 0.5641896    FALSE  TRUE     2          dog    1                  2             5
6 -0.5085709  0.4376730 0.5641896    FALSE  TRUE     2   panda bear    1                  3             6
7 -1.0524811  1.4263089 0.5641896    FALSE  TRUE     2   polar bear    1                  5             7
8  0.5633157 -1.4962957 0.5641896    FALSE  TRUE     2       rabbit    1                  6             8

Attempt C

Try adding my_color to vertices:

vertices$my_color <- ifelse(vertices$subgroup=="wild animals", "red", "black")

graph <- graph_from_data_frame(df, vertices = vertices)

# check if my_color is there
create_layout(graph, 'circlepack', weight = Freq)

I can see my_color is now in graph:

Non-leaf weights ignored
            x          y         r circular  leaf depth         name Freq my_color .ggraph.orig_index .ggraph.index
1  0.00000000  0.0000000 2.3440387    FALSE FALSE     0      animals    0    black                  8             1
2  0.42321874  1.0460045 1.2156596    FALSE FALSE     1         pets    1    black                  4             2
3 -0.45595483 -1.1269132 1.1283791    FALSE FALSE     1 wild animals    1      red                  7             3
4  1.05259805  1.2142151 0.5641896    FALSE  TRUE     2          cat    1    black                  1             4
5  0.25420381  0.4168406 0.5641896    FALSE  TRUE     2          dog    1    black                  2             5
6 -0.05740794 -0.7275760 0.5641896    FALSE  TRUE     2   panda bear    1    black                  3             6
7 -0.85450171 -1.5262505 0.5641896    FALSE  TRUE     2   polar bear    1    black                  5             7
8 -0.03714565  1.5069576 0.5641896    FALSE  TRUE     2       rabbit    1    black                  6             8

But if I run

ggraph(graph, layout = "circlepack", weight = Freq) +
  geom_node_circle(aes(fill =depth),colour = my_color) +
  coord_fixed() +
  geom_node_label(aes(label = name), repel = TRUE, size = 5)

I get

Error in layer(data = data, mapping = mapping, stat = StatNodeCircle,  : 
  object 'my_color' not found

So, then I figured that I just don’t know how to access attributes from graph but I figured that out and assigned it to the border color using colour = V(graph)$my_color. That still results in the same error indicating that the length of data is 2888. I assume that this error is being thrown because my list of colors is less than that.

Thoughts

I’m new to using ggraph, and I think that I’m lacking some fundamental knowledge to figure this out….

Solution

Modified from @DanAdams original answer:

df <- data_frame(group = c("animals","animals","pets","pets","pets","wild animals","wild animals"),
                 subgroup = c("pets","wild animals","rabbit","dog","cat","polar bear","panda bear"))

df <- as.data.frame(table(df))
df <- filter(df, Freq > 0)

vertices <- df %>%
  dplyr::distinct(subgroup, Freq) %>%
  dplyr::add_row(subgroup = "animals", Freq = 0)

vertices$my_color <- ifelse(vertices$subgroup=="wild animals", "red", "black")

graph <- graph_from_data_frame(df, vertices = vertices)

ggraph(graph, layout = "circlepack", weight = Freq) +
  geom_node_circle(aes(fill =depth,colour = my_color)) +
  coord_fixed() +
  geom_node_label(aes(label = name), repel = TRUE, size = 5)

>Solution :

It seems you just need to add color = name inside of the aes().

I also colored the labels to match to make it easier to follow.

library(tidyverse)
library(igraph)
library(ggraph)

df <- data_frame(group = c("animals","animals","pets","pets","pets","wild animals","wild animals"),
                 subgroup = c("pets","wild animals","rabbit","dog","cat","polar bear","panda bear"))

my_colors <- c("black","black","red","black","black","black","black","black")
names(my_colors) <- c("animals","pets","wild animals","rabbit","dog","cat","polar bear","panda bear")

df <- as.data.frame(table(df))
df <- filter(df, Freq > 0)

vertices <- df %>%
  dplyr::distinct(subgroup, Freq) %>%
  dplyr::add_row(subgroup = "animals", Freq = 0)

graph <- graph_from_data_frame(df, vertices = vertices)

ggraph(graph, layout = "circlepack", weight = Freq) +
  geom_node_circle(aes(fill = depth, color = name), size = 1) +
  coord_fixed() +
  geom_node_label(aes(label = name, color = name), repel = TRUE, size = 5, show.legend = F) +
  scale_color_manual(values = my_colors)

Created on 2022-09-22 by the reprex package (v2.0.1)

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading