Выделите все подключенные пути от начала до конца в графе Санки, используя R

Я хочу выделить весь путь, когда я нажимаю на node, чтобы узнать всю историю конкретного node, и вот пример - http://bl.ocks.org/git-ashish/8959771.

Пожалуйста, проверьте эту ссылку, и вы найдете функцию, которая выделяет путь в javscript, но будьте осторожны, эта функция не делает то, что я хочу, она выделяет ссылки, связанные с щелчком node и ссылками, связанными с целевые узлы. я хочу выделить все ссылки, связанные с щелчком node.

d3 Sankey - выделить все подключенные пути от начала до конца

Вот пример того, что мне нужно, введите описание изображения здесь Это весь график, что мне нужно, когда я нажимаю на Бангкок, он выделяет все узлы, которые в том же самом сырье с Бангкоком в фреймворке данных, например, выделяют ссылку на ClimateChange и EnergyShortage, затем выделяют Infrastructure & Экосистемы, лидерство и стратегия, и.... Это то, что я хочу. Здесь другая картина, показывающая узлы, связанные с Бангкоком, блестящими, чтобы проанализировать ее.

введите описание изображения здесь

Вот что происходит, когда я использую highlight_node_links, который в bl.ocks и связанный вопрос, и что неправильно, и не показывает связь между узлами и бангкоками. введите описание изображения здесь

Здесь данные для Бангкока, чтобы показать вам, как столбцы связаны друг с другом, и когда вы используете эти данные, он будет генерировать только второе изображение.

structure(list(City = c("Bangkok", "Bangkok", "Bangkok", "Bangkok", 
"Bangkok", "Bangkok", "Bangkok", "Bangkok", "Bangkok", "Bangkok", 
"Bangkok", "Bangkok", "Bangkok", "Bangkok", "Bangkok", "Bangkok"
), ResiliencyChallenge = c("ClimateChange", "ClimateChange", 
"ClimateChange", "ClimateChange", "ClimateChange", "InfrastructureFaliure", 
"EnergyShortage", "Pollution", "Pollution", "Pollution", "TransportationSystemFailure", 
"TransportationSystemFailure", "TransportationSystemFailure", 
"TransportationSystemFailure", "TransportationSystemFailure", 
"TransportationSystemFailure"), CRI.Dimesnsion.1 = c("Infrastructure & Ecosystems", 
"Infrastructure & Ecosystems", "Infrastructure & Ecosystems", 
"Infrastructure & Ecosystems", "Infrastructure & Ecosystems", 
"Infrastructure & Ecosystems", "Infrastructure & Ecosystems", 
"Leadership & Strategy", "Leadership & Strategy", "Infrastructure & Ecosystems", 
"Infrastructure & Ecosystems", "Infrastructure & Ecosystems", 
"Infrastructure & Ecosystems", "Infrastructure & Ecosystems", 
"Infrastructure & Ecosystems", "Leadership & Strategy"), Implementation.time.frame = c("Short-term", 
"Short-term", "Short-term", "Short-term", "Short-term", "Mid-term", 
"Long-term", "Short-term", "Short-term", "Mid-term", "Mid-term", 
"Short-term", "Short-term", "Short-term", "Short-term", "Short-term"
), Goal = c("Goal13", "Goal13", "Goal13", "Goal13", "Goal13", 
"Goal12", "Goal12", "Goal11", "Goal11", "Goal11", "Goal11", "Goal11", 
"Goal11", "Goal11", "Goal11", "Goal11")), .Names = c("City", 
"ResiliencyChallenge", "CRI.Dimesnsion.1", "Implementation.time.frame", 
"Goal"), class = "data.frame", row.names = c(NA, -16L))

Ответ 1

Учитывая структуру данных R-кода, которую вы предоставили...

Во-первых, sankeyNetwork ожидает данных, которые перечисляют ребра/ссылки и узлы, которые связаны этими ссылками. Ваши данные имеют... пусть называют это "путешественником" -центричным форматом, где каждая строка ваших данных связана с определенным "путем". Поэтому сначала вам нужно преобразовать эти данные в тип данных, которые требуется sankeyNetwork, сохраняя при этом информацию, необходимую для идентификации ссылок на путь, из которого они пришли. Кроме того, ваши данные имеют только один город, поэтому будет трудно увидеть результат, если не будет по крайней мере двух разных истоков для путей в ваших данных, поэтому я продублирую его и присваиваю второй набор другому городу. Вот пример этого...

library(tidyverse)

# duplicate the data for another city so we have more than 1 origin
links <-
  df %>%
  full_join(mutate(df, City = "Hong Kong")) %>%
  mutate(row = row_number()) %>%
  mutate(origin = .[[1]]) %>%
  gather("column", "source", -row, -origin) %>%
  mutate(column = match(column, names(df))) %>%
  arrange(row, column) %>%
  group_by(row) %>%
  mutate(target = lead(source)) %>%
  ungroup() %>%
  filter(!is.na(target)) %>%
  select(source, target, origin) %>%
  group_by(source, target, origin) %>%
  summarise(count = n()) %>%
  ungroup()

nodes <- data.frame(name = unique(c(links$source, links$target)))
links$source <- match(links$source, nodes$name) - 1
links$target <- match(links$target, nodes$name) - 1

Теперь у вас есть кадр данных links и nodes в форме, ожидаемой sankeyNetwork, а в кадре данных links есть дополнительный столбец origin, который идентифицирует, в каком городе каждая ссылка находится на пути от, Теперь вы можете построить это с помощью sankeyNetwork, добавить обратно в исходные данные, так как он будет удален, а затем использовать htmlwidgets::onRender для назначения поведения клика, который изменяет непрозрачность любой ссылки, чье происхождение является городом node, который был нажал...

library(networkD3)
library(htmlwidgets)

sn <- sankeyNetwork(Links = links, Nodes = nodes, Source = 'source',
                    Target = 'target', Value = 'count', NodeID = 'name')

# add origin back into the links data because sankeyNetwork strips it out
sn$x$links$origin <- links$origin


# add onRender JavaScript to set the click behavior
htmlwidgets::onRender(
  sn,
  '
  function(el, x) {
    var nodes = d3.selectAll(".node");
    var links = d3.selectAll(".link");
    nodes.on("mousedown.drag", null); // remove the drag because it conflicts
    nodes.on("click", clicked);
    function clicked(d, i) {
      links
        .style("stroke-opacity", function(d1) {
            return d1.origin == d.name ? 0.5 : 0.2;
          });
    }
  }
  '
)