রাস্তার ডেটাতে (একটি গ্রাফ) প্রতিবেশী স্থানগুলি (চক্রগুলি) সন্ধান করা হচ্ছে


10

আমি কোনও গ্রাফের বহুভুজ হিসাবে শহরগুলিতে আশেপাশের অঞ্চলগুলিকে স্বয়ংক্রিয়ভাবে সংজ্ঞায়িত করার উপায় খুঁজছি।

পাড়ার আমার সংজ্ঞাটির দুটি অংশ রয়েছে:

  1. একটি ব্লক : বেশ কয়েকটি রাস্তার মধ্যে ঘেরা একটি অঞ্চল, যেখানে রাস্তার সংখ্যা (প্রান্ত) এবং ছেদগুলি (নোড) সর্বনিম্ন তিনটি (একটি ত্রিভুজ)।
  2. একটি পাড়া : যে কোনও ব্লকের জন্য, সরাসরি সেই ব্লক সংলগ্ন সমস্ত ব্লক এবং নিজেই ব্লক।

উদাহরণ হিসাবে এই চিত্র দেখুন:

এখানে চিত্র বর্ণনা লিখুন

উদাহরণস্বরূপ, বি 4টি 7 টি নোড এবং 6 টি প্রান্তগুলি সংযুক্ত করে সংজ্ঞায়িত ব্লক। এখানে বেশিরভাগ উদাহরণ হিসাবে, অন্যান্য ব্লকগুলি 4 টি নোড এবং 4 টি প্রান্তগুলি সংযুক্ত করে সংজ্ঞায়িত করা হয়। এছাড়াও, আশপাশ এর খ 1 অন্তর্ভুক্ত B2 তে (এবং তদ্বিপরীত) যখন B2 তে অন্তর্ভুক্ত B3 থেকে

আমি ওএসএম থেকে রাস্তার ডেটা পেতে ওসমনক্স ব্যবহার করছি ।

  1. Osmnx এবং নেটওয়ার্কেক্স ব্যবহার করে, প্রতিটি ব্লককে সংজ্ঞায়িত নোড এবং প্রান্তগুলি খুঁজে পেতে আমি কীভাবে কোনও গ্রাফটি অতিক্রম করতে পারি?
  2. প্রতিটি ব্লকের জন্য, আমি কীভাবে সংলগ্ন ব্লকগুলি সন্ধান করতে পারি?

আমি কোডের একটি অংশের দিকে নিজেকে কাজ করছি যা একটি গ্রাফ এবং একজোড়া স্থানাঙ্ক (অক্ষাংশ, দ্রাঘিমাংশ) ইনপুট হিসাবে গ্রহণ করে, প্রাসঙ্গিক ব্লকটি চিহ্নিত করে এবং সেই ব্লকটির জন্য বহুভুজটি এবং উপরে বর্ণিত হিসাবে প্রতিবেশ ফিরিয়ে আনে।

মানচিত্র তৈরি করতে ব্যবহৃত কোডটি এখানে:

import osmnx as ox
import networkx as nx
import matplotlib.pyplot as plt

G = ox.graph_from_address('Nørrebrogade 20, Copenhagen Municipality',
                          network_type='all', 
                          distance=500)

এবং নোড এবং ডিগ্রীর বিভিন্ন সংখ্যার সাথে ক্রুগুলি অনুসন্ধান করার জন্য আমার প্রচেষ্টা।

def plot_cliques(graph, number_of_nodes, degree):
    ug = ox.save_load.get_undirected(graph)
    cliques = nx.find_cliques(ug)
    cliques_nodes = [clq for clq in cliques if len(clq) >= number_of_nodes]
    print("{} cliques with more than {} nodes.".format(len(cliques_nodes), number_of_nodes))
    nodes = set(n for clq in cliques_nodes for n in clq)
    h = ug.subgraph(nodes)
    deg = nx.degree(h)
    nodes_degree = [n for n in nodes if deg[n] >= degree]
    k = h.subgraph(nodes_degree)
    nx.draw(k, node_size=5)

