2021-08-24 15:49:46 +01:00
|
|
|
from collections import defaultdict
|
|
|
|
|
|
2021-08-24 15:11:00 +01:00
|
|
|
from app.broadcast_areas.models import CustomBroadcastArea
|
|
|
|
|
|
|
|
|
|
|
2021-08-24 15:01:53 +01:00
|
|
|
def aggregate_areas(areas):
|
2021-08-24 15:11:00 +01:00
|
|
|
areas = _convert_custom_areas_to_wards(areas)
|
2021-08-24 15:01:53 +01:00
|
|
|
areas = _aggregate_wards_by_local_authority(areas)
|
2021-08-24 15:49:46 +01:00
|
|
|
areas = _aggregate_lower_tier_authorities(areas)
|
2021-08-27 14:58:45 +01:00
|
|
|
return sorted(areas)
|
2021-08-24 15:01:53 +01:00
|
|
|
|
|
|
|
|
|
2021-08-24 15:11:00 +01:00
|
|
|
def _convert_custom_areas_to_wards(areas):
|
|
|
|
|
results = set()
|
|
|
|
|
|
|
|
|
|
for area in areas:
|
|
|
|
|
if type(area) == CustomBroadcastArea:
|
|
|
|
|
results |= set(area.overlapping_electoral_wards)
|
|
|
|
|
else:
|
|
|
|
|
results |= {area}
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
2021-08-24 15:01:53 +01:00
|
|
|
def _aggregate_wards_by_local_authority(areas):
|
|
|
|
|
return {
|
2021-08-24 16:06:46 +01:00
|
|
|
area.parent if area.is_electoral_ward
|
2021-08-24 15:01:53 +01:00
|
|
|
else area for area in areas
|
|
|
|
|
}
|
2021-08-24 15:49:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def _aggregate_lower_tier_authorities(areas):
|
|
|
|
|
results = set()
|
|
|
|
|
clusters = _cluster_lower_tier_authorities(areas)
|
|
|
|
|
|
|
|
|
|
for cluster in clusters:
|
2021-08-27 14:41:00 +01:00
|
|
|
# always show a single area cluster as itself (aggregation isn't helpful)
|
2021-08-24 15:49:46 +01:00
|
|
|
if len(cluster) == 1:
|
|
|
|
|
results |= set(cluster)
|
2021-08-27 14:41:00 +01:00
|
|
|
# aggregate a single cluster with lots of areas (too complex to show in full)
|
2021-08-24 15:49:46 +01:00
|
|
|
elif len(cluster) > 3:
|
|
|
|
|
results |= {cluster[0].parent}
|
2021-08-27 14:41:00 +01:00
|
|
|
# if cluster is 2 or 3 areas, and there are more than 1 cluster, aggregate the cluster
|
2021-08-24 15:49:46 +01:00
|
|
|
elif len(clusters) > 1:
|
|
|
|
|
area = cluster[0]
|
|
|
|
|
results |= {area.parent or area}
|
2021-08-27 14:41:00 +01:00
|
|
|
# else keep single 2-3 areas cluster in full (easy enough to understand)
|
2021-08-24 15:49:46 +01:00
|
|
|
else:
|
|
|
|
|
results |= set(cluster)
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _cluster_lower_tier_authorities(areas):
|
|
|
|
|
result = defaultdict(lambda: [])
|
|
|
|
|
|
|
|
|
|
for area in areas:
|
|
|
|
|
# group lower tier authorities by "county"
|
2021-08-24 16:06:46 +01:00
|
|
|
if area.is_lower_tier_local_authority:
|
2021-08-24 15:49:46 +01:00
|
|
|
result[area.parent] += [area]
|
|
|
|
|
# leave countries, unitary authorities as-is
|
|
|
|
|
else:
|
|
|
|
|
result[area] = [area]
|
|
|
|
|
|
|
|
|
|
return result.values()
|