Wprowadzenie

‘visNetwork’ jest pakietem języka R który służy do wizualizacji sieci, używając biblioteki ‘vis.js’ języka javascript.

Funkcje

[komentarz] Pojawiło się dużo nazw pakietów, żeby się nie pogubić jedno zdanie o każdym: ‘visNetwork’ = Nasz pakiet do wizualizacji i robienia wykresów ‘vis.js’ = to jest biblioteka javascript która odpowiada za wyświetlanie tych wszystkich rzeczy w przeglądarce, plus posiada w sobie kawałki bibliotek ‘DataSet’, ‘Timeline’, ‘Network’, ‘Graph2d’, ‘Graph3d’. ‘htmlwidgets’ = odpowiada za używanie javascript w konsoli R, prostymi słowami to jest to co pokazuje nam obrazki wykresów (i inne) w prawym dolnym rogu R ‘Shiny’ = Pakiet R który odpowiada za budowanie interaktywnych web-apps prosto w R. ‘R Markdown documents’ = file format for making dynamic documents with R ‘RStudio viewer’ = to jest po prostu nasz graficzny interfejs R (jak klikamy w dataset i mamy wizualnie tabelkę itd.)

[komentarz] W kodzie pojawia się mało znany operator >%> aka pipe-forward. Używa się go aby nie pisać funkcji w funkcji: plot_it(summarize_it(transform_it(clean_it(read_it(x))))) z użyciem >%> to spaghetti na górze wygląda: x %>% read_it %>% clean_it %>% transform_it %>% summarize_it %>% plot_it

Instalacja

Aby skorzystać z dodatkowych pakietów w R należy wykonać dwa kroki: 1.Zainstalować nowy pakiet.. Ten krok wystarczy wykonać raz, skopiuje on niezbędne pliki do katalogu z pakietami. 2.Włączyć zainstalowany pakiet w działającej sesji R. Ten krok należy wykonać po każdym uruchomieniu środowiska R. Spowoduje on, że w aktualnej sesji będzie można korzystać z funkcji i zbiorów danych dostępnych w pakiecie.

install.packages("visNetwork")
library(visNetwork)

Węzły

Możemy dostosować węzły wieloma opcjami na wiele różnych sposobów.

Indywidualna konfiguracja

Węzły ‘nodes’ muszą być ramką danych ‘data.frame’, z co najmniej jedną kolumną ‘id’. Węzeł konfigurujemy poprzez dodanie zmiennych do ‘data.frame’. Żeby zobaczyć wszystkie opcje można wywołać ‘?visNodes’.

Przykład zawierający najczęściej używane opcje:

nodes <- data.frame(id = 1:10,
# dodanie etykiety na węzeł
label = paste("Węzeł", 1:10),
# dodanie grup do węzełóW
group = c("GrA", "GrB"),
# przypisanie wielkości skalujących
value = 1:10,         
# ustalenie wyglądu każdego węzła
shape = c("square", "triangle", "box", "circle", "dot", "star",
          "ellipse", "database", "text", "diamond"),
# co ma sie wyświetlać gdy najedziemy na węzeł myszką
title = paste0("To jest węzeł numer ", 1:10),
# kolor
color = c("darkred", "grey", "orange", "blue", "purple"),
# cień
shadow = c(FALSE, TRUE, FALSE, TRUE, TRUE))
# stworzenie połączeń pomiędzy węzłami
edges <- data.frame(from = c(1,2,3,4,5,6), to = c(9,8,7,1,1,5))
# wizualizacja
visNetwork(nodes, edges, height = "500px", width = "100%")

[Komentarz] Tutaj mamy przykład numer dwa, który mogę napisać od ręki tylko muszę mieć wenę jaki kształt to ma być. Coś takiego że damy kilogram węzłów i one w jakiś śmieszny kształt sie ułożą na przykład glona.

Globalna konfiguracja

Jeżeli chcemy ustawić jakąś konfiguracje dla wszystkich węzłów, możemy to zrobić w prosty sposób używając wbudowanych funkcji ‘visNodes’ :

nodes <- data.frame(id = 1:6)
edges <- data.frame(from = c(1,1,1,1,1), to = c(2,3,4,5,6))

visNetwork(nodes, edges, width = "100%") %>%
  visNodes(shape = "circle",
           color = list(background = "lightblue",
                        border = "darkblue",
                        highlight = "yellow"),
           shadow = list(enabled = TRUE, size = 10)) %>%
  visLayout(randomSeed = 420)