থিয়োরি যা প্রাসঙ্গিক হতে পারে:

একটি অনির্দেশিত গ্রাফে সমস্ত চক্র গণনা করা


আকর্ষণীয় সমস্যা। আপনি এটিতে অ্যালগরিদম ট্যাগ যুক্ত করতে চাইতে পারেন। দেখে মনে হচ্ছে আপনি ব্লকগুলি বের করার পরে পাড়াগুলি আরও সহজ সমস্যা হবে। আশেপাশের অঞ্চলগুলির জন্য, আপনি যা খুঁজছেন তা কি একটি ভাগ করা প্রান্ত, সঠিক? এবং প্রতিটি ব্লকের প্রান্তগুলির একটি তালিকা থাকবে ... ব্লকগুলির জন্য, আমি মনে করি যে কোনও রাস্তায় একটি নোডে প্রতিটি রাস্তার বিকল্পের মূল দিকনির্দেশনা পাওয়া এবং আপনি একটি সার্কিট সম্পন্ন না করা বা পৌঁছানো অবধি "ডানদিকে ঘুরতে" (বা বাম দিকে) সাহায্য করা সহায়ক হবে think একটি ডেড এন্ড বা লুপ ফিরে আসুন এবং পুনরাবৃত্তভাবে ব্যাকট্র্যাক। দেখে মনে হচ্ছে কিছু আকর্ষণীয় কর্নার কেস থাকবে, যদিও।
জেফ এইচ

আমি মনে করি এই প্রশ্নটি আপনার সমস্যা নংয়ের সাথে খুব মিল। ১. আপনি যেহেতু লিঙ্কটিতে দেখতে পাচ্ছেন, আমি সমস্যার জন্য কিছুটা সময় কাজ করেছি এবং এটি একটি উদাসীন (এটি এনপি-হার্ড হিসাবে দেখা যাচ্ছে)। আমার জবাবের হিউরিস্টিক তবে এখনও আপনাকে যথেষ্ট ভাল ফলাফল দিতে পারে।
পল ব্রোডারসেন

আপনি যে কোনও সমাধান গ্রহণযোগ্য বলে মনে করেন তা সম্ভবত একটি হিউরিস্টিকও হতে পারে, প্রতিটি পদ্ধতির বৈধতা দেওয়ার জন্য একটি পরীক্ষার ডেটা সেটটি সংজ্ঞায়িত করা ভাল ধারণা হতে পারে। অর্থ, আপনার উদাহরণের গ্রাফের জন্য, মেশিনের পাঠ্যযোগ্য ফর্মের সমস্ত ব্লকের একটি টীকা দেওয়া ভাল হবে - একটি চিত্রের কয়েকটি উদাহরণ নয়।
পল ব্রোডারসেন

উত্তর:


3

গ্রাফটি ব্যবহার করে শহরের ব্লকগুলি সন্ধান করা আশ্চর্যের সাথে অ-তুচ্ছ। মূলত, এটি ক্ষুদ্রতম রিংগুলির সবচেয়ে ছোট সেট (এসএসএসআর) সন্ধানের পরিমাণ, যা এনপি-সম্পূর্ণ সমস্যা। এই সমস্যার একটি পর্যালোচনা (এবং সম্পর্কিত সমস্যাগুলি) এখানে পাওয়া যাবে । তাই, একটি অ্যালগরিদম এক বিবরণ এটি বিশ্লিষ্ট করা হল এখানে । আমি যতদূর বলতে পারি, networkx(বা সেই বিষয়টির জন্য অজগরটিতে) কোনও সম্পর্কিত বাস্তবায়ন নেই । আমি এই পদ্ধতির সংক্ষিপ্তভাবে চেষ্টা করেছি এবং তারপরে এটি ত্যাগ করেছি - আমার মস্তিষ্ক আজ সেই ধরণের কাজের জন্য স্ক্র্যাচ করতে প্রস্তুত নয়। বলা হচ্ছে, আমি যে কাউকে এই পৃষ্ঠার পরবর্তী তারিখে দেখতে এবং অ্যালগরিদমের পরীক্ষিত বাস্তবায়ন পোস্ট করতে পারে যা পাইথনে এসএসএসআর খুঁজে পায় তার জন্য আমি একটি পুরষ্কার প্রদান করব।

