def attachOrphanRedistrictingGroupsToClosestNeighbor(neighborsToAttach): tqdm.write('\n') tqdm.write( '*** Attaching Orphan Redistricting Groups To Closest Neighbor ***') contiguousRegions = findContiguousGroupsOfGraphObjects(neighborsToAttach) while len(contiguousRegions) > 1: tqdm.write(' *** Found {0} Isolated Regions ***'.format( len(contiguousRegions))) isolatedRegion = contiguousRegions[0] closestRegion = findClosestGeometry(originGeometry=isolatedRegion, otherGeometries=[ region for region in contiguousRegions if region is not isolatedRegion ]) closestGroupInIsolatedRegion = findClosestGeometry( originGeometry=closestRegion, otherGeometries=isolatedRegion) closestGroupInClosestRegion = findClosestGeometry( originGeometry=isolatedRegion, otherGeometries=closestRegion) closestGroupInIsolatedRegion.addNeighbors( neighbors=[closestGroupInClosestRegion]) closestGroupInClosestRegion.addNeighbors( neighbors=[closestGroupInIsolatedRegion]) contiguousRegions = findContiguousGroupsOfGraphObjects( neighborsToAttach) tqdm.write(' *** No More Orphaned Redistricting Groups ***')
def test_attachOrphanRedistrictingGroupsToClosestNeighbor_ThreeRegions( self): testDataFilePath = os.path.join( os.path.dirname(__file__), 'testData/2010-Michigan-KeweenawAndTheThumbRedistrictingGroupInfoHasOrphans.redistdata' ) testData = loadDataFromFile(filePath=testDataFilePath) contiguousRegions = findContiguousGroupsOfGraphObjects(testData) self.assertEqual(len(contiguousRegions), 3) assignNeighboringRedistrictingGroupsForRedistrictingGroups(testData) contiguousRegions = findContiguousGroupsOfGraphObjects(testData) self.assertEqual(len(contiguousRegions), 1)
def reorganizeAtomicBlockBetweenRedistrictingGroups(redistrictingGroups): for redistrictingGroup in redistrictingGroups: for borderBlock in redistrictingGroup.borderChildren: borderBlock.removeNonIntersectingNeighbors() atomicBlockGroupDict = {} for redistrictingGroup in redistrictingGroups: atomicBlockGroupDict[redistrictingGroup.graphId] = redistrictingGroup.children.copy() atomicBlockGroups = atomicBlockGroupDict.values() for atomicBlockGroup in atomicBlockGroups: contiguousRegions = findContiguousGroupsOfGraphObjects(atomicBlockGroup) while len(contiguousRegions) > 1: smallestContiguousRegion = min(contiguousRegions, key=lambda contiguousRegion: len(contiguousRegion)) smallestContiguousRegionPolygon = polygonFromMultipleGeometries(smallestContiguousRegion) otherRegion = None otherSplitChildrenList = [x for x in atomicBlockGroups if x is not atomicBlockGroup] for otherSplitChildren in otherSplitChildrenList: otherSplitChildrenPolygon = polygonFromMultipleGeometries(otherSplitChildren) if intersectingPolygons(smallestContiguousRegionPolygon, otherSplitChildrenPolygon): otherRegion = otherSplitChildren break if otherRegion is None: allBlocksInOtherSplits = [block for blockList in otherSplitChildrenList for block in blockList] closestBlock = findClosestGeometry(smallestContiguousRegionPolygon, allBlocksInOtherSplits) closestSplit = next((blockList for blockList in otherSplitChildrenList if closestBlock in blockList), None) otherRegion = closestSplit for childBlock in smallestContiguousRegion: atomicBlockGroup.remove(childBlock) childBlock.removeNeighborConnections() otherRegion.append(childBlock) assignNeighborBlocksFromCandidateBlocks(block=childBlock, candidateBlocks=otherRegion) contiguousRegions = findContiguousGroupsOfGraphObjects(atomicBlockGroup) for key, value in atomicBlockGroupDict.items(): groupWithId = next((redistrictingGroup for redistrictingGroup in redistrictingGroups if redistrictingGroup.graphId == key), None) groupWithId.children = value for redistrictingGroup in redistrictingGroups: redistrictingGroup.attachOrphanBlocksToClosestNeighbor() return redistrictingGroups
def mergeGroupsOfRedistrictingGroups(groupsOfRedistrictingGroups): mergedRedistrictingGroups = [] with tqdm(total=len(groupsOfRedistrictingGroups)) as pbar: for groupOfRedistrictingGroups in groupsOfRedistrictingGroups: if len(groupOfRedistrictingGroups) == 1: mergedRedistrictingGroups.append(groupOfRedistrictingGroups[0]) else: allBorderBlocks = [] allBlocks = [] for redistrictingGroup in groupOfRedistrictingGroups: allBorderBlocks.extend(redistrictingGroup.borderChildren) allBlocks.extend(redistrictingGroup.children) # assign block neighbors to former border blocks tqdm.write(' *** Starting a merge with {0} border blocks and {1} total blocks ***'.format( len(allBorderBlocks), len(allBlocks))) for formerBorderBlock in allBorderBlocks: assignNeighborBlocksFromCandidateBlocks(block=formerBorderBlock, candidateBlocks=allBlocks) contiguousRegions = findContiguousGroupsOfGraphObjects(allBlocks) mergedRedistrictingGroupsForPrevious = [] for contiguousRegion in contiguousRegions: contiguousRegionGroup = RedistrictingGroup(childrenBlocks=contiguousRegion) # assign block neighbors to former border blocks for borderBlock in contiguousRegionGroup.borderChildren: assignNeighborBlocksFromCandidateBlocks(block=borderBlock, candidateBlocks=contiguousRegionGroup.children) contiguousRegionGroup.validateBlockNeighbors() mergedRedistrictingGroupsForPrevious.append(contiguousRegionGroup) mergedRedistrictingGroups.extend(mergedRedistrictingGroupsForPrevious) pbar.update(1) return mergedRedistrictingGroups
def validateContiguousRedistrictingGroups(groupList): contiguousRegions = findContiguousGroupsOfGraphObjects(groupList) if len(contiguousRegions) > 1: saveDataToFileWithDescription(data=contiguousRegions, censusYear='', stateName='', descriptionOfInfo='ErrorCase-GroupsAreNotContiguous') plotGraphObjectGroups(contiguousRegions, showDistrictNeighborConnections=True) raise ValueError("Don't have a contiguous set of RedistrictingGroups. There are {0} distinct groups".format( len(contiguousRegions)))
def mergeContiguousRedistrictingGroups(redistrictingGroupList): for redistrictingGroup in redistrictingGroupList: redistrictingGroup.clearNeighborGraphObjects() assignNeighboringRedistrictingGroupsForRedistrictingGroups(redistrictingGroupList, shouldAttachOrphans=False) contiguousRedistrictingGroups = findContiguousGroupsOfGraphObjects(redistrictingGroupList) mergedGroupsOfRedistrictingGroups = mergeGroupsOfRedistrictingGroups(contiguousRedistrictingGroups) # find and set neighboring geometries assignNeighboringRedistrictingGroupsForRedistrictingGroups(mergedGroupsOfRedistrictingGroups) validateRedistrictingGroups(mergedGroupsOfRedistrictingGroups) validateAllAtomicBlocks() return mergedGroupsOfRedistrictingGroups
def splitNonContiguousRedistrictingGroups(redistrictingGroupList): tqdm.write('\n') tqdm.write('*** Splitting Non-contiguous Redistricting Groups ***') groupsToRemove = [] with tqdm(total=len(redistrictingGroupList)) as pbar: for redistrictingGroup in redistrictingGroupList: contiguousGroups = findContiguousGroupsOfGraphObjects(redistrictingGroup.children) if len(contiguousGroups) > 1: groupsToRemove.append(redistrictingGroup) for contiguousGroup in contiguousGroups: splitGroup = RedistrictingGroup(childrenBlocks=contiguousGroup) redistrictingGroupList.append(splitGroup) pbar.update(1) for groupToRemove in groupsToRemove: redistrictingGroupList.remove(groupToRemove)
def validateBlockNeighbors(self): contiguousRegions = findContiguousGroupsOfGraphObjects(self.children) if len(contiguousRegions) > 1: saveDataToFileWithDescription(data=[self, contiguousRegions], censusYear='', stateName='', descriptionOfInfo='ErrorCase-BlocksNotContiguous') plotGraphObjectGroups(contiguousRegions, showDistrictNeighborConnections=True) plotBlocksForRedistrictingGroup(self, showBlockNeighborConnections=True, showBlockGraphIds=True) raise RuntimeError("Don't have a contiguous set of AtomicBlocks. There are {0} distinct groups.".format( len(contiguousRegions))) for block in self.children: neighborBlocksNotInGroup = [neighborBlock for neighborBlock in block.allNeighbors if neighborBlock not in self.children] if len(neighborBlocksNotInGroup): saveDataToFileWithDescription(data=[self, block], censusYear='', stateName='', descriptionOfInfo='ErrorCase-BlockHasNeighborOutsideRedistrictingGroup') plotBlocksForRedistrictingGroup(self, showBlockNeighborConnections=True, showBlockGraphIds=True) raise RuntimeError("Some blocks have neighbor connections with block outside the redistricting group")
def mergeCandidatesIntoPreviousGroups(candidates): mergedCandidates = [] for candidate in candidates: # group redistricting groups together based on previous parent parentDict = {} for redistrictingGroup in candidate: # if it doesn't have a previous parent, that means it wasn't broken up, so we will just let is pass through if redistrictingGroup.previousParentId is None: parentDict[redistrictingGroup.graphId] = [redistrictingGroup] else: if redistrictingGroup.previousParentId in parentDict: parentDict[redistrictingGroup.previousParentId].append( redistrictingGroup) else: parentDict[redistrictingGroup.previousParentId] = [ redistrictingGroup ] # merge the grouped groups together mergedRedistrictingGroups = [] with tqdm(total=len(parentDict)) as pbar: for redistrictingGroupList in parentDict.values(): if len(redistrictingGroupList) == 1: mergedRedistrictingGroups.append(redistrictingGroupList[0]) else: allBorderBlocks = [] allBlocks = [] for redistrictingGroup in redistrictingGroupList: allBorderBlocks.extend( redistrictingGroup.borderChildren) allBlocks.extend(redistrictingGroup.children) # assign block neighbors to former border blocks tqdm.write( ' *** Starting a merge with {0} border blocks and {1} total blocks ***' .format(len(allBorderBlocks), len(allBlocks))) for formerBorderBlock in allBorderBlocks: assignNeighborBlocksFromCandidateBlocks( block=formerBorderBlock, candidateBlocks=allBlocks) contiguousRegions = findContiguousGroupsOfGraphObjects( allBlocks) mergedRedistrictingGroupsForPrevious = [] for contiguousRegion in contiguousRegions: contiguousRegionGroup = RedistrictingGroup( childrenBlocks=contiguousRegion) # assign block neighbors to former border blocks for borderBlock in contiguousRegionGroup.borderChildren: assignNeighborBlocksFromCandidateBlocks( block=borderBlock, candidateBlocks=contiguousRegionGroup.children) contiguousRegionGroup.validateBlockNeighbors() mergedRedistrictingGroupsForPrevious.append( contiguousRegionGroup) mergedRedistrictingGroups.extend( mergedRedistrictingGroupsForPrevious) pbar.update(1) mergedCandidates.append(mergedRedistrictingGroups) return mergedCandidates