Search code examples
rshinyigraphreactiveggraph

How to create ggraph reactive layout in shiny


so I've been working on this app looking at BC's drug checking data (see here), and I wanted to make my ggraph plots a bit more interactive, so that people could more readily see the connections between different nodes, by clicking over hovering over them. Whenever I try to put the create_layout() into a reactive function, however, I get

Warning: Error in E: Not a graph object

I need the layout to be in a reactive function, so it can be read by renderPrint, for something I'm trying to add. When I've run print(class(layout())) as a reactive it shows the same properties as when run within renderPlot.

The whole code is a bit complicated, but the working version is available here: https://github.com/alexbetsos/DC_Shiny, I've provided a simpler version with the error below. Unfortunately, some aspects can't be simplified, but I've tried my best.

All of the slider-related content can be ignored - it's probably not good form but it works fairly well.

To note I have the nodes and edges as reactives because they're used in other places as in the larger shiny project. The only major issue here atm is that I can't figure out how to have the layout function as a reactive.

All help appreciated.

In order to make the data reproducible, and so everything else functions I've uploaded a small sample of the data to github, so that the slider still functions correctly, however, I've limited it to just 1 expected substance.


library(readr)
urlfile <- "https://raw.githubusercontent.com/alexbetsos/stackoverflowhelp/main/test_data.csv"
test_data <- read_csv(url(urlfile))
test_data <- test_data[,-c(1)]

poss.w <- data.frame(ID = c(80,81,82,83),
 Days2 = c("Jun 28-\nJul 4\n2021",
 "Jul 5-\nJul 11\n2021",
"Jul 12-\nJul 18\n2021",
"Jul 19-\nJul 25\n2021"))
get_id <- c(max(poss.w$ID)-1, max(poss.w$ID))

interest <- c("Fentanyl/Down", "Opioids Minus Fentanyl (Grouped)", "All Opioids (Grouped)", "Methamphetamine",
              "Ketamine", "Cocaine", "Crack Cocaine", "MDMA")

test_data <- test_data[test_data$Expected.Substance %in% interest,] 


###Creates df for classification and the colour palette####
node_col <- structure(list(ID = 1:36, 
                           Names = c("Caffeine", "Erythritol", 
                                    "Uncertain Match", "Fent <5%", "Fentanyl or Analog", "Xylitol", 
                                    "Benzodiazepine <5%", "Mannitol", "Uncertain Oil/Carb/Sugar", 
                                    "Dimethyl Sulfone", "Soap", "Water", "Methamphetamine", "Acetaminophen", 
                                    "para-Fluorofentanyl", "No Cuts\nFentanyl or Analog", "No Cuts\nUncertain Match", 
                                    "Propionanilide", "MDMA", "Safrole", "Sucrose", "Phenacetin", 
                                    "4-ANPP", "Lactose", "Inositol", "Creatine", "Etizolam",
                                    "No Cuts\nTrichloroisocyanuric Acid", 
                                    "Naproxen", "Heroin", "PEG", "Diphenhydramine", "Cocaine", "Glutamine", 
                                    "Benzocaine", "Sorbitol"), 
                           Classification = c("Stimulant", "Buff", 
                                              "Other or NA", "Opioid", "Opioid", "Buff", "Benzodiazepine", 
                                              "Buff", "Other or NA", "Buff", "new_val", "Other or NA", "Stimulant", 
                                              "Buff", "Opioid", "Opioid", "Other or NA", "Buff", "Stimulant", 
                                              "Other or NA", "Buff", "Buff", "Precursor", "Buff", "Buff", "Other or NA", 
                                              "Benzodiazepine", "new_val", "new_val", "Opioid", "Buff", "Other or NA", 
                                              "Stimulant", "Buff", "Buff", "Buff")), row.names = c(NA, -36L
                                              ), class = "data.frame")

regrouped <- data.frame(ID = seq(2000, 1999+length(unique(node_col$Classification)),by=1),
                        Names = unique(unique(node_col$Classification)),
                        Classification = unique(unique(node_col$Classification)))
node_col <- rbind(node_col, regrouped)



