igraph — получить все ребра, которые образуют путь между двумя вершинами — Есть ли лучшее решение?

#r #igraph #edges

#r #igraph #ребра

Вопрос:

У меня есть график с разными маршрутами между контрольными точками (для прохождения маршрута). Пример может выглядеть следующим образом.

 library(ggraph)
library(igraph)
library(dplyr)

example_data = data.frame(start = c("D_2", "A_2", "A_2", "E_2", "G_2", "H_2", "G_2", "A_2", "B_2", "C_2", "C_2", "D_2"), 
                             end = c("D_1", "A_1", "B_1", "E_1", "G_1", "H_1", "F_1", "B_1", "A_1", "C_1", "C_1", "A_1"), 
                             length = rnorm(12, 100, 10),
                             difficulty = c("soft", "soft", "medium", "medium", "soft", "soft", "soft", "soft", "soft", "soft", "medium", "hard"),
                             trail = c(paste0("trail_", 1:11), "Fake_pist"), 
                             stringsAsFactors = F)

# relable connected end and start section points (sometimes the end of a trail is so close to the start of the next that they are seen as one point)
example_data$start[which(example_data$start %in%  c("D_1", "A_2"))] = "A_2_D_1"
example_data$end[which(example_data$end %in%  c("D_1", "A_2"))] = "A_2_D_1"

example_graph = graph_from_data_frame(example_data, directed = T)
  

Могут быть разные маршруты или комбинации маршрутов для перехода от одной контрольной точки к другой, график является направленным, поскольку выполнение маршрута разрешено только в одном направлении.

 p <- ggraph(example_graph)   
  geom_edge_fan(aes(color = as.factor(difficulty), 
                    start_cap = label_rect(node1.name), 
                    end_cap = label_rect(node2.name),
                    label = trail), arrow = arrow(type = "closed", length = unit(3, 'mm')),
                angle_calc = 'along')   
  geom_node_text(aes(label = name))   
  ggtitle('An example')  
  scale_edge_colour_manual(values = c("red", "yellow", "green"))
p
  

Для трейлраннера я хочу выяснить, какими возможными путями он мог бы воспользоваться от начальной точки до конечной, и я хочу знать длину, сложность и так далее этого маршрута.
Например, если бегун начинает с D_2 и хочет добраться до B_1, он должен сначала пройти trail_1, чтобы достичь A_2_D_1, а затем может выбрать между trail_8 и trail_3, чтобы достичь B_1.
Следовательно, возможные пути:
D_2 -> A_2_D_1 -> B_1 (в форме vertix)
trail_1 -> trail_8 или trail_1 -> trail_3 (в форме ребра)

Меня интересует форма ребра, потому что необходимая мне информация хранится с ребрами. Я не смог найти готовую функцию для получения желаемых результатов, поэтому я создал свою собственную, но я думаю, что это довольно плохое решение, поэтому я был бы очень рад, если бы вы могли предложить некоторые улучшения или даже готовую функцию, если она есть.

Функция, подлежащая улучшению:

 # get all simple path (== desired results but in Vertix-form )
l = all_simple_paths(example_graph, from = "D_2", to = "B_1", mode = "out")
l

l2 = all_simple_paths(example_graph, from = "D_2", to = "A_1", mode = "out")
l2



my_get_edges = function(temp_vertix, temp_graph)
{
  # convert graph to data.frame
  temp_graph_df = igraph::as_data_frame(temp_graph, what="edges")

  # If the overall path consists of more than just 1 trail.
  temp_vertix = names(temp_vertix)
  if(length(temp_vertix) > 2)
  {
    # create matrix with each row beeing start-vertix, end-vertix for every trail of the whole path
    temp_vertix = c(temp_vertix[1], rep(temp_vertix[-c(1, length(temp_vertix))], each = 2), temp_vertix[length(temp_vertix)])
    temp_vertix = matrix(temp_vertix, ncol = 2, byrow = T)
  } else
  {
    temp_vertix = matrix(temp_vertix, ncol = 2, byrow = T)
  }

  # filter those rows from the data.frame that match the start and stop vertix
  temp_edges = apply(temp_vertix, 1, function(f) temp_graph_df %>% filter(from == f[1], to == f[2]))

  return(temp_edges)
}

lapply(l, my_get_edges, example_graph)

lapply(l2, my_get_edges, example_graph)
  

Заранее спасибо

Комментарии:

1. вы с этим разобрались?

2. Привет, Эмильбебри. Нет, я придерживался решения из сообщения, и поскольку тогда проект не был продолжен, я никогда не думал об улучшении функции впоследствии : (

3. все в порядке 🙂 то, что мне было нужно, было проще, чем то, что у вас есть, поэтому я разобрался с этим, используя shortest_paths() , который содержит элемент списка x $ vpath[[1]], который вы можете передать в аргумент path = E(). Это позволяет выбирать любые пути, которые вы хотите, и создавать атрибуты вдоль ребер. Потребовалось некоторое время на разработку, синтаксис igraph не очень удобен для новичков