如何用Overpy按admin_level 6统计酒吧与酒馆数量并生成对应列表
Hey there! I see you're trying to get a list of (département ref, bar/pub count) pairs using Overpy, but your current query is returning all individual nodes/ways without grouping. Let's fix that with two straightforward approaches—one that leverages Overpass's built-in counting (most efficient) and another if you need to work with raw elements.
Approach 1: Let Overpass Do the Counting (Recommended)
Instead of fetching every single bar/pub element and grouping them yourself, modify your Overpass query to calculate the counts before sending results to Overpy. This is way more efficient, especially since you don't need the raw data for each venue.
Here's the updated code:
import overpy api = overpy.Overpass() # Revised query to return aggregated counts instead of raw elements query = """ [out:json]; // Target all French départements (admin_level 6) area[admin_level=6]["ISO3166-2"~"^FR-(?:[0-9]|[1-8][0-9]|9[0-5]|2[A-B])"]; foreach->.dpt( // Find all bars and pubs in the current département ( way(area.dpt)[amenity=pub]; way(area.dpt)[amenity=bar]; node(area.dpt)[amenity=pub]; node(area.dpt)[amenity=bar]; ); // Create a count entry with the département's ref and total venue count make count id = dpt.set(t["ref"]), total = count(ways) + count(nodes); out; ); """ # Run the query and parse results result = api.query(query) # Build your desired list of (département ref, count) pairs departement_bar_counts = [] for element in result.elements: dpt_ref = element.tags.get("id") total_venues = int(element.tags.get("total", 0)) departement_bar_counts.append((dpt_ref, total_venues)) # Example: Print the first 5 entries to verify for ref, count in departement_bar_counts[:5]: print(f"Département {ref}: {count} bars/pubs")
Why this works:
- We use
make countin Overpass to generate a summary element for each département, containing its reference code (id) and total bar/pub count (total). - Overpy can parse these summary elements from the JSON output, and we extract the values from their
tagsattribute to build our final list. - The regex is optimized with a non-capturing group (
(?:...)) to avoid unnecessary grouping, making it cleaner.
Approach 2: Group Raw Elements Manually (If Needed)
If you do need to keep the raw bar/pub data for additional processing, you can fetch all elements first, then map each to its département. This is less efficient but useful for edge cases:
import overpy from collections import defaultdict api = overpy.Overpass() # First, fetch all départements and map their area IDs to refs dpt_query = """ [out:json]; area[admin_level=6]["ISO3166-2"~"^FR-(?:[0-9]|[1-8][0-9]|9[0-5]|2[A-B])"]; out tags; """ dpt_result = api.query(dpt_query) area_id_to_ref = {elem.id: elem.tags.get("ref") for elem in dpt_result.elements} # Now fetch all bars/pubs bar_query = """ [out:json]; area[admin_level=6]["ISO3166-2"~"^FR-(?:[0-9]|[1-8][0-9]|9[0-5]|2[A-B])"]->.dpts; ( way(area.dpts)[amenity=pub]; way(area.dpts)[amenity=bar]; node(area.dpts)[amenity=pub]; node(area.dpts)[amenity=bar]; ); out body; """ bar_result = api.query(bar_query) # Count venues per département counts = defaultdict(int) # Check nodes for node in bar_result.nodes: for area_id in node.area_ids: if area_id in area_id_to_ref: counts[area_id_to_ref[area_id]] += 1 break # Stop after matching the first admin_level 6 area # Check ways for way in bar_result.ways: for area_id in way.area_ids: if area_id in area_id_to_ref: counts[area_id_to_ref[area_id]] += 1 break # Convert to your desired list format departement_bar_counts = list(counts.items())
Notes on this approach:
- We first map each département's area ID to its reference code, since nodes/ways only store area IDs.
- For each bar/pub element, we check which admin_level 6 area it belongs to and increment the count for that département.
- This is slower than Approach 1 because you're transferring and processing all 3895 elements, but it's useful if you need to work with individual venue data.
内容的提问来源于stack exchange,提问作者gee

