#' SNAhelper
#'
#' \code{SNAhelper} is a RStudio-Addin that provides a graphical interface for network analysis and visualization.
#'
#' @details To run the addin, highlight an igraph-object in your current script and select \code{SNAhelper} from the Addins-menu within RStudio. After terminating the addin, a character string containing the code for visualization is inserted in your current script. Alternatively you can run it with SNAhelperGadget(graph) from the console.
#' @param graph An igraph object to visualize
#' @return \code{SNAhelper} returns a character vector with code.
#' @import miniUI
#' @import shiny
#' @import ggplot2
#' @import ggraph
#' @import rstudioapi
#' @import igraph
#' @importFrom colourpicker colourInput
#' @importFrom grDevices col2rgb
#' @importFrom grDevices colors
#' @name SNAhelper
NULL
SNAhelper <- function(text){
if (!requireNamespace("graphlayouts", quietly = TRUE)) {
stop("graphlayouts package not found. Install it with install.packages('graphlayouts')", call. = FALSE)
}
if (any(ls(envir = .GlobalEnv) == text)) {
g <- get(text, envir = .GlobalEnv)
if(!igraph::is.igraph(g)){
stop(paste0(text, ' is not an igraph object'))
}
if(any(igraph::vertex_attr_names(g)=="x") & any(igraph::vertex_attr_names(g)=="y")){
xy <- cbind(igraph::V(g)$x,igraph::V(g)$y)
} else{
xy <- graphlayouts::layout_with_stress(g)
}
rv <- reactiveValues(g=g,xy=xy)
} else {
stop(paste0('Couldn\'t find the graph ', text, '.'))
}
if(any(igraph::is.multiple(g))){
edge_geom <- "geom_edge_parallel0("
} else{
edge_geom <- "geom_edge_link0("
}
#ui ----
ui <- miniPage(
tags$script(jscodeWidth),
tags$script(jscodeHeight),
tags$style(type = "text/css", ".selectize-dropdown{ width: 200px !important; }"),
tags$style(type = "text/css",".form-group.shiny-input-container{width:50%;}"),
gadgetTitleBar("SNA helper"),
miniTabstripPanel(selected = 'layout',
miniTabPanel("layout", icon = icon('sliders-h'),
miniContentPanel(
scrollable = FALSE,
fillRow(height = heading.height, width = '100%',
headingOutput('Choose Layout')
),
fillRow(height = line.height, width = '100%',
selectizeInput('graphLayout',label="Layout Algorithm",
choices=layouts.available,
selected="graphlayouts::layout_with_stress",width=input.width),
shiny::conditionalPanel("input.graphLayout=='graphlayouts::layout_with_focus'",
selectizeInput('focalNode',label = 'Choose Focal Node ID',
choices = 1:igraph::vcount(g),
width = input.width)),
shiny::conditionalPanel("input.graphLayout=='graphlayouts::layout_with_centrality'",
selectizeInput('centralLay',label = 'Choose Centrality',
choices = NULL,
width = input.width))
),
fillRow(height = line.height, width = '50%',
actionButton("do.layout","Calculate Layout"),
actionButton("del.isolate","Delete Isolates")
),
fillRow(height = heading.height, width = '100%',
headingOutput('Tweak Layout'),
checkboxInput("showLabs", label = "Show NodeIDs", value = FALSE)
),
fillRow(height = line.height, width = '100%',
selectizeInput('nodeId', label = 'NodeID', choices = 1:vcount(g),
width = input.width),
p("tweak node position by clicking on the desired location.")
)
),
plotOutput("Graph1", width = '80%', height = '55%',click = "tweakxy")
),
miniTabPanel("node attributes",icon = icon("list-ol"),
miniContentPanel(
scrollable = FALSE,
fillRow(height = line.height, width = '100%',
selectizeInput('centindex', label = 'Index',
choices = NULL,
width = input.width),
selectizeInput('clusteralg', label = 'Clustering',
choices = c("Louvain" = "cluster_louvain(rv$g)"),
width = input.width)
),
fillRow(height=line.height, width = '100%',
actionButton("calcIndex","Calculate Index"),
actionButton("calcClust","Calculate Clustering")
),
fillRow(height = heading.height, width = '100%',
headingOutput('Node Attributes')
),
DT::dataTableOutput("attrManageN")
)
),
miniTabPanel("nodes", icon = icon('circle'),
miniContentPanel(
scrollable = FALSE,
fillRow(height = heading.height, width = '100%',
headingOutput('Manual')
),
fillRow(height = line.height, width = '100%',
colourInput('nodeColMan',label="Colour",value = "gray32"),
numericInput('nodeSizeMan', label = 'Size',
min = 0, max = 20, step = 0.5, value = 5,width = input.width),
colourInput('nodeBorderColMan',label="Border Colour",value = "black"),
numericInput('nodeBorderSizeMan', label = 'Border Size',
min = 0, max = 2, step = 0.1, value = 0.3,width=input.width)
),
fillRow(height = heading.height, width = '100%',
headingOutput('Attribute')
),
fillRow(height = line.height, width = '100%',
selectizeInput('nodeColAttr', label = 'Colour (Cont.)',
choices = NULL,
width = input.width),
selectizeInput('nodeColAttrD', label = 'Colour (Discrete)',
choices = NULL,
width = input.width),
selectizeInput('nodeSizeAttr', label = 'Size (Cont.)',
choices = NULL,
width = input.width),
selectizeInput('nodeLabelAttr', label = 'Node Label',
choices = NULL,
width = input.width)
),
fillRow(height=line.height,width='100%',
shiny::conditionalPanel("input.nodeColAttr!='None'",
colourInput('nodeColAttrL',label="Min Colour",value = "skyblue1"),
colourInput('nodeColAttrH',label="Max Colour",value = "royalblue4")
),
shiny::conditionalPanel("input.nodeColAttrD!='None'",
selectizeInput('nodeColAttrP',label = 'Palette',
choices = c("Set1","Set2","Set3","Pastel2","Pastel1",
"Paired","Dark2","Accent"),
width = input.width)
),
shiny::conditionalPanel("input.nodeSizeAttr!='None'",
numericInput('nodeSizeAttrL', label = 'Min Size',
min = 0, max = 20, step = 0.5, value = 3,width=input.width),
numericInput('nodeSizeAttrH', label = 'Max Size',
min = 0, max = 20, step = 0.5, value = 8,width=input.width)
),
shiny::conditionalPanel("input.nodeLabelAttr!='None'",
colourInput('nodeLabelCol',label="Colour",value = "black"),
# selectizeInput('nodeLabelCol',label = 'Colour',
# choices = NULL, width = input.width),
numericInput('nodeLabelSize', label = 'Size',
min = 0, max = 20, step = 0.5, value = 6,width=input.width),
selectizeInput('nodeLabelFont',label = 'Font',
choices = fonts.available, width = input.width),
shiny::checkboxInput('nodeLabelRepel',label = 'Repel Labels?',value = FALSE)
)
)
),
plotOutput("Graph2", width = '80%', height = '55%')
),
miniTabPanel("edge attributes",icon = icon("list-ol"),
miniContentPanel(
scrollable = FALSE,
fillRow(height = heading.height, width = '100%',
headingOutput('Edge Attributes')
),
DT::dataTableOutput("attrManageE")
)
),
miniTabPanel("edges", icon = icon('minus'),
miniContentPanel(
scrollable = FALSE,
fillRow(height = heading.height, width = '100%',
headingOutput('Manual')
),
fillRow(height = line.height, width = '75%',
colourInput('edgeColMan',label="Colour",value = "gray66"),
numericInput('edgeSizeMan', label = 'Width',
min = 0, max = 10, step = 0.1, value = 0.8,width=input.width),
numericInput('edgeAlphaMan', label = 'Alpha',
min = 0, max = 1, step = 0.01, value = 1.0,width=input.width)
),
fillRow(height = heading.height, width = '100%',
headingOutput('Attribute')
),
fillRow(height = line.height, width = '100%',
selectizeInput('edgeColAttr', label = 'Colour (Cont.)',
choices = NULL,
width = input.width),
selectizeInput('edgeColAttrD', label = 'Colour (Discrete)',
choices = NULL,
width = input.width),
selectizeInput('edgeSizeAttr', label = 'Width (Cont.)',
choices = NULL,
width = input.width),
selectizeInput('edgeAlphaAttr', label = 'Alpha (Cont.)',
choices = NULL,
width = input.width)
),
fillRow(height=line.height,width='100%',
shiny::conditionalPanel("input.edgeColAttr!='None'",
colourInput('edgeColAttrL',label="Min Colour",value = "skyblue1"),
colourInput('edgeColAttrH',label="Max Colour",value = "royalblue4")
),
shiny::conditionalPanel("input.edgeColAttrD!='None'",
selectizeInput('edgeColAttrP',label = 'Palette',
choices = c("Set1","Set2","Set3","Pastel2","Pastel1",
"Paired","Dark2","Accent"),
width = input.width)
),
shiny::conditionalPanel("input.edgeSizeAttr!='None'",
numericInput('edgeSizeAttrL', label = 'Min Width',
min = 0, max = 10, step = 0.1, value = 0.3,width=input.width),
numericInput('edgeSizeAttrH', label = 'Max Width',
min = 0, max = 10, step = 0.1, value = 1.2,width=input.width)
),
shiny::conditionalPanel("input.edgeAlphaAttr!='None'",
numericInput('edgeAlphaAttrL', label = 'Min Alpha',
min = 0, max = 1, step = 0.01, value = 0.1,width=input.width),
numericInput('edgeAlphaAttrH', label = 'Max Alpha',
min = 0, max = 1, step = 0.01, value = 1,width=input.width)
)
)
),
plotOutput("Graph3", width = '80%', height = '55%')
),
miniTabPanel("result", icon = icon('bezier-curve'),
plotOutput("Graph4", width = '90%', height = '80%'),
miniContentPanel(
scrollable = TRUE,
fillRow(height = line.height, width = '50%',
selectInput('legendPos', label = 'Show Legend:',
choices = c("none","top","bottom","left","right"),
width = input.width)),
downloadButton("downloadData", "Save PNG")
)
)
))
server <- function(input, output, session) {
#--------------------#
#constants ----
#--------------------#
vattr.to.aes <- igraph::vertex_attr_names(g)[!grepl("name",igraph::vertex_attr_names(g))]
if(length(vattr.to.aes)>0){
idC <- which(sapply(vattr.to.aes,function(x) is.numeric(igraph::get.vertex.attribute(g,x))))
vattrC.to.aes <- c("None",vattr.to.aes[idC])
idC <- which(sapply(vattr.to.aes,function(x) !is.numeric(igraph::get.vertex.attribute(g,x))))
vattrD.to.aes <- c("None",vattr.to.aes[idC])
} else{
vattrC.to.aes <- c("None")
vattrD.to.aes <- c("None")
}
eattr.to.aes <- igraph::edge_attr_names(g)
if(length(eattr.to.aes)>0){
idC <- which(sapply(eattr.to.aes,function(x) is.numeric(igraph::get.edge.attribute(g,x))))
eattrC.to.aes <- c("None",eattr.to.aes[idC])
idC <- which(sapply(eattr.to.aes,function(x) !is.numeric(igraph::get.edge.attribute(g,x))))
eattrD.to.aes <- c("None",eattr.to.aes[idC])
} else{
eattrC.to.aes <- c("None")
eattrD.to.aes <- c("None")
}
#--------------------#
# check graph properties
#--------------------#
if(is.directed(g) & !is.weighted(g)){
cent_choice <- c("In-Degree" = "degree(rv$g,mode='in')",
"Out-Degree" = "degree(rv$g,mode='out')",
"Degree" = "degree(rv$g,mode='all')",
"Betwenness" = "betweenness(rv$g)",
"Closeness" = "closeness(rv$g)",
"PageRank" = "page_rank(rv$g)$vector")
} else if(!is.directed(g) & is.weighted(g)){
cent_choice <- c("Degree" = "degree(rv$g)",
"Weighted Degree" = "graph.strength(rv$g)",
"Betwenness" = "betweenness(rv$g)",
"Closeness" = "closeness(rv$g)",
"Eigenvector" = "eigen_centrality(rv$g)$vector")
} else if(!is.directed(g) & !is.weighted(g)){
cent_choice <- c("Degree" = "degree(rv$g)",
"Betwenness" = "betweenness(rv$g)",
"Closeness" = "closeness(rv$g)",
"Eigenvector" = "eigen_centrality(rv$g)$vector")
} else{
cent_choice <- c("In-Degree" = "degree(rv$g,mode='in')",
"Out-Degree" = "degree(rv$g,mode='out')",
"Degree" = "degree(rv$g,mode='all')",
"Weighted In-Degree" = "graph.strength(rv$g,mode='in')",
"Weighted Out-Degree" = "graph.strength(rv$g,mode='out')",
"Weighted Degree" = "graph.strength(rv$g,mode='all')",
"Betwenness" = "betweenness(rv$g)",
"Closeness" = "closeness(rv$g)",
"PageRank" = "page_rank(rv$g)$vector")
}
#--------------------#
#initialize selectors ----
#--------------------#
updateSelectizeInput(session = session, inputId = 'centralLay',
choices = vattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'nodeColAttr',
choices = vattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'nodeLabelAttr',
choices = c("None",igraph::vertex_attr_names(g)),
selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'nodeColAttrD',
choices = vattrD.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'nodeSizeAttr',
choices = vattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'edgeColAttr',
choices = eattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'edgeColAttrD',
choices = eattrD.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'edgeSizeAttr',
choices = eattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'edgeAlphaAttr',
choices = eattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'centindex',
choices = cent_choice, selected = cent_choice[1], server = TRUE,
options = list(create = TRUE))
#--------------------#
#be sure either discrete or continuos is selected ----
#--------------------#
shiny::observe({
if(input$nodeColAttr!="None"){
shiny::updateSelectInput(session,"nodeColAttrD",selected="None")
}
})
shiny::observe({
if(input$nodeColAttrD!="None"){
shiny::updateSelectInput(session,"nodeColAttr",selected="None")
}
})
shiny::observe({
if(input$edgeColAttr!="None"){
shiny::updateSelectInput(session,"edgeColAttrD",selected="None")
}
})
shiny::observe({
if(input$edgeColAttrD!="None"){
shiny::updateSelectInput(session,"edgeColAttr",selected="None")
}
})
#--------------------#
#calculate initial layout ----
#--------------------#
shiny::observeEvent(input$del.isolate,{
idx <- which(degree(rv$g)==0)
if(length(idx)>=1){
g <- igraph::delete.vertices(rv$g,idx)
xy <- rv$xy[-idx,]
rv$g <- g
rv$xy <- xy
gg_reactive()
}
})
shiny::observeEvent(input$do.layout,{
if(input$graphLayout=="graphlayouts::layout_as_backbone"){
xy <- eval(parse(text = paste0(input$graphLayout,"(rv$g)")))
rv$xy <- xy$xy
bb <- rep(0,ecount(rv$g))
bb[xy$backbone] <- 1
g <- igraph::set.edge.attribute(graph = rv$g,name = "backbone",value = bb)
rv$g <- g
eattr.to.aes <- igraph::edge_attr_names(g)
if(length(eattr.to.aes)>0){
idC <- which(sapply(eattr.to.aes,function(x) is.numeric(igraph::get.edge.attribute(g,x))))
eattrC.to.aes <- c("None",eattr.to.aes[idC])
} else{
eattrC.to.aes <- c("None")
}
updateSelectizeInput(session = session, inputId = 'edgeColAttr',
choices = eattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'edgeSizeAttr',
choices = eattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'edgeAlphaAttr',
choices = eattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
} else if(input$graphLayout=="graphlayouts::layout_with_focus"){
xy <- eval(parse(text = paste0(input$graphLayout,"(rv$g, v = ",input$focalNode,")$xy")))
rv$xy <- xy
} else if(input$graphLayout=="graphlayouts::layout_with_centrality"){
xy <- eval(parse(text = paste0(input$graphLayout,"(rv$g, cent = get.vertex.attribute(rv$g,\"",input$centralLay,"\"))")))
rv$xy <- xy
}
else{
xy <- eval(parse(text = paste0(input$graphLayout,"(rv$g)")))
rv$xy <- xy
}
gg_reactive()
})
#--------------------#
#tweak layout ----
#--------------------#
shiny::observeEvent(input$tweakxy,{
indX <- as.numeric(input$nodeId)
rv$xy[indX,1] <- input$tweakxy$x
rv$xy[indX,2] <- input$tweakxy$y
gg_reactive()
})
#--------------------#
#calculate centrality/clustering ----
#--------------------#
shiny::observeEvent(input$calcIndex, {
attr_name <- gsub("\\(rv.*","",input$centindex)
if(igraph::is_directed(g) & attr_name=="degree"){
opt <- gsub("')","",gsub(".*mode='","",input$centindex))
attr_name <- paste0(opt,"_",attr_name)
}
if(igraph::is_directed(g) & attr_name=="graph.strength"){
opt <- gsub("')","",gsub(".*mode='","",input$centindex))
attr_name <- paste0(opt,"_",attr_name)
}
if(!attr_name%in%igraph::vertex_attr_names(rv$g)){
ind <- eval(parse(text=input$centindex))
g <- igraph::set.vertex.attribute(graph = rv$g,name = attr_name,value = ind)
rv$g <- g
vattr.to.aes <- igraph::vertex_attr_names(rv$g)[!grepl("name",igraph::vertex_attr_names(rv$g))]
idC <- which(sapply(vattr.to.aes,function(x) is.numeric(igraph::get.vertex.attribute(rv$g,x))))
vattrC.to.aes <- c("None",vattr.to.aes[idC])
updateSelectizeInput(session = session, inputId = 'centralLay',
choices = vattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'nodeColAttr',
choices = vattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'nodeSizeAttr',
choices = vattrC.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'nodeLabelAttr',
choices = c("None",igraph::vertex_attr_names(g)),
selected = "None", server = TRUE,
options = list(create = TRUE))
}
})
shiny::observeEvent(input$calcClust, {
attr_name <- gsub("\\(rv.*","",input$clusteralg)
if(!attr_name%in%igraph::vertex_attr_names(rv$g)){
ind <- eval(parse(text=input$clusteralg))
ind <- as.character((igraph::membership(ind)))
g <- igraph::set.vertex.attribute(graph = rv$g,name = attr_name,value = ind)
rv$g <- g
vattr.to.aes <- igraph::vertex_attr_names(rv$g)[!grepl("name",igraph::vertex_attr_names(rv$g))]
idC <- which(sapply(vattr.to.aes,function(x) !is.numeric(igraph::get.vertex.attribute(rv$g,x))))
vattrD.to.aes <- c("None",vattr.to.aes[idC])
updateSelectizeInput(session = session, inputId = 'nodeColAttrD',
choices = vattrD.to.aes, selected = "None", server = TRUE,
options = list(create = TRUE))
updateSelectizeInput(session = session, inputId = 'nodeLabelAttr',
choices = c("None",igraph::vertex_attr_names(g)),
selected = "None", server = TRUE,
options = list(create = TRUE))
}
})
#------------------------------------------------------------#
#--------------------#
#main plotting function ----
#--------------------#
gg_reactive <- reactive({
validate(
need(is.validColour(input$nodeColMan), ''),
need(is.validColour(input$edgeColMan), ''),
need(is.validColour(input$nodeBorderColMan), ''),
# need(is.validColour(input$nodeColAttr), ''),
# need(is.validColour(input$nodeColAttrL), ''),
# need(is.validColour(input$nodeColAttrH), ''),
# need(is.validColour(input$edgeColAttr), ''),
# need(is.validColour(input$edgeColAttrL), ''),
# need(is.validColour(input$edgeColAttrH), ''),
need(is.validColour(input$edgeColMan), '')
)
#--------------------#
#layout ----
#--------------------#
# xy <- get_layout()
code_layout <- "ggraph(rv$g,layout = \"manual\", x = rv$xy[,1], y = rv$xy[,2])"
#--------------------#
#nodes ----
#--------------------#
if(input$nodeColAttr=="None" & input$nodeColAttrD=="None" & input$nodeSizeAttr=="None"){
code_nodes <- paste0("geom_node_point(",
"fill = \"",input$nodeColMan,"\"",
",colour = \"",input$nodeBorderColMan,"\"",
",size = ",input$nodeSizeMan,
",stroke = ", input$nodeBorderSizeMan,
",shape = 21",
")")
} else if(input$nodeColAttr!="None" & input$nodeSizeAttr=="None"){
code_nodes <- paste0("geom_node_point(",
"aes(fill = ",input$nodeColAttr,")",
",\ncolour = \"",input$nodeBorderColMan,"\"",
",\nsize = ",input$nodeSizeMan,
",\nshape = 21",
", stroke = ", input$nodeBorderSizeMan,
")")
nodes_scale_col <- paste0("scale_fill_gradient(low = \"",input$nodeColAttrL,"\",",
"high = \"",input$nodeColAttrH,"\")")
code_nodes <- paste(code_nodes,nodes_scale_col,sep=" + ")
} else if(input$nodeColAttrD!="None" & input$nodeSizeAttr=="None"){
code_nodes <- paste0("geom_node_point(",
"aes(fill = ",input$nodeColAttrD,")",
",\ncolour = \"",input$nodeBorderColMan,"\"",
",\nsize = ",input$nodeSizeMan,
",\nshape = 21",
", stroke = ", input$nodeBorderSizeMan,
")")
nodes_scale_col <- paste0("scale_fill_brewer(palette = \"",input$nodeColAttrP,"\", na.value = \"gray53\")")
code_nodes <- paste(code_nodes,nodes_scale_col,sep=" + ")
} else if(input$nodeColAttr=="None" & input$nodeColAttrD=="None" & input$nodeSizeAttr!="None"){
code_nodes <- paste0("geom_node_point(",
"aes(size = ",input$nodeSizeAttr,")",
",\nfill = \"",input$nodeColMan,"\"",
",\ncolour = \"",input$nodeBorderColMan,"\"",
",\nshape = 21",
", stroke = ", input$nodeBorderSizeMan,
")")
nodes_scale_size <- paste0("scale_size(range = c(",input$nodeSizeAttrL,",",input$nodeSizeAttrH,"))")
code_nodes <- paste(code_nodes,nodes_scale_size,sep=" + ")
} else if(input$nodeColAttr!="None" & input$nodeSizeAttr!="None"){
code_nodes <- paste0("geom_node_point(",
"aes(fill = ",input$nodeColAttr,
",size = ",input$nodeSizeAttr,")",
",\ncolour = \"",input$nodeBorderColMan,"\"",
",\nshape = 21",
", stroke = ", input$nodeBorderSizeMan,
")")
nodes_scale_col <- paste0("scale_fill_gradient(low = \"",input$nodeColAttrL,"\",",
"high = \"",input$nodeColAttrH,"\")")
nodes_scale_size <- paste0("scale_size(range = c(",input$nodeSizeAttrL,",",input$nodeSizeAttrH,"))")
code_nodes <- paste(code_nodes,nodes_scale_col,nodes_scale_size,sep=" + ")
} else if(input$nodeColAttrD!="None" & input$nodeSizeAttr!="None"){
code_nodes <- paste0("geom_node_point(",
"aes(fill = ",input$nodeColAttrD,
", size = ",input$nodeSizeAttr,")",
",\ncolour = \"",input$nodeBorderColMan,"\"",
",\nshape = 21",
", stroke = ", input$nodeBorderSizeMan,
")")
nodes_scale_col <- paste0("scale_fill_brewer(palette = \"",input$nodeColAttrP,"\", na.value = \"gray53\")")
nodes_scale_size <- paste0("scale_size(range = c(",input$nodeSizeAttrL,",",input$nodeSizeAttrH,"))")
code_nodes <- paste(code_nodes,nodes_scale_col,nodes_scale_size,sep=" + ")
}
#--------------------#
#nodes labels ----
#--------------------#
if(input$nodeLabelAttr!="None" & input$nodeLabelAttr!=""){
code_labels <- paste0("geom_node_text(",
"aes(label = ",input$nodeLabelAttr,")",
", colour = \"",input$nodeLabelCol,"\"",
", size = ",input$nodeLabelSize,
", family = \"",input$nodeLabelFont,"\"",
")")
if(input$nodeLabelRepel){
insert <- paste0(", repel = ",input$nodeLabelRepel, ",segment.alpha=0)")
code_labels <- gsub("\\)$",insert,code_labels)
}
code_nodes <- paste(code_nodes,code_labels,sep=" + ")
}
#--------------------#
#edges ----
#--------------------#
if(input$edgeColAttr=="None" & input$edgeColAttrD=="None" & input$edgeSizeAttr=="None" & input$edgeAlphaAttr=="None"){
code_edges <- paste0(edge_geom,
"edge_colour = \"",input$edgeColMan,"\"",
",edge_width = ",input$edgeSizeMan,
",edge_alpha = ",input$edgeAlphaMan,")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
} else if(input$edgeColAttr!="None" & input$edgeSizeAttr=="None" & input$edgeAlphaAttr=="None"){
code_edges <- paste0(edge_geom,
"aes(colour = ",input$edgeColAttr,")",
",edge_width = ",input$edgeSizeMan,
",edge_alpha = ",input$edgeAlphaMan,")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_col <- paste0("scale_edge_colour_gradient(low = \"",input$edgeColAttrL,"\",",
"high = \"",input$edgeColAttrH,"\")")
code_edges <- paste(code_edges,edge_scale_col,sep=" + ")
} else if(input$edgeColAttrD!="None" & input$edgeSizeAttr=="None" & input$edgeAlphaAttr=="None"){
code_edges <- paste0(edge_geom,
"aes(colour = ",input$edgeColAttrD,")",
",edge_width = ",input$edgeSizeMan,
",edge_alpha = ",input$edgeAlphaMan,")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_col <- paste0("scale_edge_colour_brewer(palette = \"",
input$edgeColAttrP,"\", na.value = \"gray53\")")
code_edges <- paste(code_edges,edge_scale_col,sep=" + ")
} else if(input$edgeColAttr=="None" & input$edgeColAttrD=="None" & input$edgeSizeAttr!="None" & input$edgeAlphaAttr=="None"){
code_edges <- paste0(edge_geom,
"aes(width = ",input$edgeSizeAttr,")",
",\nedge_colour = \"",input$edgeColMan,"\"",
",edge_alpha = ",input$edgeAlphaMan,")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_size <- paste0("scale_edge_width(",
"range = c(",input$edgeSizeAttrL,",",input$edgeSizeAttrH,"))")
code_edges <- paste(code_edges,edge_scale_size,sep=" + ")
} else if(input$edgeColAttr=="None" & input$edgeColAttrD=="None" & input$edgeSizeAttr=="None" & input$edgeAlphaAttr!="None"){
code_edges <- paste0(edge_geom,
"aes(alpha = ",input$edgeAlphaAttr,")",
",\nedge_colour = \"",input$edgeColMan,"\"",
",\nedge_width = ",input$edgeSizeMan,")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_alpha <- paste0("scale_edge_alpha(",
"range = c(",input$edgeAlphaAttrL,",",input$edgeAlphaAttrH,"))")
code_edges <- paste(code_edges,edge_scale_alpha,sep=" + ")
} else if(input$edgeColAttr!="None" & input$edgeSizeAttr!="None" & input$edgeAlphaAttr=="None"){
code_edges <- paste0(edge_geom,
"aes(width = ",input$edgeSizeAttr,
",\ncolour = ",input$edgeColAttr,")",
",edge_alpha = ",input$edgeAlphaMan,")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_size <- paste0("scale_edge_width(",
"range = c(",input$edgeSizeAttrL,",",input$edgeSizeAttrH,"))")
edge_scale_col <- paste0("scale_edge_colour_gradient(low = \"",input$edgeColAttrL,"\",",
"high = \"",input$edgeColAttrH,"\")")
code_edges <- paste(code_edges,edge_scale_col,edge_scale_size,sep=" + ")
}else if(input$edgeColAttrD!="None" & input$edgeSizeAttr!="None" & input$edgeAlphaAttr=="None"){
code_edges <- paste0(edge_geom,
"aes(width = ",input$edgeSizeAttr,
",\ncolour = ",input$edgeColAttrD,")",
",edge_alpha = ",input$edgeAlphaMan,")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_size <- paste0("scale_edge_width(",
"range = c(",input$edgeSizeAttrL,",",input$edgeSizeAttrH,"))")
edge_scale_col <- paste0("scale_edge_colour_brewer(palette = \"",
input$edgeColAttrP,"\", na.value = \"gray53\")")
code_edges <- paste(code_edges,edge_scale_col,edge_scale_size,sep=" + ")
} else if(input$edgeColAttr!="None" & input$edgeSizeAttr=="None" & input$edgeAlphaAttr!="None"){
code_edges <- paste0(edge_geom,
"aes(alpha = ",input$edgeAlphaAttr,
",colour = ",input$edgeColAttr,")",
",\nedge_width = ",input$edgeSizeMan,")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_alpha <- paste0("scale_edge_alpha(",
"range = c(",input$edgeAlphaAttrL,",",input$edgeAlphaAttrH,"))")
edge_scale_col <- paste0("scale_edge_colour_gradient(low = \"",input$edgeColAttrL,"\",",
"high = \"",input$edgeColAttrH,"\")")
code_edges <- paste(code_edges,edge_scale_col,edge_scale_alpha,sep=" + ")
} else if(input$edgeColAttrD!="None" & input$edgeSizeAttr=="None" & input$edgeAlphaAttr!="None"){
code_edges <- paste0(edge_geom,
"aes(alpha = ",input$edgeAlphaAttr,
",colour = ",input$edgeColAttrD,")",
",\nedge_width = ",input$edgeSizeMan,")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_alpha <- paste0("scale_edge_alpha(",
"range = c(",input$edgeAlphaAttrL,",",input$edgeAlphaAttrH,"))")
edge_scale_col <- paste0("scale_edge_colour_brewer(palette = \"",
input$edgeColAttrP,"\", na.value = \"gray53\")")
code_edges <- paste(code_edges,edge_scale_col,edge_scale_alpha,sep=" + ")
} else if(input$edgeColAttr=="None" & input$edgeColAttrD=="None" & input$edgeSizeAttr!="None" & input$edgeAlphaAttr!="None"){
code_edges <- paste0(edge_geom,
"aes(alpha = ",input$edgeAlphaAttr,
",width = ",input$edgeSizeAttr,")",
",\nedge_colour = \"", input$edgeColMan,"\"",")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_alpha <- paste0("scale_edge_alpha(",
"range = c(",input$edgeAlphaAttrL,",",input$edgeAlphaAttrH,"))")
edge_scale_size <- paste0("scale_edge_width(",
"range = c(",input$edgeSizeAttrL,",",input$edgeSizeAttrH,"))")
code_edges <- paste(code_edges,edge_scale_size,edge_scale_alpha,sep=" + ")
} else if(input$edgeColAttr!="None" & input$edgeSizeAttr!="None" & input$edgeAlphaAttr!="None"){
code_edges <- paste0(edge_geom,
"aes(alpha = ",input$edgeAlphaAttr,
",width = ",input$edgeSizeAttr,
",\ncolour = ",input$edgeColAttr,")",")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_alpha <- paste0("scale_edge_alpha(",
"range = c(",input$edgeAlphaAttrL,",",input$edgeAlphaAttrH,"))")
edge_scale_size <- paste0("scale_edge_width(",
"range = c(",input$edgeSizeAttrL,",",input$edgeSizeAttrH,"))")
edge_scale_col <- paste0("scale_edge_colour_gradient(low = \"",input$edgeColAttrL,"\",",
"high = \"",input$edgeColAttrH,"\")")
code_edges <- paste(code_edges,edge_scale_col,edge_scale_size,edge_scale_alpha,sep=" + ")
} else if(input$edgeColAttrD!="None" & input$edgeSizeAttr!="None" & input$edgeAlphaAttr!="None"){
code_edges <- paste0(edge_geom,
"aes(alpha = ",input$edgeAlphaAttr,
",width = ",input$edgeSizeAttr,
",\ncolour = ",input$edgeColAttrD,")",")")
if(is.directed(g)){
arrow_code <- paste0(",\narrow = arrow(angle = 30, length = unit(0.15, \"inches\")",
",\nends = \"last\", type = \"closed\"))")
code_edges <- gsub(")$",arrow_code,code_edges)
}
edge_scale_alpha <- paste0("scale_edge_alpha(",
"range = c(",input$edgeAlphaAttrL,",",input$edgeAlphaAttrH,"))")
edge_scale_size <- paste0("scale_edge_width(",
"range = c(",input$edgeSizeAttrL,",",input$edgeSizeAttrH,"))")
edge_scale_col <- paste0("scale_edge_colour_brewer(palette = \"",
input$edgeColAttrP,"\", na.value = \"gray53\")")
code_edges <- paste(code_edges,edge_scale_col,edge_scale_size,edge_scale_alpha,sep=" + ")
}
#----------------#
#theme ----
#----------------#
code_theme <- paste0("theme_graph() + theme(legend.position = \"",input$legendPos,"\")")
#----------------#
#glue ----
#----------------#
code <- paste(code_layout,code_edges,code_nodes,code_theme,sep=" + ")
if(input$showLabs){
code <- paste0(code,"+ geom_node_text(label = 1:vcount(rv$g),colour=\"white\")")
}
# p <- eval(parse(text = code))
p <- code
return(p)
})
#----------------#
DT_reactiveN <- reactive({
create_attribute_df(rv$g,which = "nodes")
})
DT_reactiveE <- reactive({
create_attribute_df(rv$g,which = "edges")
})
#----------------#
#render plot
ggnet <- renderPlot( {
eval(parse(text = gg_reactive()))
})
#render for save
plotInput = function() {
eval(parse(text = gg_reactive()))
}
#save plot as png
output$downloadData <- downloadHandler(
filename = "graph.png",
content = function(file) {
ggsave(file,plot=plotInput())
}
)
#render Attribute Manager
dfattrN <- DT::renderDataTable({
DT_reactiveN()
},options = list(
lengthMenu = list(c(10, 20, -1), c('10', '20', 'All')),
pageLength = 10,
searching = FALSE))
dfattrE <- DT::renderDataTable({
DT_reactiveE()
},options = list(
lengthMenu = list(c(10, 20, -1), c('10', '20', 'All')),
pageLength = 10,
searching = FALSE))
output$Graph1 <- ggnet
output$Graph2 <- ggnet
output$Graph3 <- ggnet
output$Graph4 <- ggnet
output$attrManageN <- dfattrN
output$attrManageE <- dfattrE
# DONE -----
observeEvent(input$done, {
result <- gg_reactive()
result <- gsub("ggraph\\(rv\\$g,",paste0("ggraph\\(",text,","),result)
V(rv$g)$x <- rv$xy[,1]
V(rv$g)$y <- rv$xy[,2]
result <- gsub("rv\\$xy\\[,1\\]","x",result)
result <- gsub("rv\\$xy\\[,2\\]","y",result)
# result <- gsub("rv\\$xy\\[,1\\]",paste0("V(",text,")$x"),result)
# result <- gsub("rv\\$xy\\[,2\\]",paste0("V(",text,")$y"),result)
#
result <- paste0("y <- ","c(",paste0(round(rv$xy[,2],4),collapse = ", "),")","\n\n",result)
result <- paste0("x <- ","c(",paste0(round(rv$xy[,1],4),collapse = ", "),")","\n",result)
result <- formatR::tidy_source(text=result,output = FALSE)$text.tidy
result <- gsub("\\+","\\+ \n\t",result)
result <- gsub("\n\\s*\n","\n",result)
eval(parse(text = paste0("assign(\"",text,"\",rv$g",",envir = .GlobalEnv)")))
rstudioapi::insertText(result)
invisible(stopApp())
})
observeEvent(input$cancel, {
invisible(stopApp())
})
}
viewer <- dialogViewer(dialogName = 'SNAhelper', width = 990, height = 900)
# viewer <- browserViewer(browser = getOption("browser"))
runGadget(ui, server, stopOnCancel = FALSE, viewer = viewer)
}
#' @export
#' @examples
#' if (interactive()) {
#' graph <- igraph::sample_gnp(100,0.2)
#' SNAhelperGadget(graph)
#' }
#' @rdname SNAhelper
SNAhelperGadget <- function(graph) {
if (missing(graph)) {
stop('You must provide an igraph object.', call. = FALSE)
}
graph <- deparse(substitute(graph))
if (grepl('^\\s*[[:alpha:]]+[[:alnum:]\\.]*\\s*$', paste0(graph, collapse = ''))) {
SNAhelper(graph)
} else {
stop('You must provide an igraph object.', call. = FALSE)
}
}
#' @export
#' @rdname SNAhelper
SNAhelperAddin <- function() {
context <- rstudioapi::getActiveDocumentContext()
text <- context$selection[[1]]$text
# text <- "gr"
if (nchar(text) == 0) {
stop('Please highlight an igraph object before using this addin.')
}
SNAhelper(text)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.