আমি পরিবর্তে গ্রাফটি পরিকল্পনাকারী হওয়ার নিশ্চয়তার বিষয়টি নিশ্চিত করে পৃথক পদ্ধতির অনুসরণ করেছি approach সংক্ষেপে, এটিকে গ্রাফের সমস্যা হিসাবে বিবেচনা করার পরিবর্তে আমরা এটিকে একটি চিত্র বিভাজন সমস্যা হিসাবে বিবেচনা করি। প্রথমত, আমরা চিত্রটিতে সমস্ত সংযুক্ত অঞ্চল খুঁজে পাই। তারপরে আমরা প্রতিটি অঞ্চলের চারপাশে কনট্যুর নির্ধারণ করি, চিত্রের সমন্বয়গুলিতে রূপরেখাগুলি দ্রাঘিমাংশ এবং অক্ষাংশে রূপান্তর করি।

নিম্নলিখিত আমদানি এবং ফাংশন সংজ্ঞা দেওয়া:

#!/usr/bin/env python
# coding: utf-8

"""
Find house blocks in osmnx graphs.
"""

import numpy as np
import osmnx as ox
import networkx as nx
import matplotlib.pyplot as plt

from matplotlib.path import Path
from matplotlib.patches import PathPatch
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from skimage.measure import label, find_contours, points_in_poly
from skimage.color import label2rgb

ox.config(log_console=True, use_cache=True)


def k_core(G, k):
    H = nx.Graph(G, as_view=True)
    H.remove_edges_from(nx.selfloop_edges(H))
    core_nodes = nx.k_core(H, k)
    H = H.subgraph(core_nodes)
    return G.subgraph(core_nodes)


def plot2img(fig):
    # remove margins
    fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)

    # convert to image
    # https://stackoverflow.com/a/35362787/2912349
    # https://stackoverflow.com/a/54334430/2912349
    canvas = FigureCanvas(fig)
    canvas.draw()
    img_as_string, (width, height) = canvas.print_to_buffer()
    as_rgba = np.fromstring(img_as_string, dtype='uint8').reshape((height, width, 4))
    return as_rgba[:,:,:3]

ডেটা লোড করুন। আমদানি ক্যাশে করুন, যদি বার বার এটি পরীক্ষা করা হয় - অন্যথায় আপনার অ্যাকাউন্ট নিষিদ্ধ হতে পারে। এখানে অভিজ্ঞতা থেকে কথা বলছি।

G = ox.graph_from_address('Nørrebrogade 20, Copenhagen Municipality',
                          network_type='all', distance=500)
G_projected = ox.project_graph(G)
ox.save_graphml(G_projected, filename='network.graphml')

# G = ox.load_graphml('network.graphml')

নুন এবং প্রান্তগুলি ছাঁটাই যা কোনও চক্রের অংশ হতে পারে না। এই পদক্ষেপটি কঠোরভাবে প্রয়োজনীয় নয় তবে ফলস্বরূপ উত্তমরূপে আসে।

H = k_core(G, 2)
fig1, ax1 = ox.plot_graph(H, node_size=0, edge_color='k', edge_linewidth=1)

ছাঁটাই গ্রাফ

প্লটটিকে চিত্রে রূপান্তর করুন এবং সংযুক্ত অঞ্চলগুলি সন্ধান করুন:

img = plot2img(fig1)
label_image = label(img > 128)
image_label_overlay = label2rgb(label_image[:,:,0], image=img[:,:,0])
fig, ax = plt.subplots(1,1)
ax.imshow(image_label_overlay)

অঞ্চল লেবেলের প্লট