####---Libraries & Functions---####
library(tidyverse)
library(igraph)
library(ggraph)
library(tidygraph)
library(shiny)
library(shinyjs)
library(shinydashboard)
library(shinyWidgets)
library(shinythemes)
ui <- navbarPage(title = "BC Drug Checking Visualizations",theme = shinytheme("flatly"),
                 tabPanel("Instructions",
                          tabPanel("Drug Checking Data",
                                   sidebarLayout(
                                     sidebarPanel(width = 2,
                                                  selectInput("Drug",
                                                              "Expected Substance",
                                                              choices = interest,
                                                              selected = NULL),
                                                  selectInput("City",
                                                              "City",
                                                              choices = unique(test_data$City.Town),
                                                              selected = "Vancouver"),
                                                  radioButtons("duration",
                                                               label = "1 Week or Multiple",
                                                               choices = c("1 Week", "Multiple"),
                                                               selected = "1 Week"),
                                                  checkboxGroupInput("regroup",
                                                                     label = "Regroup Variables",
                                                                     choices = regrouped$Classification,
                                                                     selected = NULL)
                                                  
                                     ),
                                     mainPanel(width = 9,
                                               fluidRow(
                                                 uiOutput("myList")),
                                               tabsetPanel(
                                                 tabPanel("Network Graph",
                                                          fluidRow(tabstyle='padding:0px',
                                                                   box(width = 12, 
                                                                       offset = 0,
                                                                       plotOutput("net", width = "100%",
                                                                                  height = "750px",
                                                                                  click = "plot_click",
                                                                                  brush = "plot_brush"))),
                                                          fluidRow(verbatimTextOutput("info"))
                                                          
                                                          #Need to add the bar chart & Table back in
                                                 )
                                               )
                          )))))
                                   
