Hey there! Welcome to another R project of mine. This time, I’m going to be creating network visuals of the characters in R. Kelly’s urban opera “Trapped in the Closet.” There are a bunch of characters, 22 or so, who are connected to one another either by marriage, family, friend, affair, or associate.

This urban opera was released like 10 years ago and if you were to watch the whole thing you would’ve realized back then that R. Kelly is clearly crazy. Everything that was in the news about him over the past two years didn’t even remotely shock me. I suggest watching all 33 chapters of this highly entertaining production.

Network analysis is simple mentally, but complex when pen hits paper. The many-to-many relationships really complicate things. A many to many relationship would be authors and books. Many authors can write many books and many books can have many authors.

Networks generally have nodes (the people or circles) and edges (the relationships between them or lines).

The immediate shortcoming I’ve had with this exercise, and I welcome help, is making more of the edges. I ideally would have liked to have the lines color coded to the type of relationship between characters. I also would have liked to make the outline of the nodes correspond to whether or not a character may have “the package” or AIDS (a lot of people are connected sexually).

Anyhow, let’s see what we have. I used the packages: tidyverse, igraph, networkD3, GGally, network, sna, and ggplot2.

And with that…

Robert Kelly, as “Sylvester”

Robert Kelly, as “Sylvester”

So here is where I’m going to import two datasets locally: Trapped_Playing and Trapped_Matrix. I made both of these from scratch, so they’re clean.

Trapped_Playing was my original dataset I made to work with the networkD3 package as well as Tableau. We can see that it follows a pretty reasonable structure as a dataframe.

Trapped_Matrix was an adjusted dataset I made to work with ggplot2. It’s originally a dataframe object that is in a matrix format, which converts to a network object pretty easily. I attempted to denote the type of connect with R for related, or A for affair, but it didn’t work out. I didn’t end up needing the first column, so I deleted it.

I included a head() function that is supposed to show the first 5 rows of a dataset.

#importing the regular dataframe
Trapped_Playing<- read.csv(file = "Trapped in the Closet Network - Sheet1.csv")
#importing the matrix dataframe
Trapped_Matrix<-read.csv(file = "Trapped in the Closet Network - MAtrix.csv")
#inspecting the regular dataframe, note how clean it is
head(Trapped_Playing)
##   Connection.. Character.Name Relationship Other.Person
## 1            1      Sylvester      Married    Gwendolyn
## 2            2      Sylvester       Affair        Cathy
## 3            3      Sylvester       Friend         Twan
## 4            4      Sylvester       Friend  Pimp Lucius
## 5            5      Sylvester      Related        Myrna
## 6            6      Sylvester      Related     Old Dale
#inspecting the matrix dataframe, a little long eh?
head(Trapped_Matrix)
##           X Sylvester Gwendolyn Cathy Rufus Chuck James Bridget Big.Man
## 1 Sylvester         0         M     A     0     0     0       0       0
## 2 Gwendolyn         M         0     F     0     0     A       0       0
## 3     Cathy         A         F     0     M     0     0       0       0
## 4     Rufus         0         0     M     0     A     0       0       0
## 5     Chuck         0         0     0     A     0     A       0       0
## 6     James         0         A     0     0     A     0       M       0
##   Dr..Perry The.Reverend Beeno Joey Twan Roxanne Tina Pimp.Lucius
## 1         0            0     B    B    F       0    0           F
## 2         0            0     0    0    R       0    0           0
## 3         B            0     0    0    0       0    0           0
## 4         B            B     0    0    0       0    0           0
## 5         0            0     0    0    0       0    0           0
## 6         0            0     0    0    0       0    0           0
##   Lucius.Hos Myrna Old.Dale Rosie Randolph Bill.Clinton
## 1          0     R        R     0        0            0
## 2          0     0        0     0        0            0
## 3          0     0        0     0        0            0
## 4          0     0        0     0        B            0
## 5          0     0        0     0        0            0
## 6          0     0        0     0        0            0
#removing the first column
Trapped_Matrix<- Trapped_Matrix[,2:23]

Great, now to some actual fun stuff.

The first network graph I made was very easy. The networkD3 package allows for Trapped_Playing to easily be used to create the graphic. All I really need to do is denote the “source” and “target” columns. Everything else is just extra for aesthetic. While this is quick and short and pretty, it lacks some power. I can’t denote color based on a group or category. If I wanted to make the color of nodes be dependent on male vs female, I can’t. I also can’t do anything with the edges, despite having a column denoted the type of relationship.

BTW, you can click and drag and zoom this graphic. It’s interactive.

p <- simpleNetwork(Trapped_Playing, height="100px", width="100px",        
                   Source = 2,                 # column number of source
                   Target = 4,                 # column number of target
                   linkDistance = 10,          # distance between node. 
                   charge = -500,              # numeric attract vs repel
                   fontSize = 14,              # size of the node names
                   fontFamily = "serif",       # font of node names
                   linkColour = "#666",        # color of edges, evil
                   nodeColour = "#69b3a2",     # color of nodes
                   opacity = 0.9,              # opacity of nodes, 0-1
                   zoom = TRUE                 # Can you zoom on the figure?
                  )
p

Next, we move to a more complex but powerful approach with ggplot2.

I’ll be honest, I’m not 100% on what a network object is and how it works. This is evident in my inability to adjust the edges to include the type of relationship. Plowing ahead, I was able to convert Trapped_Matrix to a network object, trapped_network. I then gave each node a name from the original dataframe matrix. Lastly, I used that name to denote male vs female based on whether the name was in a list of female names.

After all that prep is done I can plot the points. While this looks way worse than the previous map, I can atleast denote sex. In a better world the lines would also have more significance.

#converting to a network object
trapped_network <-as.network(Trapped_Matrix)
#setting the names of nodes to be the column names
network.vertex.names(trapped_network) = colnames(Trapped_Matrix)
#adding an attribute to nodes to denote male vs female
trapped_network %v% "Sex" = ifelse(colnames(Trapped_Matrix) %in% c("Tina", "Gwendolyn", "Cathy", "Myrna","Rosie","Roxanne","Bridget","Lucius.Hos"), "Female", "Male")
trapped_network %v% "color" = ifelse(trapped_network %v% "Sex" == "Male", "steelblue", "pink")

#plotting the network map
ggnet2(trapped_network, 
       node.size = 5,edge.size = 1,
       node.label = TRUE, label.size = 3,
       node.color = "color",legend.size = 12,
       legend.position = "bottom") +
  theme(panel.background = element_rect(color = "grey"))

That’s all I have today. Let me know what you think and thanks for reading!