প্রতিটি লেবেলযুক্ত অঞ্চলের জন্য, কনট্যুর সন্ধান করুন এবং কনট্যুর পিক্সেল স্থানাঙ্কগুলিকে ডেটা স্থানাঙ্কে ফিরে রূপান্তর করুন।

# using a large region here as an example;
# however we could also loop over all unique labels, i.e.
# for ii in np.unique(labels.ravel()):
ii = np.argsort(np.bincount(label_image.ravel()))[-5]

mask = (label_image[:,:,0] == ii)
contours = find_contours(mask.astype(np.float), 0.5)

# Select the largest contiguous contour
contour = sorted(contours, key=lambda x: len(x))[-1]

# display the image and plot the contour;
# this allows us to transform the contour coordinates back to the original data cordinates
fig2, ax2 = plt.subplots()
ax2.imshow(mask, interpolation='nearest', cmap='gray')
ax2.autoscale(enable=False)
ax2.step(contour.T[1], contour.T[0], linewidth=2, c='r')
plt.close(fig2)

# first column indexes rows in images, second column indexes columns;
# therefor we need to swap contour array to get xy values
contour = np.fliplr(contour)

pixel_to_data = ax2.transData + ax2.transAxes.inverted() + ax1.transAxes + ax1.transData.inverted()
transformed_contour = pixel_to_data.transform(contour)
transformed_contour_path = Path(transformed_contour, closed=True)
patch = PathPatch(transformed_contour_path, facecolor='red')
ax1.add_patch(patch)

কনট্যুর প্লট ছাঁটাই গ্রাফে ওভারলেড

কনট্যুরের ভিতরে (বা চালু) পড়ার মূল গ্রাফের সমস্ত পয়েন্ট নির্ধারণ করুন।

x = G.nodes.data('x')
y = G.nodes.data('y')
xy = np.array([(x[node], y[node]) for node in G.nodes])
eps = (xy.max(axis=0) - xy.min(axis=0)).mean() / 100
is_inside = transformed_contour_path.contains_points(xy, radius=-eps)
nodes_inside_block = [node for node, flag in zip(G.nodes, is_inside) if flag]

node_size = [50 if node in nodes_inside_block else 0 for node in G.nodes]
node_color = ['r' if node in nodes_inside_block else 'k' for node in G.nodes]
fig3, ax3 = ox.plot_graph(G, node_color=node_color, node_size=node_size)

লাল ব্লকযুক্ত নোডের সাথে নেটওয়ার্কের প্লট

দুটি ব্লক প্রতিবেশী কিনা তা নির্ধারণ করা খুব সহজ। তারা নোড ভাগ করে নিন কিনা তা পরীক্ষা করুন:

if set(nodes_inside_block_1) & set(nodes_inside_block_2): # empty set evaluates to False
    print("Blocks are neighbors.")

2

আমি পুরোপুরি নিশ্চিত নই যে cycle_basisএটি আপনার সন্ধানের আশেপাশের স্থানগুলি দেবে, তবে যদি তা হয় তবে এ থেকে প্রতিবেশী গ্রাফ পাওয়া সহজ জিনিস:

import osmnx as ox
import networkx as nx
import matplotlib.pyplot as plt

G = ox.graph_from_address('Nørrebrogade 20, Copenhagen Municipality',
                          network_type='all',
                          distance=500)

H = nx.Graph(G) # make a simple undirected graph from G

cycles = nx.cycles.cycle_basis(H) # I think a cycle basis should get all the neighborhoods, except
                                  # we'll need to filter the cycles that are too small.
cycles = [set(cycle) for cycle in cycles if len(cycle) > 2] # Turn the lists into sets for next loop.

# We can create a new graph where the nodes are neighborhoods and two neighborhoods are connected if
# they are adjacent:

I = nx.Graph()
for i, n in enumerate(cycles):
    for j, m in enumerate(cycles[i + 1:], start=i + 1):
        if not n.isdisjoint(m):
            I.add_edge(i, j)