Możemy łączyć ze sobą konfiguracje indywidualną i globalną:

nodes <- data.frame(id = 1:6,
                    shape = "square",
                    label = LETTERS[1:6])
edges <- data.frame(from = c(1,1,1,1,1), to = c(2,3,4,5,6))

visNetwork(nodes, edges, width = "100%") %>%
  visNodes(shape = "circle",
           color = list(background = "lightblue",
                        border = "darkblue",
                        highlight = "yellow"),
           shadow = list(enabled = TRUE, size = 10)) %>%
  visLayout(randomSeed = 420)

Używaj złożonej konfiguracji indywidualnie!

Gdy opcje są dostępne przy użyciu listy, możemy użyć ich w ramce danych z określoną notacją:

nodes <- data.frame(id = 1:4, 
                    color.background = c("red", "blue", "green", "pink"),
                    color.highlight.background = c("yellow", NA, "cyan", "magenta"), 
                    shadow.size = c(5, 10, 15, 20))

edges <- data.frame(from = c(1,2), to = c(2,4),
                    label = LETTERS[1:4], 
                    font.color =c ("red", "blue", "green", "pink"), 
                    font.size = c(10,20,30,40))

visNetwork(nodes, edges)

Krawędzie

Możemy dostosować krawędzie wieloma opcjami na wiele różnych sposobów, w taki sam sposób jak węzły.

Indywidualna konfiguracja

Krawędzie ‘edges’ muszą być ramką danych ‘data.frame’, z co najmniej jedną kolumną ‘from’ i ‘to’’. Węzeł konfigurujemy poprzez dodanie zmiennych do ‘data.frame’. Żeby zobaczyć wszystkie opcje można wywołać ‘?visNodes’.

Najczęściej używane są przedstawione w poniższym przykładzie:

Globalna konfiguracja

Jeżeli chcemy ustawić jakąś konfiguracje dla wszystkich krawędzi, możemy to zrobić w prosty sposób używając wbudowanych funkcji ‘visEdges’ :

nodes <- data.frame(id = 1:9)
edges <- data.frame(from = c(2,4,3,5,7,6,9,2,8), to = c(1,2,4,3,6,5,7,8,9))

visNetwork(nodes, edges, width = "100%") %>%
  visEdges(shadow = TRUE,
           arrows = list(to = list(enabled = TRUE, scaleFactor = 2)),
           color = list(color = "green", highlight = "pink")) %>%
  visLayout(randomSeed = 12)

Możemy łączyć ze sobą konfiguracje indywidualną i globalną

nodes <- data.frame(id = 1:4, label = 1:4)
edges <- data.frame(from = c(2,4,3,2), 
                    to = c(1,2,4,3), 
                    dashes = c(TRUE, FALSE))

visNetwork(nodes, edges, width = "100%") %>% 
  visEdges(shadow = TRUE,
           arrows =list(to = list(enabled = TRUE, scaleFactor = 2)),
           color = list(color = "lightblue", highlight = "red")) %>%
  visLayout(randomSeed = 12)

Gdy opcje są dostępne przy użyciu listy, możemy użyć ich w ramce danych z określoną notacją:

visNetwork(nodes, edges, height = "500px", width = "100%")
nodes <- data.frame(id = 1:3, 
                    color.background = c("red", "blue", "green"),
                    color.highlight.background = c("red", NA, "red"), 
                    shadow.size = c(5, 15, 25))

edges <- data.frame(from = c(1,2), to = c(1,3),
                    label = LETTERS[1:2], 
                    font.color =c ("pink", "black"), 
                    font.size = c(10,20))

visNetwork(nodes, edges)  

Grupy

Możesz oddziaływać na grupę do węzła używając kolumny ‘group’ w węźle data.frame, i dodać konfiguracje dla grupy używając ‘visGroups’.

nodes <- data.frame(id = 1:5, group = c(rep("A", 2), rep("B", 3)))
edges <- data.frame(from = c(1,2,3,4,5), to = c(2,3,1,1,1))

visNetwork(nodes, edges, width = "100%") %>% 
  # grupa A kwadraty koloru cyan
  visGroups(groupname = "A", color = "cyan", shape = "square") %>% 
  # grupa B trojkaty koloru rozowego
  visGroups(groupname = "B", color = "pink", shape = "triangle")  

