def getPopulationEnergySplit(self, alignment, shouldDrawGraph=False): polygonSplitResult = self.getPopulationEnergyPolygonSplit(alignment=alignment, shouldDrawGraph=shouldDrawGraph) polygonSplitResultType = polygonSplitResult[0] if polygonSplitResultType is SplitType.NoSplit: return SplitType.NoSplit, None elif polygonSplitResultType is SplitType.ForceSplitAllBlocks: return SplitType.ForceSplitAllBlocks, None polygonSplits = polygonSplitResult[1] aSplitPolygon = polygonSplits[0] bSplitPolygon = polygonSplits[1] if polygonSplitResultType is SplitType.SplitIncludedInSeam: seamOnEdge = True seamSplitPolygon = None else: seamOnEdge = False seamSplitPolygon = polygonSplitResult[2] aSplit = [] bSplit = [] seamSplit = [] for block in self.children: if doesPolygonContainTheOther(container=aSplitPolygon, target=block.geometry, ignoreInteriors=False): aSplit.append(block) elif doesPolygonContainTheOther(container=bSplitPolygon, target=block.geometry, ignoreInteriors=False): bSplit.append(block) elif not seamOnEdge and doesPolygonContainTheOther(container=seamSplitPolygon, target=block.geometry, ignoreInteriors=False): seamSplit.append(block) # elif allIntersectingPolygons(seamSplitPolygon, block.geometry): # seamSplit.append(block) # plotPolygons([block.geometry]) else: saveDataToFileWithDescription(data=[self, alignment, aSplitPolygon, bSplitPolygon, seamSplitPolygon, block.geometry, seamOnEdge, polygonSplitResultType], censusYear='', stateName='', descriptionOfInfo='ErrorCase-CouldNotFindContainerForBlock') plotPolygons([aSplitPolygon, bSplitPolygon, seamSplitPolygon, block.geometry]) raise RuntimeError("Couldn't find a container for block: {0}".format(block.geometry)) aSplitPopulation = sum(block.population for block in aSplit) bSplitPopulation = sum(block.population for block in bSplit) if aSplitPopulation < bSplitPopulation: aSplit += seamSplit else: bSplit += seamSplit if shouldDrawGraph: plotGraphObjectGroups(graphObjectGroups=[aSplit, bSplit]) return SplitType.NormalSplit, (aSplit, bSplit)
def deflationScore(polygon, shouldPlotResult=False): exteriorPolygon = Polygon(polygon.exterior) stepSize = 1.0 / 60.0 / 60.0 stepSize = 0.01 count = 0 while True: deflateValue = stepSize * count deflatedPolygon = exteriorPolygon.buffer(-deflateValue) if deflatedPolygon.is_empty: deflateValue = inf break if type(deflatedPolygon) is MultiPolygon: break count += 1 if shouldPlotResult and not deflatedPolygon.is_empty: from exportData.displayShapes import plotPolygons plotPolygons([exteriorPolygon, deflatedPolygon]) return deflateValue
def getPopulationEnergyPolygonSplit(self, alignment, shouldDrawGraph=False): finishingBlocksToAvoid = [] while True: lowestEnergySeamResult = self.getLowestPopulationEnergySeam(alignment=alignment, finishingBlocksToAvoid=finishingBlocksToAvoid) if lowestEnergySeamResult is None: return SplitType.NoSplit, None lowestEnergySeam = lowestEnergySeamResult[0] energySeamFinishingBlock = lowestEnergySeamResult[1] energySeamStartingEnergy = lowestEnergySeamResult[2] seamSplitPolygon = polygonFromMultipleGeometries(geometryList=lowestEnergySeam) polygonWithoutSeam = self.geometry.difference(seamSplitPolygon) # if the polygon without the seam is empty, that means we have a small enough redistricting group where # we need to break it up completely. Because our seams can no longer break up any further. if polygonWithoutSeam.is_empty: return SplitType.ForceSplitAllBlocks, None if type(polygonWithoutSeam) is MultiPolygon: seamOnEdge = False splitPolygons = list(polygonWithoutSeam) else: seamOnEdge = True splitPolygons = [polygonWithoutSeam, seamSplitPolygon] if alignment is Alignment.northSouth: aSplitRepresentativeBlockDirection = CardinalDirection.north bSplitRepresentativeBlockDirection = CardinalDirection.south else: aSplitRepresentativeBlockDirection = CardinalDirection.west bSplitRepresentativeBlockDirection = CardinalDirection.east # Identify which polygon is in which direction # Note: Need to make sure we don't select a block in the seam so we supply a list without those blocks # If the seam is completely on the edge though, let's include the seam if seamOnEdge: borderChildrenRepresentativeCandidates = self.borderChildren else: borderChildrenRepresentativeCandidates = [child for child in self.borderChildren if child not in lowestEnergySeam] if len(borderChildrenRepresentativeCandidates) == 0: return SplitType.NoSplit, None aSplitRepresentativeBlock = mostCardinalOfGeometries(geometryList=borderChildrenRepresentativeCandidates, direction=aSplitRepresentativeBlockDirection) bSplitRepresentativeBlock = mostCardinalOfGeometries(geometryList=borderChildrenRepresentativeCandidates, direction=bSplitRepresentativeBlockDirection) aSplitPolygon = getPolygonThatContainsGeometry(polygonList=splitPolygons, targetGeometry=aSplitRepresentativeBlock, useTargetRepresentativePoint=True) bSplitPolygon = getPolygonThatContainsGeometry(polygonList=splitPolygons, targetGeometry=bSplitRepresentativeBlock, useTargetRepresentativePoint=True) leftOverPolygons = [geometry for geometry in splitPolygons if geometry is not aSplitPolygon and geometry is not bSplitPolygon] if aSplitPolygon is None or bSplitPolygon is None: plotPolygons(splitPolygons + [aSplitRepresentativeBlock.geometry, bSplitRepresentativeBlock.geometry]) saveDataToFileWithDescription(data=self, censusYear='', stateName='', descriptionOfInfo='ErrorCase-AorBSplitIsNone') raise RuntimeError('Split a or b not found') if aSplitPolygon is bSplitPolygon: finishingBlocksToAvoid.append(energySeamFinishingBlock) continue if len(leftOverPolygons) is not len(splitPolygons) - 2: saveDataToFileWithDescription(data=self, censusYear='', stateName='', descriptionOfInfo='ErrorCase-MissingPolygons') raise RuntimeError('Missing some polygons for mapping. Split polygons: {0} Left over polygon: {1}' .format(len(splitPolygons), len(leftOverPolygons))) polygonSplits = (aSplitPolygon, bSplitPolygon) if shouldDrawGraph: plotPolygons(polygonSplits) if seamOnEdge: return SplitType.SplitIncludedInSeam, polygonSplits, None, energySeamStartingEnergy else: seamSplitPolygon = polygonFromMultiplePolygons(polygonList=[seamSplitPolygon] + leftOverPolygons) return SplitType.NormalSplit, polygonSplits, seamSplitPolygon, energySeamStartingEnergy
descriptionToWorkWith)) initialDistrict = createDistrictFromRedistrictingGroups(redistrictingGroups=redistrictingGroups) populationDeviation = populationDeviationFromPercent(overallPercentage=overallPercentageOffIdealAllowed, numberOfDistricts=numberOfDistricts, totalPopulation=initialDistrict.population) districts = initialDistrict.splitDistrict(numberOfDistricts=numberOfDistricts, populationDeviation=populationDeviation, weightingMethod=WeightingMethod.cardinalDistance, breakingMethod=BreakingMethod.splitGroupsOnEdge, shouldMergeIntoFormerRedistrictingGroups=True, shouldDrawEachStep=False, shouldRefillEachPass=True, fastCalculations=False, showDetailedProgress=False) saveDataToFileWithDescription(data=districts, censusYear=censusYear, stateName=stateInfo, descriptionOfInfo='{0}-FederalDistricts'.format(descriptionToWorkWith)) saveGeoJSONToDirectoryWithDescription(geographyList=districts, censusYear=censusYear, stateName=stateInfo, descriptionOfInfo='FederalDistrictsGeoJSON') plotDistricts(districts=districts, showPopulationCounts=False, showDistrictNeighborConnections=False) districtPolygons = [district.geometry for district in districts] plotPolygons(districtPolygons)