হাই নোনা ডাই মধ্যে চিপ লাগাচ্ছে জন্য তাই এবং ধন্যবাদ স্বাগত জানাই। যখন করছেন nx.Graph(G)আমি তথ্য অনেক (directedness এবং multigraph প্রকার) হারাচ্ছি তাই আমি একটি কঠিন সময় আপনার উত্তর যাচাই করছি, নাকিসুরে কথা যেমন আমি নতুন গ্রাফ কহা বলে মনে হচ্ছে Iথেকে আমার মূল গ্রাফ G
tmo

আসল গ্রাফ থেকে জ্যামিতিক তথ্য সংরক্ষণ করা কিছুটা কাজ হবে। আমি শীঘ্রই এই চেষ্টা করব।
লবণের ডাই

@ টেমো কেবল পাশ দিয়ে যাচ্ছেন: আপনি মাল্টিডিগ্রাফ ক্লাসটি ব্যবহার করতে সক্ষম হবেন (এটি গ্রাফকে প্রসারিত করে)
থো রুবেনাচ

1

আমার কোনও কোড নেই তবে আমি অনুমান করি যে একবার আমি ফুটপাতে আছি, যদি আমি প্রতিটি কোণে ডানদিকে ঘুরতে থাকি তবে আমি আমার ব্লকের প্রান্তগুলি দিয়ে ঘুরে বেড়াব। আমি গ্রন্থাগারগুলি জানি না তাই আমি এখানেই আলগো আলাপ করব।

  • আপনার দিক থেকে, আপনি কোনও রাস্তায় না পৌঁছানো পর্যন্ত উত্তর দিকে যান
  • আপনি যতটা ডান দিকে ঘুরুন এবং রাস্তায় হাঁটুন
  • পরবর্তী কোণে, সমস্ত স্টিটগুলি সন্ধান করুন, একটি বেছে নিন যা আপনার রাস্তাকে ডান থেকে গণনা করে সবচেয়ে ছোট কোণ তৈরি করে।
  • এই রাস্তায় হাঁটা।
  • ডানদিকে ঘুরুন, ইত্যাদি

গোলকধাঁধা থেকে বেরিয়ে আসার জন্য এটি আসলে একটি অ্যালগরিদম: আপনার ডান হাতটি দেয়ালে রাখুন এবং হাঁটুন। গোলকধাঁধার লুপগুলির ক্ষেত্রে এটি কাজ করে না, আপনি কেবল চারপাশে লুপ করবেন। তবে এটি আপনার সমস্যার সমাধান দেয়।


এটি আমার চেয়ে অনেক ভাল ধারণা। আমি আপনার অন্তর্দৃষ্টি বাস্তবায়নের সাথে একটি উত্তর যুক্ত করব।
পল ব্রোডারসেন

0

এটি হাশেমি ইমাদের ধারণার বাস্তবায়ন । এটি যতক্ষণ না প্রারম্ভিক অবস্থানটি বেছে নেওয়া হয় ততক্ষণ তা কার্যকরভাবে কাজ করে যে কোনও শক্ত বৃত্তে ঘড়ির কাঁটার বিপরীতে পদক্ষেপ নেওয়ার একটি উপায় বিদ্যমান। কিছু প্রান্তের জন্য, বিশেষত মানচিত্রের বাইরের চারপাশে এটি সম্ভব নয়। কীভাবে ভাল শুরু করার অবস্থানগুলি নির্বাচন করতে হয়, বা কীভাবে সমাধানগুলি ফিল্টার করতে হয় সে সম্পর্কে আমার ধারণা নেই - তবে অন্য কারও একটি হতে পারে।

কাজের উদাহরণ (প্রান্ত দিয়ে শুরু (1204573687, 4555480822)):

এখানে চিত্র বর্ণনা লিখুন

উদাহরণ, যেখানে এই পদ্ধতির কাজ হয় না (প্রান্ত দিয়ে শুরু (1286684278, 5818325197)):

এখানে চিত্র বর্ণনা লিখুন

কোড

#!/usr/bin/env python
# coding: utf-8