Legenda i tytul

Możesz dodać tytuł (‘main’), podtytuł (‘subtitle’) oraz stopkę (‘footer’) do swojej sieci:

nodes <- data.frame(id = 1:3)
edges <- data.frame(from = c(1,2), to = c(2,3))

visNetwork(nodes, edges, 
           main = "Prosty przyklad", 
           submain = list(text = "Twój podtytul",
                          style = "font-family:Comic Sans MS;color:#ff0000;font-size:15px;text-align:center;"), 
           footer = "Twoja stopka",
           width = "100%")

Używaj obrazów lub ikon

Obrazy

Aby użyć obrazów w węzłach, najpierw musisz ustawić shape w image lub circularImage. Następnie ustaw ścieżkę względną lub bezwzględną na wartości image W przypadku błędnej ścieżki dostępna jest opcja: brokenImage Możesz używać obramowań z shapeProperties i useBorderWithImage

path_to_images <- "https://raw.githubusercontent.com/datastorm-open/datastorm-open.github.io/master/visNetwork/data/img/indonesia/"

nodes <- data.frame(id = 1:4, 
                    shape = c("image", "circularImage"),
                    image = paste0(path_to_images, 1:4, ".png"),
                    label = "I'm an image")

edges <- data.frame(from = c(1,4,3,2), to = c(1,2,4,2))

visNetwork(nodes, edges, width = "100%") %>% 
  visNodes(shapeProperties = list(useBorderWithImage = TRUE)) %>%
  visLayout(randomSeed = 2)

fontAwesome icons

visNetwork obsługuje ikony fontAwesome. Font-awesome nie jest częścią domyślnych zależności, ale w razie potrzeby możesz użyć addFontAwesome().

Aby używać ikon w węzłach, musisz najpierw ustawić kształt na ikonę. Opcje ikon muszą być listą, więc musisz użyć visNodes lub visGroups lub przekazać bezpośrednio w nodes data.frame (patrz przykład Ionicons poniżej) Wybierz ikonę według kodu, ustaw rozmiar i kolor

nodes <- data.frame(id = 1:3, group = c("B", "A", "B"))
edges <- data.frame(from = c(1,2), to = c(2,3))

visNetwork(nodes, edges, width = "100%") %>%
  visGroups(groupname = "A", shape = "icon", 
            icon = list(code = "f0c0", size = 75)) %>%
  visGroups(groupname = "B", shape = "icon", 
            icon = list(code = "f007", color = "red")) %>%
  addFontAwesome()

Ionicons

Obsługa ikon Ionicons. W przypadku wystepowania zależności możesz w razie potrzeby użyć addIonicons(). Proces definiowania jest taki sam jak w przypadku ikon fontAwesome, z wyjątkiem tego, że musisz ustawić set = ‘Ionicons’.

nodes <- data.frame(id = 1:3, shape = "icon", icon.face = 'Ionicons',
                    icon.code = c("f101", "f100", "f101"))
edges <- data.frame(from = c(1,2), to = c(2,3))

visNetwork(nodes, edges) %>%
  addIonicons()

Opcje

Niektóre opcje niestandardowe są dostępne za pomocą visOptions().

nb <- 10
nodes <- data.frame(id = 1:nb, label = paste("Label", 1:nb),
 group = sample(LETTERS[1:3], nb, replace = TRUE), value = 1:nb,
 title = paste0("<p>", 1:nb,"<br>Tooltip !</p>"), stringsAsFactors = FALSE)

edges <- data.frame(from = c(8,2,7,6,1,8,9,4,6,2),
 to = c(3,7,2,7,9,1,5,3,2,9),
 value = rnorm(nb, 10), label = paste("Edge", 1:nb),
 title = paste0("<p>", 1:nb,"<br>Edge Tooltip !</p>"))

Wyróżnij najbliższe

Możesz podświetlić najbliższe węzły i krawędzie, klikając węzeł za pomocą funkcji HighlightNearest. Po prostu kliknij wszędzie z wyjątkiem węzłów, aby zresetować sieć:

visNetwork(nodes, edges, height = "500px", width = "100%") %>% 
  visOptions(highlightNearest = TRUE) %>%
  visLayout(randomSeed = 123)

