Как последовательно упорядочить геометрию LineString в возвращаемых ребрах OSMNX GeoDataFrame

У меня есть кадр геоданных с краями, возвращаемыми из OSMNX:

import osmnx as ox

# Getting graph for specific road
cf = '["highway"!~"motorway"]["ref"~"TF-563"]'
G = ox.graph_from_place('Tenerife, Spain', network_type='walk', simplify=False, custom_filter=cf)

# Adding length weights
G = ox.distance.add_edge_lengths(G)

# Getting nodes and edges of graph
nodes, edges = ox.convert.graph_to_gdfs(G, nodes=True)

Это дает столбец геометрии, где каждая строка содержит Linestring. Я хочу, чтобы у меня была одна длинная строка, упорядоченная правильно, чтобы я мог построить график, похожий на «edges.plot()», где все строки строятся непрерывно.

Для создания многострочной строки я использую следующее:

multi_line = geometry.MultiLineString(list(edges['geometry']))

Но когда я рисую это, все выглядит беспорядочно, и я предполагаю, что это связано с тем, что порядок строк в edges фрейме геоданных не упорядочен, и поэтому строки соединяются случайным образом.

    m = folium.Map(location=[28.105040, -16.610664], zoom_start=15)
    
    # Extract coordinates from MultiLineString
    def get_coordinates(multi_line):
        all_coords = []
        for line in multi_line.geoms:
            all_coords.extend(list(line.coords))
        return all_coords
    
    # Get the coordinates
    coordinates = get_coordinates(multi_line)
    
    # Add the coordinates as PolyLines 
    folium.PolyLine([(coord[1], coord[0]) for coord in coordinates], color = "blue").add_to(m)
    m

Кто-нибудь знает, есть ли способ упорядочить геометрию ребер, возвращаемую OSMNX, или есть другая причина, по которой я вижу эту проблему?

Для этого вопроса было бы полезно использовать MRE, (NameError: name 'G' is not defined).

Timeless 02.07.2024 20:02

@Timeless Вопрос обновлен.

Ellio 02.07.2024 20:56

Спасибо за поправки. Вы не показываете, как вы «строите сюжет». Я не могу размножаться с помощью фолиума (см. здесь)

Timeless 03.07.2024 01:09

@Timeless снова обновлен с кодом для построения графика.

Ellio 04.07.2024 20:28
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вам действительно не нужна одна единственная PolyLine , одним из вариантов может быть переиндексация краев:

extremities = [n for n, d in G.in_degree() if d == 1] # must be exactly 2 !
route = [(u,v) for u,v,*_ in list(nx.all_simple_edge_paths(G, *extremities))[0]]

# this requires geopandas>=1.0.0
single_ls = (
    edges.droplevel(2).reindex(route)
    .dissolve().geometry.line_merge().squeeze()
)
# otherwise, use from shapely.ops import linemerge
# single_ls = (
#     linemerge(
#         edges.droplevel(2).reindex(route)
#         .dissolve().geometry.squeeze()
#     )
# )

m = folium.Map(location=[28.105040, -16.610664], zoom_start=15)

folium.PolyLine(
    [(coord[1], coord[0]) for coord in single_ls.coords],
    color = "blue",
).add_to(m)

В противном случае вы можете просто исследовать оба узла/ребра:

m = edges.explore(
    style_kwds=dict(weight=5, color = "black"),
    location=[28.11114, -16.61616],
    zoom_start=16,
)
m = nodes.explore(
    m=m,
    marker_type = "circle_marker",
    marker_kwds=dict(radius=5),
    style_kwds=dict(fillColor = "cyan", color = "black"),
)

Вывод (m):

Это здорово, именно то, чего я пытался достичь! Спасибо!

Ellio 05.07.2024 10:29

Можете ли вы также предложить, как этот код можно повторно использовать, например, при работе с более крупными дорожными сетями; cf = '["шоссе"~"автомагистраль"]', поскольку это делает конечности > 2.

Ellio 05.07.2024 10:49

Другие вопросы по теме