"""
Find house blocks in osmnx graphs.
"""

import numpy as np
import networkx as nx
import osmnx as ox

import matplotlib.pyplot as plt; plt.ion()

from matplotlib.path import Path
from matplotlib.patches import PathPatch


ox.config(log_console=True, use_cache=True)


def k_core(G, k):
    H = nx.Graph(G, as_view=True)
    H.remove_edges_from(nx.selfloop_edges(H))
    core_nodes = nx.k_core(H, k)
    H = H.subgraph(core_nodes)
    return G.subgraph(core_nodes)


def get_vector(G, n1, n2):
    dx = np.diff([G.nodes.data()[n]['x'] for n in (n1, n2)])
    dy = np.diff([G.nodes.data()[n]['y'] for n in (n1, n2)])
    return np.array([dx, dy])


def angle_between(v1, v2):
    # https://stackoverflow.com/a/31735642/2912349
    ang1 = np.arctan2(*v1[::-1])
    ang2 = np.arctan2(*v2[::-1])
    return (ang1 - ang2) % (2 * np.pi)


def step_counterclockwise(G, edge, path):
    start, stop = edge
    v1 = get_vector(G, stop, start)
    neighbors = set(G.neighbors(stop))
    candidates = list(set(neighbors) - set([start]))
    if not candidates:
        raise Exception("Ran into a dead end!")
    else:
        angles = np.zeros_like(candidates, dtype=float)
        for ii, neighbor in enumerate(candidates):
            v2 = get_vector(G, stop, neighbor)
            angles[ii] = angle_between(v1, v2)
        next_node = candidates[np.argmin(angles)]
        if next_node in path:
            # next_node might not be the same as the first node in path;
            # therefor, we backtrack until we end back at next_node
            closed_path = [next_node]
            for node in path[::-1]:
                closed_path.append(node)
                if node == next_node:
                    break
            return closed_path[::-1] # reverse to have counterclockwise path
        else:
            path.append(next_node)
            return step_counterclockwise(G, (stop, next_node), path)


def get_city_block_patch(G, boundary_nodes, *args, **kwargs):
    xy = []
    for node in boundary_nodes:
        x = G.nodes.data()[node]['x']
        y = G.nodes.data()[node]['y']
        xy.append((x, y))
    path = Path(xy, closed=True)
    return PathPatch(path, *args, **kwargs)


if __name__ == '__main__':

    # --------------------------------------------------------------------------------
    # load data

    # # DO CACHE RESULTS -- otherwise you can get banned for repeatedly querying the same address
    # G = ox.graph_from_address('Nørrebrogade 20, Copenhagen Municipality',
    #                           network_type='all', distance=500)
    # G_projected = ox.project_graph(G)
    # ox.save_graphml(G_projected, filename='network.graphml')

    G = ox.load_graphml('network.graphml')

    # --------------------------------------------------------------------------------
    # prune nodes and edges that should/can not be part of a cycle;
    # this also reduces the chance of running into a dead end when stepping counterclockwise

    H = k_core(G, 2)

    # --------------------------------------------------------------------------------
    # pick an edge and step counterclockwise until you complete a circle

    # random edge
    total_edges = len(H.edges)
    idx = np.random.choice(total_edges)
    start, stop, _ = list(H.edges)[idx]

    # good edge
    # start, stop = 1204573687, 4555480822

    # bad edge
    # start, stop = 1286684278, 5818325197

    steps = step_counterclockwise(H, (start, stop), [start, stop])

    # --------------------------------------------------------------------------------
    # plot

    patch = get_city_block_patch(G, steps, facecolor='red', edgecolor='red', zorder=-1)

    node_size = [100 if node in steps else 20 for node in G.nodes]
    node_color = ['crimson' if node in steps else 'black' for node in G.nodes]
    fig1, ax1 = ox.plot_graph(G, node_size=node_size, node_color=node_color, edge_color='k', edge_linewidth=1)
    ax1.add_patch(patch)
    fig1.savefig('city_block.png')
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.