Możliwe jest teraz kontrolowanie stopnia głębokości, a włączenie tej opcji umożliwia również najeżdżanie na węzły (najechanie). Po najechaniu kursorem możesz nadal używać kliknięcia, aby ustawić widok :

visNetwork(nodes, edges, height = "500px", width = "100%") %>% 
  visOptions(highlightNearest = list(enabled = T, degree = 2, hover = T)) %>%
  visLayout(randomSeed = 123)

Ta funkcja jest dostępna również z obrazami i ikonami:

visNetwork(nodes, edges, height = "500px", width = "100%") %>% 
  visGroups(groupname = "A", shape = "icon", 
            icon = list(code = "f0c0", size = 75)) %>%
  visGroups(groupname = "B", shape = "icon", 
            icon = list(code = "f007", color = "red")) %>%
  visGroups(groupname = "C", shape = "icon", 
            icon = list(code = "f1b9", color = "black")) %>%
  visOptions(highlightNearest = list(enabled =TRUE, degree = 2, hover = T)) %>%
  addFontAwesome() %>%
  visLayout(randomSeed = 123)

Wybierz według identyfikatora węzła

Możesz również wybrać węzeł według id/etykiety z listą za pomocą nodesIdSelection:

visNetwork(nodes, edges, height = "500px", width = "100%") %>% 
  visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE) %>%
  visLayout(randomSeed = 123)

Wybierz według kolumny

Wybierz podzbiór węzłów według wartości kolumny za pomocą selectedBy. Węzły mogą mieć wiele grup przy użyciu wartości oddzielonych przecinkami:

w “autoryzowanej” kolumnie

visNetwork(nodes, edges, height = "500px", width = "100%") %>%
  visOptions(selectedBy = "group") %>%
  visLayout(randomSeed = 123)

w nowej kolumnie z wieloma grupami

nodes$sample <- paste(sample(LETTERS[1:3], nrow(nodes), replace = TRUE),
                      sample(LETTERS[1:3], nrow(nodes), replace = TRUE), 
                      sep = ",")
nodes$label <- nodes$sample

visNetwork(nodes, edges, height = "500px", width = "100%") %>%
  visOptions(selectedBy = list(variable = "sample", multiple = T)) %>%
  visLayout(randomSeed = 123)

Opcje dostosowywania

Dostępnych jest wiele funkcji umożliwiających dostosowanie selectedBy & nodesIdSelection, na przykład:

wartości : kontroluj dostępne wartości na liście wybrane: zainicjuj wybór styl: dostosuj css listy To jest przykład bazujacy na nodesIdSelection :