server <- function(input, output, session) {
  
  #Create reactive value to hold slider info
  slidertype <- reactiveValues()
  
  slidertype$type <- "default"
  observeEvent(input$duration, {
    #When person changes from 1 week to multiple it will change slider
    if(input$duration == "1 Week"){
      slidertype$type <- "1 Week"
    } else if(input$duration == "Multiple"){
      slidertype$type <- "Multiple"
    } else {
      slidertype$type <- "default"
    }
  })
  #Renders the UI for the slider
  output$myList <- renderUI({
    #Changes based on whether someone selects output
    if(slidertype$type == "1 Week"){
      sliderTextInput("Change",
                      label = NULL,
                      choices = as.character(poss.w$Days2),
                      selected = as.character(poss.w$Days2[poss.w$ID == max(get_id)]),
                      force_edges = TRUE,
                      width = "1200px")
    } else if(slidertype$type == "Multiple") {
      sliderTextInput("Change",
                      label = NULL,
                      choices = as.character(poss.w$Days2),
                      selected = as.character(poss.w$Days2[poss.w$ID %in% get_id]),
                      force_edges = TRUE,
                      width = "1200px")
    } else{
      sliderTextInput("Change",
                      label = NULL,
                      choices = as.character(poss.w$Days2),
                      selected = as.character(poss.w$Days2[poss.w$ID == max(get_id)]),
                      force_edges = TRUE, width = "1200px")
    }
  })
  #Create reactive df - requires different filtering
  df_react <- reactive({
    if(slidertype$type != "Multiple"){
      test_data%>%
        filter(Expected.Substance == input$Drug & Week.val %in% input$Change & City.Town == input$City)
    } else if (slidertype$type == "Multiple") {
      test_data %>%
        filter(Expected.Substance == input$Drug & Week.val <= input$Change[2] &
                 Week.val >=input$Change[1] & City.Town == input$City)
    }
  })
  
  observeEvent(input$City,{
    poss_e <- poss.w[poss.w$Days2 <= max(test_data$Week.val[test_data$City.Town == input$City]) & poss.w$Days2 >= min(test_data$Week.val[test_data$City.Town == input$City]),]
    if(slidertype$type != "Multiple"){
      new_id <- max(poss_e$ID)
      updateSliderTextInput(session,inputId = "Change", choices = as.character(poss_e$Days2), selected = as.character(poss_e$Days2[poss_e$ID == max(get_id)]))
    } else {
      new_id <- c(max(poss_e$ID)-1, max(poss_e$ID))
      updateSliderTextInput(session,inputId = "Change", choices = as.character(poss_e$Days2), selected = as.character(poss_e$Days2[poss_e$ID %in% get_id]))
    }
  })
  
  df_react2 <- reactive({
    if(!is.null(input$regroup)){
      df_react() %>%
        dplyr::rename(Names = value) %>%
        left_join(node_col[,c(2:3)]) %>%
        mutate(Classification2 = ifelse(Classification %in% input$regroup, Classification, Names)) %>%
        rename(value = Classification2)
    } else {
      df_react()
    }
  })
  
  #Nodes for the Social Network Visualization
  nodes <- reactive({
    node <-  df_react2() %>%
      select(value) %>%
      count(value) %>%
      dplyr::rename(Names = value, Weight = n) %>%
      left_join(node_col) %>%
      select(ID, Names, Weight, Classification) %>%
      arrange(desc(Weight))
    node$Weight[grepl("No Cuts", node$Names)] <- node$Weight[grepl("No Cuts", node$Names)]/2
    return(node)
  })
  #Edges for SN
  #The nesting solution was a huge help from a user on stackoverflow
  #This code doesn't work without it: https://stackoverflow.com/a/63083986/7263991
  edges2 <- reactive({
    if(nrow(df_react2()) != 0){
      df_react2() %>%
        select(ID, value) %>%
        nest(data=(value)) %>%
        mutate(pairs=map(data, ~as_tibble(t(combn(.$value, 2))), .name_repair=T, .keep)) %>%
        unnest(pairs) %>%
        select(V1, V2) %>%
        group_by(V1, V2) %>%
        summarise(amount = n()) %>%
        ungroup()
    } else {
      df_react2()
    }
  })
the_layout <- reactive({
  edges <- edges2()
  validate(
    need(nrow(edges) >0.9, "Not tested During this Time")
  )
  colnames(edges) <- c("to", "from", "weight")
  edges$from <- nodes()$ID[match(edges$from, nodes()$Names)]
  edges$to <- nodes()$ID[match(edges$to, nodes()$Names)]
  edges <- select(edges, from, to, weight)
  
  g <- graph_from_data_frame(d = edges, vertices = nodes(), directed = FALSE) 
  g <- simplify(g, remove.loops = TRUE)
  if(input$Drug %in% c(V(g)$Names, "Fentanyl/Down", "All Opioids (Grouped)") & 
     nrow(edges) >=10){
    #Checks if there is just one graph or several
    if(is.connected(g) == FALSE){
      #if true then, it splits the main graph from the subgraphs
      c <- clusters(g); cn <- cbind(V(g), c$membership)
      lc <- which(which.max(c$csize)==c$membership);
      gs <- induced.subgraph(g, lc)
      if(input$Drug == "All Opioids (Grouped)"|input$Drug == "Fentanyl/Down"){
        st1 <- layout_as_star(gs, center = V(gs)$Names == "Fentanyl or Analog")
        
      }else{
        st1 <- layout_as_star(gs, center = V(gs)$Names == input$Drug)
      }
      st1 <- norm_coords(st1, xmin = -0.6, xmax = 0.6, 
                         ymin = -0.6, ymax = +0.6,
                         zmin = -0.6, zmax = +0.6)
      #Normalize even and odd rows at different min & max to stagger nodes
      st1[seq(2, nrow(st1),2),] <- norm_coords(st1[seq(2, nrow(st1),2),],
                                               xmin = -0.45, xmax = 0.45, 
                                               ymin = -0.45, ymax = +0.45,
                                               zmin = -0.45, zmax = +0.45)
      lc2 <- which(!which.max(c$csize)==c$membership)
      gs2 <- induced.subgraph(g, lc2)
      circ <- layout_in_circle(gs2)
      circ <- norm_coords(circ, xmin = -0.8, xmax = 0.8, 
                          ymin = -0.8, ymax = +0.8,
                          zmin = -0.8, zmax = +0.8)
      test2 <- rbind(st1,circ) 
      g <- gs %du% gs2
      t_lay <- create_layout(g, test2)
      
    }else{
      st1 <- layout_as_star(g, center = V(g)$Names == input$Drug)
      st1 <- norm_coords(st1, xmin = -0.8, xmax = 0.8, 
                         ymin = -0.8, ymax = +0.8,
                         zmin = -0.8, zmax = +0.8)
      t_lay <- create_layout(g, st1)
    }
    #For every other drug sample - still WIP
  } else {
    t_lay <- create_layout(g, layout = "nicely")
    
  }
})
  #Set graph space limits
output$net <- renderPlot({ 
  t_lay <- the_layout()
  x_max <- max(t_lay$x)+0.1
  x_min <- min(t_lay$x)-0.1
  y_min <- min(t_lay$y)-0.1
  y_max <- max(t_lay$y)+0.1
  par(mar = c(0, 0, 0, 0))
  ggraph(t_lay) +
    geom_edge_link0(aes(width = E(g)$weight), colour = "grey") +   # add edges to the plot
    scale_edge_width_continuous(breaks = c(1, 5, 10, 25, 50,100),
                                label = c(1, 5, 10, 25, 50, 100),
                                range = c(1,20), name = "Frequency Found Together",
                                limits = c(0,400),
                                guide = guide_legend(order = 2, 
                                                     nrow = 1,
                                                     ncol =7)) +
    geom_node_point(aes(size = V(g)$Weight, color = V(g)$Classification)) +
    coord_cartesian(ylim = c(y_min, y_max), xlim = c(x_min, x_max)) +
    geom_node_text(aes(label = V(g)$Names), angle = 30, size = 5) +
    scale_size(breaks = c(1,10,20,40, 60,80, 100), label=scales::number,
               range = c(1,60), limits = c(1,400), name = "# of Times Drug Found \n in Test Results",
               guide = guide_legend(order = 1,
                                    nrow = 4,
                                    ncol = 2,
                                    label.hjust =0.5)) +
    labs(caption = "Fent/Benzodiazepine < 5% means substance tested positive on test strip") +
    theme(legend.position= "right",
          legend.box.background = element_blank(),
          legend.direction = "vertical",
          legend.key = element_blank(),
          legend.background = element_blank(),
          legend.text = element_text(size=12, hjust  = 0.4, inherit.blank = TRUE),
          legend.box.just = "top",
          legend.box = "vertical",
          legend.justification = "right",
          legend.box.spacing = unit(0.5,"cm"),
          plot.caption = element_text(size = 14),
          legend.title.align = 0.2,
          legend.text.align = 0.4,
          legend.title=element_text(size=14),
          legend.key.width = unit(0.5, "cm"),
          legend.key.height = unit(0.2, "cm"),
          legend.spacing = unit(0.5, "cm"),
          panel.background = element_blank(),
          legend.box.margin = margin(t = 0, r = 0, b = 0, l = 0, unit = "cm"),
          legend.margin = margin(0,0, 0, 0, unit = "cm"))+
    guides(color = guide_legend(override.aes = list(size=10),
                                nrow = 5,
                                ncol = 4))
  
})
#I would like to do something like this
output$info <- renderPrint({
  brushedPoints(the_layout(), input$plot_brush, allRows = TRUE)})
}
shinyApp(ui = ui, server = server)```

Solution

  • I got the shiny app to work by changing the assignment of g from <- to <<-. The amended code is below for you.

    urlfile <- "https://raw.githubusercontent.com/alexbetsos/stackoverflowhelp/main/test_data.csv"
    test_data <- read_csv(url(urlfile))
    test_data <- test_data[,-c(1)]
    
    poss.w <- data.frame(ID = c(80,81,82,83),
                         Days2 = c("Jun 28-\nJul 4\n2021",
                                   "Jul 5-\nJul 11\n2021",
                                   "Jul 12-\nJul 18\n2021",
                                   "Jul 19-\nJul 25\n2021"))
    get_id <- c(max(poss.w$ID)-1, max(poss.w$ID))
    
    interest <- c("Fentanyl/Down", "Opioids Minus Fentanyl (Grouped)", "All Opioids (Grouped)", "Methamphetamine",
                  "Ketamine", "Cocaine", "Crack Cocaine", "MDMA")
    
    test_data <- test_data[test_data$Expected.Substance %in% interest,] 
    
    
    ###Creates df for classification and the colour palette####
    node_col <- structure(list(ID = 1:36, 
                               Names = c("Caffeine", "Erythritol", 
                                         "Uncertain Match", "Fent <5%", "Fentanyl or Analog", "Xylitol", 
                                         "Benzodiazepine <5%", "Mannitol", "Uncertain Oil/Carb/Sugar", 
                                         "Dimethyl Sulfone", "Soap", "Water", "Methamphetamine", "Acetaminophen", 
                                         "para-Fluorofentanyl", "No Cuts\nFentanyl or Analog", "No Cuts\nUncertain Match", 
                                         "Propionanilide", "MDMA", "Safrole", "Sucrose", "Phenacetin", 
                                         "4-ANPP", "Lactose", "Inositol", "Creatine", "Etizolam",
                                         "No Cuts\nTrichloroisocyanuric Acid", 
                                         "Naproxen", "Heroin", "PEG", "Diphenhydramine", "Cocaine", "Glutamine", 
                                         "Benzocaine", "Sorbitol"), 
                               Classification = c("Stimulant", "Buff", 
                                                  "Other or NA", "Opioid", "Opioid", "Buff", "Benzodiazepine", 
                                                  "Buff", "Other or NA", "Buff", "new_val", "Other or NA", "Stimulant", 
                                                  "Buff", "Opioid", "Opioid", "Other or NA", "Buff", "Stimulant", 
                                                  "Other or NA", "Buff", "Buff", "Precursor", "Buff", "Buff", "Other or NA", 
                                                  "Benzodiazepine", "new_val", "new_val", "Opioid", "Buff", "Other or NA", 
                                                  "Stimulant", "Buff", "Buff", "Buff")), row.names = c(NA, -36L
                                                  ), class = "data.frame")
    
    regrouped <- data.frame(ID = seq(2000, 1999+length(unique(node_col$Classification)),by=1),
                            Names = unique(unique(node_col$Classification)),
                            Classification = unique(unique(node_col$Classification)))
    node_col <- rbind(node_col, regrouped)
    
    
    
    ####---Libraries & Functions---####
    library(tidyverse)
    library(igraph)
    library(ggraph)
    library(tidygraph)
    library(shiny)
    library(shinyjs)
    library(shinydashboard)
    library(shinyWidgets)
    library(shinythemes)
    ui <- navbarPage(title = "BC Drug Checking Visualizations",theme = shinytheme("flatly"),
                     tabPanel("Instructions",
                              tabPanel("Drug Checking Data",
                                       sidebarLayout(
                                         sidebarPanel(width = 2,
                                                      selectInput("Drug",
                                                                  "Expected Substance",
                                                                  choices = interest,
                                                                  selected = NULL),
                                                      selectInput("City",
                                                                  "City",
                                                                  choices = unique(test_data$City.Town),
                                                                  selected = "Vancouver"),
                                                      radioButtons("duration",
                                                                   label = "1 Week or Multiple",
                                                                   choices = c("1 Week", "Multiple"),
                                                                   selected = "1 Week"),
                                                      checkboxGroupInput("regroup",
                                                                         label = "Regroup Variables",
                                                                         choices = regrouped$Classification,
                                                                         selected = NULL)
                                                      
                                         ),
                                         mainPanel(width = 9,
                                                   fluidRow(
                                                     uiOutput("myList")),
                                                   tabsetPanel(
                                                     tabPanel("Network Graph",
                                                              fluidRow(tabstyle='padding:0px',
                                                                       box(width = 12, 
                                                                           offset = 0,
                                                                           plotlOutput("net", width = "100%",
                                                                                      height = "750px",
                                                                                      click = "plot_click",
                                                                                      brush = "plot_brush"))),
                                                              fluidRow(verbatimTextOutput("info"))
                                                              
                                                              #Need to add the bar chart & Table back in
                                                     )
                                                   )
                                         )))))
    
    server <- function(input, output, session) {
      
      #Create reactive value to hold slider info
      slidertype <- reactiveValues()
      
      slidertype$type <- "default"
      observeEvent(input$duration, {
        #When person changes from 1 week to multiple it will change slider
        if(input$duration == "1 Week"){
          slidertype$type <- "1 Week"
        } else if(input$duration == "Multiple"){
          slidertype$type <- "Multiple"
        } else {
          slidertype$type <- "default"
        }
      })
      #Renders the UI for the slider
      output$myList <- renderUI({
        #Changes based on whether someone selects output
        if(slidertype$type == "1 Week"){
          sliderTextInput("Change",
                          label = NULL,
                          choices = as.character(poss.w$Days2),
                          selected = as.character(poss.w$Days2[poss.w$ID == max(get_id)]),
                          force_edges = TRUE,
                          width = "1200px")
        } else if(slidertype$type == "Multiple") {
          sliderTextInput("Change",
                          label = NULL,
                          choices = as.character(poss.w$Days2),
                          selected = as.character(poss.w$Days2[poss.w$ID %in% get_id]),
                          force_edges = TRUE,
                          width = "1200px")
        } else{
          sliderTextInput("Change",
                          label = NULL,
                          choices = as.character(poss.w$Days2),
                          selected = as.character(poss.w$Days2[poss.w$ID == max(get_id)]),
                          force_edges = TRUE, width = "1200px")
        }
      })
      #Create reactive df - requires different filtering
      df_react <- reactive({
        if(slidertype$type != "Multiple"){
          test_data %>%
            filter(Expected.Substance == input$Drug & Week.val %in% input$Change & City.Town == input$City)
        } else if (slidertype$type == "Multiple") {
          test_data %>%
            filter(Expected.Substance == input$Drug & Week.val <= input$Change[2] &
                     Week.val >=input$Change[1] & City.Town == input$City)
        }
      })
      
      observeEvent(input$City,{
        poss_e <- poss.w[poss.w$Days2 <= max(test_data$Week.val[test_data$City.Town == input$City]) & poss.w$Days2 >= min(test_data$Week.val[test_data$City.Town == input$City]),]
        if(slidertype$type != "Multiple"){
          new_id <- max(poss_e$ID)
          updateSliderTextInput(session,inputId = "Change", choices = as.character(poss_e$Days2), selected = as.character(poss_e$Days2[poss_e$ID == max(get_id)]))
        } else {
          new_id <- c(max(poss_e$ID)-1, max(poss_e$ID))
          updateSliderTextInput(session,inputId = "Change", choices = as.character(poss_e$Days2), selected = as.character(poss_e$Days2[poss_e$ID %in% get_id]))
        }
      })
      
      df_react2 <- reactive({
        if(!is.null(input$regroup)){
          df_react() %>%
            dplyr::rename(Names = value) %>%
            left_join(node_col[,c(2:3)]) %>%
            mutate(Classification2 = ifelse(Classification %in% input$regroup, Classification, Names)) %>%
            rename(value = Classification2)
        } else {
          df_react()
        }
      })
      
      #Nodes for the Social Network Visualization
      nodes <- reactive({
        node <-  df_react2() %>%
          select(value) %>%
          count(value) %>%
          dplyr::rename(Names = value, Weight = n) %>%
          left_join(node_col) %>%
          select(ID, Names, Weight, Classification) %>%
          arrange(desc(Weight))
        node$Weight[grepl("No Cuts", node$Names)] <- node$Weight[grepl("No Cuts", node$Names)]/2
        return(node)
      })
      #Edges for SN
      #The nesting solution was a huge help from a user on stackoverflow
      #This code doesn't work without it: https://stackoverflow.com/a/63083986/7263991
      edges2 <- reactive({
        if(nrow(df_react2()) != 0){
          df_react2() %>%
            select(ID, value) %>%
            nest(data=(value)) %>%
            mutate(pairs=map(data, ~as_tibble(t(combn(.$value, 2))), .name_repair=T, .keep)) %>%
            unnest(pairs) %>%
            select(V1, V2) %>%
            group_by(V1, V2) %>%
            summarise(amount = n()) %>%
            ungroup()
        } else {
          df_react2()
        }
      })
      the_layout <- reactive({
        edges <- edges2()
        validate(
          need(nrow(edges) >0.9, "Not tested During this Time")
        )
        colnames(edges) <- c("to", "from", "weight")
        edges$from <- nodes()$ID[match(edges$from, nodes()$Names)]
        edges$to <- nodes()$ID[match(edges$to, nodes()$Names)]
        edges <- select(edges, from, to, weight)
        
        g <<- graph_from_data_frame(d = edges, vertices = nodes(), directed = FALSE) 
        g <<- simplify(g, remove.loops = TRUE)
        if(input$Drug %in% c(V(g)$Names, "Fentanyl/Down", "All Opioids (Grouped)") & 
           nrow(edges) >=10){
          #Checks if there is just one graph or several
          if(is.connected(g) == FALSE){
            #if true then, it splits the main graph from the subgraphs
            c <- clusters(g); cn <- cbind(V(g), c$membership)
            lc <- which(which.max(c$csize)==c$membership);
            gs <- induced.subgraph(g, lc)
            if(input$Drug == "All Opioids (Grouped)"|input$Drug == "Fentanyl/Down"){
              st1 <- layout_as_star(gs, center = V(gs)$Names == "Fentanyl or Analog")
              
            }else{
              st1 <- layout_as_star(gs, center = V(gs)$Names == input$Drug)
            }
            st1 <- norm_coords(st1, xmin = -0.6, xmax = 0.6, 
                               ymin = -0.6, ymax = +0.6,
                               zmin = -0.6, zmax = +0.6)
            #Normalize even and odd rows at different min & max to stagger nodes
            st1[seq(2, nrow(st1),2),] <- norm_coords(st1[seq(2, nrow(st1),2),],
                                                     xmin = -0.45, xmax = 0.45, 
                                                     ymin = -0.45, ymax = +0.45,
                                                     zmin = -0.45, zmax = +0.45)
            lc2 <- which(!which.max(c$csize)==c$membership)
            gs2 <- induced.subgraph(g, lc2)
            circ <- layout_in_circle(gs2)
            circ <- norm_coords(circ, xmin = -0.8, xmax = 0.8, 
                                ymin = -0.8, ymax = +0.8,
                                zmin = -0.8, zmax = +0.8)
            test2 <- rbind(st1,circ) 
            g <- gs %du% gs2
            t_lay <- create_layout(g, test2)
            
          }else{
            st1 <- layout_as_star(g, center = V(g)$Names == input$Drug)
            st1 <- norm_coords(st1, xmin = -0.8, xmax = 0.8, 
                               ymin = -0.8, ymax = +0.8,
                               zmin = -0.8, zmax = +0.8)
            t_lay <- create_layout(g, st1)
          }
          #For every other drug sample - still WIP
        } else {
          t_lay <- create_layout(g, layout = "nicely")
          
        }
      })
      #Set graph space limits
      output$net <- renderPlot({ 
        t_lay <<- the_layout()
        x_max <- max(t_lay$x)+0.1
        x_min <- min(t_lay$x)-0.1
        y_min <- min(t_lay$y)-0.1
        y_max <- max(t_lay$y)+0.1
        par(mar = c(0, 0, 0, 0))
        ggraph(t_lay) +
          geom_edge_link0(aes(width = E(g)$weight), colour = "grey") +   # add edges to the plot
          scale_edge_width_continuous(breaks = c(1, 5, 10, 25, 50,100),
                                      label = c(1, 5, 10, 25, 50, 100),
                                      range = c(1,20), name = "Frequency Found Together",
                                      limits = c(0,400),
                                      guide = guide_legend(order = 2, 
                                                           nrow = 1,
                                                           ncol =7)) +
          geom_node_point(aes(size = V(g)$Weight, color = V(g)$Classification)) +
          coord_cartesian(ylim = c(y_min, y_max), xlim = c(x_min, x_max)) +
          geom_node_text(aes(label = V(g)$Names), angle = 30, size = 5) +
          scale_size(breaks = c(1,10,20,40, 60,80, 100), label=scales::number,
                     range = c(1,60), limits = c(1,400), name = "# of Times Drug Found \n in Test Results",
                     guide = guide_legend(order = 1,
                                          nrow = 4,
                                          ncol = 2,
                                          label.hjust =0.5)) +
          labs(caption = "Fent/Benzodiazepine < 5% means substance tested positive on test strip") +
          theme(legend.position= "right",
                legend.box.background = element_blank(),
                legend.direction = "vertical",
                legend.key = element_blank(),
                legend.background = element_blank(),
                legend.text = element_text(size=12, hjust  = 0.4, inherit.blank = TRUE),
                legend.box.just = "top",
                legend.box = "vertical",
                legend.justification = "right",
                legend.box.spacing = unit(0.5,"cm"),
                plot.caption = element_text(size = 14),
                legend.title.align = 0.2,
                legend.text.align = 0.4,
                legend.title=element_text(size=14),
                legend.key.width = unit(0.5, "cm"),
                legend.key.height = unit(0.2, "cm"),
                legend.spacing = unit(0.5, "cm"),
                panel.background = element_blank(),
                legend.box.margin = margin(t = 0, r = 0, b = 0, l = 0, unit = "cm"),
                legend.margin = margin(0,0, 0, 0, unit = "cm"))+
          guides(color = guide_legend(override.aes = list(size=10),
                                      nrow = 5,
                                      ncol = 4))
        
      })
      #I would like to do something like this
      output$info <- renderPrint({
        brushedPoints(the_layout(), input$plot_brush, allRows = TRUE)})
    }
    shinyApp(ui = ui, server = server)