Blogs

Interactive Movie Network

Kenny Darrell

Sept 25, 2014

I just created an account on shinyapps. It seems pretty easy to launch an app that can be hosted here. I have heard the term Platform as a Service, or more succinctly PaaS, but never really new what it meant. It seems cool though, they offer the platform and you deploy applications onto it. It takes care of all of the overhead type stuff, you only need to focus on the core of what the app does. There is a great tutorial that can be found on the Shiny website to get you up and running.

I am going to take a break from my last few posts about temporal type data and jump back to one of my other interests, graph data. I used the social network graph of Pulp Fiction from moviegalaxies.com to explore a bunch of graph related technologies. I thought it would be cool to create an interactive application using d3 and Shiny to show off this technology using a bunch of movie network.

The movie networks are really cool. I bet there is also some cool technology behind developing them. I would imagine it would be some algorithm that examines the script and determines who talks to who or who is present in particular scenes. I would not imagine a person sitting with stack of DVDs or a huge queue from Netflix with a pen and paper. I was wondering if this type of thing could be used for books or even TV shows like Survivor that have a huge social aspect.

The app uses a lot of code I have mentioned in prior posts, mainly how to get gexf files into R and how to turn an igraph object into something more suited for d3. I am trying a new approach to making code available for when I am working at any of the various project locations I may find myself. It is often hard to get new packages and I often find myself working on a function or two and then needing to pull it from somewhere. I have placed an import function into my Rprofile that allows me to pull them from my website directly and only what I need. It may be a little flakey compared to a full blown package on CRAN or even on Github, but it works. You can get the core of what I used here.

library(devtools)
source_url('https://raw.githubusercontent.com/darrkj/home/gh-pages/rcode/import.R')
import('igrpah_2_d3')
import('d3plot')

I wanted to do something other than just create an app that had a plot so I gave it a drop-down where you can select which movie and it will use d3 to plot it. It will calculate a collection of parameters from the network as a whole as well as centrality measures for each node in the network. After playing with it a bit it got me thinking about some interesting questions. Would closeness or degree centrality be highly correlated to pay, the most prevalent actor/actress would receive largest paycheck? Would the overall sales depend on the complexity of the whole network, not to simple and not too confusing, just to right level of complexity? This also strengthens my thoughts on apps like these, they can be made as the final output from some analysis but if done correctly they should also conjure up new thoughts to be the starting point for future work.

library(igraph)

nodeAttr <- function(graph) {
  data.frame(
    name = vertex.attributes(graph)$name,
    degree = centralization.degree(graph)$res,
    closeness = centralization.closeness(graph)$res,
    betweeness = centralization.betweenness(graph, directed = FALSE)$res,
    eigenvector = centralization.evcent(graph, directed = FALSE)$vector)
}


graphAttr <- function(graph) { data.frame(
  Property = c('Degree Centralization', 'Closeness Centralization',
               'Betweenness Centralization', 'Eigenvector Centralization',
               'Assortativity Coefficient', 'Average Path Length',
               'Clique Number', 'Diameter', 'Radius', 'Girth',
               'Adhesion', 'Density', 'Chordal', 'Connected'),
  value = c(centralization.degree(graph)$centralization,
            centralization.closeness(graph)$centralization,
            centralization.betweenness(graph, directed = FALSE)$centralization,
            centralization.evcent(graph, directed = FALSE)$centralization,
            assortativity.degree(graph),
            average.path.length(graph, directed = FALSE, unconnected = TRUE),
            clique.number(graph), diameter(graph),
            radius(graph), girth(graph)$girth,
            graph.adhesion(graph), graph.density(graph),
            is.chordal(graph)$chordal, is.connected(graph)))
}

After we have the code to get the various network measures we need the actual shiny app code. This is a fairly standard app, many of the aspects of it come directly from the site''s tutorial pages. You can make apps that can do some pretty complex stuff, way beyond what is happening here. Below is the server code.

shinyServer(function(input, output) {
  output$txt <- renderText({ clean(info[[which(names(info) == input$x)]])})

  output$mytable = renderDataTable({
    nodeAttr(ig[[input$x]])
  }, options = list(aLengthMenu = c(5, 30, 50), iDisplayLength = 5))
  
  output$mytable2 = renderDataTable({
    graphAttr(ig[[input$x]])
  }, options = list(aLengthMenu = c(5, 30, 50), iDisplayLength = 5))
  
  output$networkPlot <- renderPrint({    
    d3SimpleNetwork(igraph_2_d3(ig[[input$x]]), 
                    width = 500, height = 350,
                    textColour = 'orange', linkColour = 'red',
                    parentElement = '#networkPlot')
  })
})

And here is the UI code.

shinyUI(fluidPage(
  tags$head(
    tags$script(src = 'd3.min.js')
  ),  
  
  titlePanel("Movie Network"),

  mainPanel(
    selectInput('x','Select Movie', setdiff(names(info), c("12", "1492: Conquest of Paradise"))),
    textOutput('txt', container = div),

    htmlOutput('networkPlot'),
    h2('Graph Properties'),
    tabsetPanel(
      tabPanel('Nodes',
               dataTableOutput('mytable')),
      tabPanel('Graph',
               dataTableOutput("mytable2"))
    )
  )
))

An the icing on the cake, the app itself.