Znasz jakąś sensowną z dobrą dokumentacją?
Chciałbym uzyskać podział terytorialny. Pokażę Ci moją bazę danych:
-
administrative_levels
-
administrative_divisions
(nie mogę wstawić drugiego multimedialnego obrazka ponieważ jestem nowym użytkownikiem)
Chciałbym aby w administrative_divisions był podział:
województwo → powiat → gmina → miejscowość itd.
A to mój kod w pythonie który tworzy mi podział terytorialny ale bez granic tych terytorium.
import osmium
import json
import os
from multiprocessing import Pool, Manager, current_process
import logging
import time
# Ustawienia logowania
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
class OsmInitialBuilder(osmium.SimpleHandler):
def __init__(self, target_relation_id):
super(OsmInitialBuilder, self).__init__()
self.target_relation_id = target_relation_id
self.relations = {}
self.parent_map = {}
self.relation_ids_to_process = set([target_relation_id])
def relation(self, r):
if r.id == self.target_relation_id or r.id in self.relation_ids_to_process:
if 'boundary' in r.tags and r.tags['boundary'] == 'administrative':
admin_level = r.tags.get('admin_level', None)
self.relations[r.id] = {
'relation_id': r.id,
'admin_level': admin_level,
'name': r.tags.get('name', '-'),
'tags': {tag.k: tag.v for tag in r.tags},
'members': [{'type': member.type, 'ref': member.ref, 'role': member.role} for member in r.members],
'postcode': r.tags.get('addr:postcode', 'No postcode')
}
logging.info(f"{current_process().name} - Processed relation ID: {r.id}, Name: {r.tags.get('name', '-')}, Admin level: {admin_level}")
if admin_level == '4':
self.relation_ids_to_process.remove(r.id)
# Track parent relations
for member in r.members:
if member.type == 'r':
self.parent_map[member.ref] = r.id
if member.ref not in self.relations:
self.relation_ids_to_process.add(member.ref)
def parse_initial_relations(target_relation_id, filename):
logging.info(f"{current_process().name} - Starting parse_initial_relations")
handler = OsmInitialBuilder(target_relation_id)
handler.apply_file(filename)
logging.info(f"{current_process().name} - Finished parse_initial_relations")
return handler.relations, handler.parent_map
class OsmHierarchyBuilder(osmium.SimpleHandler):
def __init__(self, initial_relations, initial_parent_map, relations, parent_map, processed_relations, relation_ids_to_process):
super(OsmHierarchyBuilder, self).__init__()
self.initial_relations = initial_relations
self.initial_parent_map = initial_parent_map
self.relations = relations
self.parent_map = parent_map
self.processed_relations = processed_relations
self.relation_ids_to_process = relation_ids_to_process
self.start_time = time.time()
self.total_relations = len(relation_ids_to_process)
def relation(self, r):
if r.id in self.initial_relations or r.id in self.relation_ids_to_process:
if 'boundary' in r.tags and r.tags['boundary'] == 'administrative':
admin_level = r.tags.get('admin_level', None)
self.relations[r.id] = {
'relation_id': r.id,
'admin_level': admin_level,
'name': r.tags.get('name', '-'),
'tags': {tag.k: tag.v for tag in r.tags},
'members': [{'type': member.type, 'ref': member.ref, 'role': member.role} for member in r.members],
'postcode': r.tags.get('addr:postcode', 'No postcode')
}
if r.id not in self.processed_relations:
self.processed_relations.append(r.id)
logging.info(f"{current_process().name} - Processed relation ID: {r.id}, Name: {r.tags.get('name', '-')}, Admin level: {admin_level}")
# Calculate and log estimated time remaining
processed_count = len(self.processed_relations)
elapsed_time = time.time() - self.start_time
estimated_total_time = (elapsed_time / processed_count) * self.total_relations
estimated_remaining_time = estimated_total_time - elapsed_time
logging.info(f"{current_process().name} - Progress: {processed_count}/{self.total_relations}, Estimated remaining time: {estimated_remaining_time:.2f} seconds")
# Track parent relations
for member in r.members:
if member.type == 'r':
self.parent_map[member.ref] = r.id
if member.ref not in self.processed_relations and member.ref not in self.relation_ids_to_process:
self.relation_ids_to_process.append(member.ref)
def parse_relations(initial_relations, initial_parent_map, filename, relations, parent_map, processed_relations, relation_ids_to_process):
logging.info(f"{current_process().name} - Starting parse_relations")
handler = OsmHierarchyBuilder(initial_relations, initial_parent_map, relations, parent_map, processed_relations, relation_ids_to_process)
handler.apply_file(filename)
logging.info(f"{current_process().name} - Finished parse_relations")
return list(handler.relations.items()), list(handler.parent_map.items()), list(handler.processed_relations), list(handler.relation_ids_to_process)
def build_hierarchy(relations, parent_map):
hierarchy = {}
for relation_id, details in relations.items():
hierarchy_list = []
current_id = relation_id
while current_id in parent_map:
parent_id = parent_map[current_id]
if parent_id not in relations:
break
parent = relations[parent_id]
hierarchy_list.append({
'admin_level': parent['admin_level'],
'name': parent['name'],
'relation_id': parent['relation_id'],
'postcode': parent['postcode']
})
current_id = parent_id
hierarchy[relation_id] = list(reversed(hierarchy_list))
return hierarchy
def save_to_file(data, filename):
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
logging.info(f"Data saved to {filename}")
def load_from_file(filename):
with open(filename, 'r', encoding='utf-8') as f:
data = json.load(f)
logging.info(f"Data loaded from {filename}")
return data
def main():
# Target relation ID for Poland
target_relation_id = 49715
relations_file = 'data/PL/multiprocessing/relations.json'
hierarchy_file = 'data/PL/multiprocessing/hierarchy.json'
filename = 'data/PL/OSM.osm.pbf'
# Check if the relations file already exists
if os.path.exists(relations_file) and os.path.exists(hierarchy_file):
# Load relations and hierarchy from files
relations = load_from_file(relations_file)
hierarchy = load_from_file(hierarchy_file)
# Rebuild the parent map
parent_map = {}
for relation_id, details in relations.items():
for member in details['members']:
if member['type'] == 'r':
parent_map[member['ref']] = relation_id
else:
# Parse initial relations to get admin_level 4
initial_relations, initial_parent_map = parse_initial_relations(target_relation_id, filename)
# Filter initial relations to get only those with admin_level 4
admin_level_4_relations = {r_id: rel for r_id, rel in initial_relations.items() if rel['admin_level'] == '4'}
# Create a manager to handle shared data between processes
with Manager() as manager:
relations = manager.dict()
parent_map = manager.dict()
processed_relations = manager.list()
relation_ids_to_process = manager.list(admin_level_4_relations.keys())
# Add initial relations to shared data
for r_id, rel in initial_relations.items():
relations[r_id] = rel
for p_id, parent in initial_parent_map.items():
parent_map[p_id] = parent
# Create a pool of workers
with Pool(processes=len(admin_level_4_relations)) as pool:
results = []
for admin_relation_id in admin_level_4_relations.keys():
logging.info(f"Main process - Dispatching relation ID {admin_relation_id} for processing")
result = pool.apply_async(parse_relations, (initial_relations, initial_parent_map, filename, relations, parent_map, processed_relations, relation_ids_to_process))
results.append(result)
# Collect results
for result in results:
rel_items, par_items, proc_list, ids_list = result.get()
relations.update(rel_items)
parent_map.update(par_items)
processed_relations.extend(proc_list)
relation_ids_to_process.extend(ids_list)
# Convert manager.dict to normal dict for saving
relations = dict(relations)
parent_map = dict(parent_map)
# Build the hierarchy
hierarchy = build_hierarchy(relations, parent_map)
# Save relations and hierarchy to files
save_to_file(relations, relations_file)
save_to_file(hierarchy, hierarchy_file)
# Example usage: Get hierarchy for a specific relation
relation_id = 3275052 # Example: Relation ID for Prawda
hierarchy_list = hierarchy.get(relation_id, [])
print(f"Hierarchy for relation ID {relation_id}:")
for level in hierarchy_list:
print(f" Admin level: {level['admin_level']}, Name: {level['name']}, Relation ID: {level['relation_id']}, Postcode: {level['postcode']}")
# Example usage: Get hierarchy for another specific relation
relation_id = 454648 # Example: Relation ID for Pieńsk
hierarchy_list = hierarchy.get(relation_id, [])
print(f"\nHierarchy for relation ID {relation_id}:")
for level in hierarchy_list:
print(f" Admin level: {level['admin_level']}, Name: {level['name']}, Relation ID: {level['relation_id']}, Postcode: {level['postcode']}")
if __name__ == "__main__":
main()
Uzyskuję 2 pliki:
- hierarchy.json
{
"6252503": [
{
"admin_level": "2",
"name": "Polska",
"relation_id": 49715,
"postcode": "No postcode"
},
{
"admin_level": "4",
"name": "województwo dolnośląskie",
"relation_id": 224457,
"postcode": "No postcode"
},
{
"admin_level": "6",
"name": "powiat oleśnicki",
"relation_id": 451525,
"postcode": "No postcode"
},
{
"admin_level": "7",
"name": "gmina Syców",
"relation_id": 2942236,
"postcode": "No postcode"
}
],
"6252504": [
{
"admin_level": "2",
"name": "Polska",
"relation_id": 49715,
"postcode": "No postcode"
},
{
"admin_level": "4",
"name": "województwo dolnośląskie",
"relation_id": 224457,
"postcode": "No postcode"
},
{
"admin_level": "6",
"name": "powiat oleśnicki",
"relation_id": 451525,
"postcode": "No postcode"
},
{
"admin_level": "7",
"name": "gmina Syców",
"relation_id": 2942236,
"postcode": "No postcode"
}
]
}
- relations.json
{
"4454375": {
"relation_id": 4454375,
"admin_level": "8",
"name": "Nieświń",
"tags": {
"admin_level": "8",
"boundary": "administrative",
"name": "Nieświń",
"type": "boundary",
"wikidata": "Q11791957",
"wikipedia": "pl:Nieświń"
},
"members": [
{
"type": "n",
"ref": 2422705569,
"role": "admin_centre"
},
{
"type": "w",
"ref": 320168064,
"role": "outer"
},
{
"type": "w",
"ref": 320120443,
"role": "outer"
},
{
"type": "w",
"ref": 320119364,
"role": "outer"
},
{
"type": "w",
"ref": 320119368,
"role": "outer"
},
{
"type": "w",
"ref": 319979168,
"role": "outer"
},
{
"type": "w",
"ref": 319979166,
"role": "outer"
},
{
"type": "w",
"ref": 319979167,
"role": "outer"
},
{
"type": "w",
"ref": 319980853,
"role": "outer"
},
{
"type": "w",
"ref": 320168063,
"role": "outer"
}
],
"postcode": "No postcode"
},
"4454496": {
"relation_id": 4454496,
"admin_level": "8",
"name": "Czerwony Most",
"tags": {
"admin_level": "8",
"boundary": "administrative",
"name": "Czerwony Most",
"type": "boundary",
"wikidata": "Q5202092",
"wikipedia": "pl:Czerwony Most"
},
"members": [
{
"type": "n",
"ref": 6166867262,
"role": "admin_centre"
},
{
"type": "w",
"ref": 320172666,
"role": "outer"
},
{
"type": "w",
"ref": 320172678,
"role": "outer"
},
{
"type": "w",
"ref": 218046826,
"role": "outer"
}
],
"postcode": "No postcode"
}
}
Napisałem drugi kod w których chciałem uzyskać takie dane:
{
“12345”: [
[30.0, 10.0],
[40.0, 40.0],
[20.0, 40.0],
[10.0, 20.0]
],
“67890”: [
[35.0, 15.0],
[45.0, 45.0],
[25.0, 45.0],
[15.0, 25.0]
]
}
Abym mógł pobrać z tych wyżej danych i wstawić w “members”: [ z relations.json.
Trochę masło maślane ale mam nadzieję, że zrozumiałeś o co mi chodzi