patternpythonMinor
Creating a flood from a seed point in an array
Viewed 0 times
pointcreatingarrayseedfloodfrom
Problem
I have created a python script that takes a 2D NumPy array of elevation values and given a seed value and an elevation it will grow a flood from that seed point. It does this by checking all adjacent cells to see if they are above or below the flood level. From there it checks all of those locations until all cells that touch a flooded cell have been checked. If a cell is below the flood level, but surrounded by higher values it doesn't get flooded.
This is the test code. I then implement it in GIS where I convert a raster to an array and process that. This works, but doesn't scale well at all if used with a larger raster, i.e. takes ages.
How can I improve this code, is this the right approach in python? I know there are GIS tools to do this out there, this is a learning task for myself.
```
'''
This program is designed to generate in_array flood array from in_array seed point
and an elevation to flood to. The output array is set to 0 where
the cell is calculated to be flooded and retains its elevation
everywhere else.
'''
#Support Python 3 print functionality in Python 2
from __future__ import print_function
#import generic modules
import sys
import numpy as np
import matplotlib.pyplot as plt
#global variables
in_array = np.random.rand(0)
proc_array = np.random.rand(0)
spent = []
to_process = []
'''
Main calling block
'''
def proc_main():
print('Starting...')
try:
#Run actual functionality
proc_run()
except Exception as e:
print ('Error:' + str(e))
finally:
pass
#optional wait for keypress
#input('Press Enter...')
'''
Main program functionality
'''
def proc_run():
global in_array,proc_array, spent, to_process
#in_array = np.random.rand(11,11)
in_array = np.array([[5,9,5,5,5,5,9,5,5,5,5],
[5,9,5,5,9,9,9,5,5,5,5],
[9,9,5,5,9,5,9,5,5,5,5],
[9,9,5,5,9,9,9,5,5,5,5],
[5,5,5,5,5,5,9,5,5,5,9],
This is the test code. I then implement it in GIS where I convert a raster to an array and process that. This works, but doesn't scale well at all if used with a larger raster, i.e. takes ages.
How can I improve this code, is this the right approach in python? I know there are GIS tools to do this out there, this is a learning task for myself.
```
'''
This program is designed to generate in_array flood array from in_array seed point
and an elevation to flood to. The output array is set to 0 where
the cell is calculated to be flooded and retains its elevation
everywhere else.
'''
#Support Python 3 print functionality in Python 2
from __future__ import print_function
#import generic modules
import sys
import numpy as np
import matplotlib.pyplot as plt
#global variables
in_array = np.random.rand(0)
proc_array = np.random.rand(0)
spent = []
to_process = []
'''
Main calling block
'''
def proc_main():
print('Starting...')
try:
#Run actual functionality
proc_run()
except Exception as e:
print ('Error:' + str(e))
finally:
pass
#optional wait for keypress
#input('Press Enter...')
'''
Main program functionality
'''
def proc_run():
global in_array,proc_array, spent, to_process
#in_array = np.random.rand(11,11)
in_array = np.array([[5,9,5,5,5,5,9,5,5,5,5],
[5,9,5,5,9,9,9,5,5,5,5],
[9,9,5,5,9,5,9,5,5,5,5],
[9,9,5,5,9,9,9,5,5,5,5],
[5,5,5,5,5,5,9,5,5,5,9],
Solution
This is a job for
together with a flood level and a seed point for the flood:
Then
Here
Each labelled region corresponds to a floodable basin in the original problem, and
scipy.ndimage.measurements.label. Suppose that we have an array of elevations:elevation = np.array([[5,9,5,5,5,5,9,5,5,5,5],
[5,9,5,5,9,9,9,5,5,5,5],
[9,9,5,5,9,5,9,5,5,5,5],
[9,9,5,5,9,9,9,5,5,5,5],
[5,5,5,5,5,5,9,5,5,5,9],
[5,5,5,5,5,8,9,5,5,5,9],
[5,5,5,5,5,5,9,5,5,5,9],
[5,5,5,5,5,5,9,5,5,5,5],
[5,5,5,5,5,5,9,5,5,5,5],
[5,5,5,5,5,5,9,5,5,5,5],
[5,5,5,5,5,5,5,5,5,5,5]])together with a flood level and a seed point for the flood:
flood_level = 8.5
flood_seed = 5, 5Then
elevation < flood_level is an array containing True for each cell that is below the flood level, and False otherwise. Passing this array to scipy.ndimage.measurements.label gives an array labelling the orthogonally connected regions, together with the count of the regions:regions, nregions = scipy.ndimage.measurements.label(elevation < flood_level)Here
regions is the array:[[1, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2],
[1, 0, 2, 2, 0, 0, 0, 2, 2, 2, 2],
[0, 0, 2, 2, 0, 3, 0, 2, 2, 2, 2],
[0, 0, 2, 2, 0, 0, 0, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]]Each labelled region corresponds to a floodable basin in the original problem, and
regions[flood_seed] gives the number of the region that is flooded starting at flood_seed: here, region 2.Code Snippets
elevation = np.array([[5,9,5,5,5,5,9,5,5,5,5],
[5,9,5,5,9,9,9,5,5,5,5],
[9,9,5,5,9,5,9,5,5,5,5],
[9,9,5,5,9,9,9,5,5,5,5],
[5,5,5,5,5,5,9,5,5,5,9],
[5,5,5,5,5,8,9,5,5,5,9],
[5,5,5,5,5,5,9,5,5,5,9],
[5,5,5,5,5,5,9,5,5,5,5],
[5,5,5,5,5,5,9,5,5,5,5],
[5,5,5,5,5,5,9,5,5,5,5],
[5,5,5,5,5,5,5,5,5,5,5]])flood_level = 8.5
flood_seed = 5, 5regions, nregions = scipy.ndimage.measurements.label(elevation < flood_level)[[1, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2],
[1, 0, 2, 2, 0, 0, 0, 2, 2, 2, 2],
[0, 0, 2, 2, 0, 3, 0, 2, 2, 2, 2],
[0, 0, 2, 2, 0, 0, 0, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]]Context
StackExchange Code Review Q#92559, answer score: 3
Revisions (0)
No revisions yet.