visNetwork(nodes, edges, height = "500px", width = "100%") %>% 
  visOptions(highlightNearest = TRUE, 
              nodesIdSelection = list(enabled = TRUE,
                                 selected = "8",
                                 values = c(5:10),
                                 style = 'width: 200px; height: 26px;
                                 background: #f8f8f8;
                                 color: darkblue;
                                 border:none;
                                 outline:none;')) %>%
  visLayout(randomSeed = 123)

Zwiń / Rozwiń węzły

nodes <- data.frame(id = 1:15, label = paste("Label", 1:15),
 group = sample(LETTERS[1:3], 15, replace = TRUE))

edges <- data.frame(from = trunc(runif(15)*(15-1))+1,
 to = trunc(runif(15)*(15-1))+1)
 
# keeping all parent node attributes  
visNetwork(nodes, edges) %>% visEdges(arrows = "to") %>%
 visOptions(collapse = TRUE)

Manipulacja danymi

Korzystając z manipulacji, możesz edytować swoją sieć:

Dodaj/usuń węzły/krawędzie Zmień linki

visNetwork(nodes, edges, height = "500px", width = "100%") %>% 
  visOptions(manipulation = TRUE) %>%
  visLayout(randomSeed = 123)

Przykład „Nedznicy”

nodes <- jsonlite::fromJSON("https://raw.githubusercontent.com/datastorm-open/datastorm-open.github.io/master/visNetwork/data/nodes_miserables.json")

edges <- jsonlite::fromJSON("https://raw.githubusercontent.com/datastorm-open/datastorm-open.github.io/master/visNetwork/data/edges_miserables.json")


visNetwork(nodes, edges, height = "700px", width = "100%") %>%
  visOptions(selectedBy = "group", 
             highlightNearest = TRUE, 
             nodesIdSelection = TRUE) %>%
  visPhysics(stabilization = FALSE)

Uklad

Układ można konfigurować za pomocą funkcji visLayout() i visHierarchicalLayout().

Ustawianie ziarna

Węzły są początkowo rozmieszczone losowo. Oznacza to, że ustalony wynik jest za każdym razem inny. Jeśli podasz losowe ziarno ręcznie (randomSeed), układ będzie za każdym razem taki sam.

Układ hierarchiczny

Możesz używać i kontrolować układ hierarchiczny z niektórymi opcjami:

levelSeparation- odległość między różnymi poziomami. direction- kierunek układu hierarchicznego. sortMethod- algorytm używany do określania poziomów węzłów na podstawie danych

nodes <- data.frame(id = 1:7)
edges <- data.frame(from = c(1,2,2,2,3,3),
 to = c(2,3,4,5,6,7))
visNetwork(nodes, edges, width = "100%") %>% 
  visEdges(arrows = "from") %>% 
  visHierarchicalLayout()
visNetwork(nodes, edges, width = "100%") %>% 
  visEdges(arrows = "from") %>% 
  visHierarchicalLayout(direction = "LR", levelSeparation = 500)

Możliwe jest również zdefiniowanie poziomu każdego węzła:

  nodes <- data.frame(id = 1:4, level = c(2, 1, 1, 1))
edges <- data.frame(from = c(1, 1, 1),
 to = c(2,3,4))

Z poziomem wezla:

visNetwork(nodes, edges, width = "100%") %>% 
  visEdges(arrows = "from") %>% 
  visHierarchicalLayout()

Brak poziomu wezla:

nodes$level <- NULL
visNetwork(nodes, edges, width = "100%") %>% 
  visEdges(arrows = "from") %>% 
  visHierarchicalLayout()

Pakiet Igraph

Od visNetwork_0.2.1 możliwe jest powiązanie funkcji pakietu igraph z funkcjami visNetwork. Użyj układu igraph do obliczenia współrzędnych w celu szybkiego renderowania za pomocą visIgraphLayout() Przekształć sieć igraph w sieć visNetwork za pomocą visIgraph() lub toVisNetworkData()

Użyj układu Igraf

Dzięki visIgraphLayout() możesz wykorzystać wszystkie dostępne układy w igraph i obliczyć współrzędne przed wysłaniem do vis.js :

nnodes <- 100
nnedges <- 200

nodes <- data.frame(id = 1:nnodes)
edges <- data.frame(from = sample(1:nnodes, nnedges, replace = T),
                    to = sample(1:nnodes, nnedges, replace = T))
visNetwork(nodes, edges, height = "500px") %>%
  visIgraphLayout() %>%
  visNodes(size = 10)
visNetwork(nodes, edges, height = "500px") %>%
  visIgraphLayout(layout = "layout_in_circle") %>%
  visNodes(size = 10) %>%
  visOptions(highlightNearest = list(enabled = T, hover = T), 
             nodesIdSelection = T)

Użyj sieci Igraph

visIgraph bezpośrednio przekształca sieć igraph w visNetwork. Możesz również użyć toVisNetworkData, aby po prostu uzyskać dane w formacie visNetwork:

library("igraph", quietly = TRUE, warn.conflicts = FALSE, verbose = FALSE)
## Warning: package 'igraph' was built under R version 4.0.5
igraph_network <- graph.famous("Walther")

plot(igraph_network)

dane i wykres:

data <- toVisNetworkData(igraph_network)
visNetwork(nodes = data$nodes, edges = data$edges, height = "500px")

lub tylko wykres:

visIgraph(igraph_network)

Wydajnosc

Przy domyślnych/niektórych opcjach renderowanie sieci może zająć dużo czasu. Oto kilka sposobów na poprawę wydajności:

Domyślnie, jeśli nie przekazujemy żadnych informacji o współrzędnych, vis.js oblicza współrzędne dynamicznie i czeka na stabilizację przed renderowaniem. Możesz wyłączyć lub kontrolować stabilizację za pomocą visPhysics :

visNetwork(nodes, edges) %>%
  visPhysics(stabilization = FALSE)

Kolejną wskazówką jest wyłączenie gładkiej krzywej dla krawędzi. To prowadzi do lepszej wydajnosci:

visNetwork(nodes, edges) %>%
  visEdges(smooth = FALSE)

Możliwe jest powiązanie funkcji pakietu igraph z funkcjami visNetwork. Najlepszym sposobem na wydłużenie czasu kreślenia grafu jest użycie układu igraph do obliczenia współrzędnych wcześniej za pomocą visIgraphLayout():

visNetwork(nodes, edges) %>%
  visIgraphLayout()

Koszyk

Od wersji visNetwork_2.0.0 możesz wizualizować drzewa klasyfikacji i regresji z danych wyjściowych pakietu rpart, używając po prostu visTree :

Drzewo klasyfikacyjne

library(rpart)
library(htmlwidgets)
## Warning: package 'htmlwidgets' was built under R version 4.0.5
library(sparkline)
## Warning: package 'sparkline' was built under R version 4.0.5
res <- rpart(Species~., data=iris)
visTree(res, main = "Iris classification Tree", width = "100%")

Drzewo regresji

res <- rpart(Petal.Length~., data=iris)
visTree(res, edgesFontSize = 14, nodesFontSize = 16, width = "100%")
data("solder")
res <- rpart(Opening~., data = solder, control = rpart.control(cp = 0.00005))
visTree(res, height = "800px", nodesPopSize = TRUE, minNodeSize = 10, 
        maxNodeSize = 30, width = "100%")

Użycie w shiny

Spójrz na visTreeEditor, aby edytować i wrócić do sieci, oraz na visTreeModuleServer, aby użyć niestandardowego modułu drzewa w R.

Shiny

Korzystaj z sieci w Shiny dzięki visNetworkOutput i renderVisNetwork

require(shiny)
## Loading required package: shiny
## Warning: package 'shiny' was built under R version 4.0.5
require(visNetwork)

server <- function(input, output) {
  output$mynetworkid <- renderVisNetwork({
    # minimal example
    nodes <- data.frame(id = 1:3)
    edges <- data.frame(from = c(1,2), to = c(1,3))
    
    visNetwork(nodes, edges)
  })
}

ui <- fluidPage(
    visNetworkOutput("mynetworkid")
)

shinyApp(ui = ui, server = server)

Shiny applications not supported in static R Markdown documents

Interakcje Shiny

dane wejściowe są tworzone po zainicjowaniu sieci: input$mynetworkid_initialized z nodesIdSelection możesz uzyskać dostęp do nowych danych wejściowych z bieżącą wartością wyboru:

Zmodyfikuj swoją sieć za pomocą visNetworkProxy

Aby nie przerysowywać całej sieci, możesz użyć funkcji visNetworkProxy w shiny, a następnie zmienić konfigurację swojej sieci bez jej przerysowywania.

Możesz korzystać z prawie wszystkich funkcji dostępnych w visNetworkProxy, a nawet z niektórych funkcji specjalnych.

klasyczne funkcje: visNodes, visEdges, visGroups, visOptions (>=0.2.2), visPhysics, visInteraction, visLayout & visHierarchicalLayout

funkcje specjalne (metody vis.js):

visFocus : skoncentruj się na jednym węźle docelowym visFit : dopasuj widok do jednego lub kilku węzłów visUpdateNodes / visUpdateEdges : aktualizuj / dodaj dane visRemoveNodes / visRemoveEdges : usuń dane visSelectNodes / visSelectEdges / visSetSelection: wybór a także visRedraw, visStabilize,visSetData,visGetPositions,visMoveNode,visUnselectAll

require(shiny)
require(visNetwork)

server <- function(input, output) {
  output$network_proxy_nodes <- renderVisNetwork({
    nodes <- data.frame(id = 1:3)
    edges <- data.frame(from = c(1,2), to = c(1,3))
    
    visNetwork(nodes, edges) %>% visNodes(color = "blue")
  })
  
  
  observe({
    visNetworkProxy("network_proxy_nodes") %>%
      visFocus(id = input$Focus, scale = 4)
  })
  
  observe({
    visNetworkProxy("network_proxy_nodes") %>%
      visNodes(color = input$color)
  })
  
}

ui <- fluidPage(
  fluidRow(
    column(
      width = 4,
      selectInput("color", "Color :",
                    c("blue", "red", "green")),
      selectInput("Focus", "Focus on node :",
                    c(1:3))
    ),
    column(
      width = 8,
      visNetworkOutput("network_proxy_nodes", height = "400px")
    )
  )
)

shinyApp(ui = ui, server = server)

Shiny applications not supported in static R Markdown documents