Source code for eaarl.rcf
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8 :
'''Random-consensus filter algorithms'''
# Boilerplate for cross-compatibility of Python 2/3
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future.builtins import * # pylint: disable=wildcard-import
import future.standard_library
future.standard_library.install_aliases()
import numpy as np
[docs]def rcf_jury(jury, width, tie=None):
'''Find winning window of jury
Parameters
jury : array-like of numeric
Jury of values to search for winning window
width : numeric
Search window
tie : string or None
Specifies how to handle a tie. Valid values:
* 'high' or None - Uses the highest winning window
* 'mid' - Uses the middle winning window
* 'low' - Uses the lowest winning window
'''
jury = np.array(jury)
jury.sort()
best_vote = 0
best_index = [0]
i = j = 0
while i < jury.size:
lower = jury[i]
upper = lower + width
while j < jury.size and jury[j] < upper:
j += 1
vote = j - i
if vote > best_vote:
best_vote = vote
best_index = [i]
elif vote == best_vote:
best_index.append(i)
i += 1
while i < jury.size and jury[i] == lower:
i += 1
if tie is None or tie == 'high':
idx = best_index[-1]
elif tie == 'low':
idx = best_index[0]
elif tie == 'mid':
idx = best_index[int(len(best_index)/2.)]
else:
raise ValueError('invalid tie value')
return jury[idx]
[docs]def rcf_grid(x, y, z, width, cell_size, min_winners=3, tie=None):
'''Determines which points pass the gridded RCF filter
Returns an array of Boolean values where True means a point passed the
filter. The filter divides the points into cells based on cell_size, then
finds points with elevation values that pass the RCF filter using the given
width.
Parameters
x : array-like of floats
x coordinates for points
y : array-like of floats
y coordinates for points
z : array-like of floats
z coordinates for points
width : numeric
Vertical search window to use in each cell
cell_size : numeric
Horizontal cell size
min_winners : integer
Minimum number of points needed for winning points to pass the
filter in a grid cell
tie : string or None
Specifies how to handle a tie. Valid values:
* 'high' or None - Uses the highest winning window
* 'mid' - Uses the middle winning window
* 'low' - Uses the lowest winning window
'''
bottom = lambda v: int(v.min() / cell_size) * cell_size
grid_nums = lambda v: ((v - bottom(v))/cell_size).astype('int')
xgrid = grid_nums(x)
ygrid = grid_nums(y)
xgrid_uniq = np.unique(xgrid)
ygrid_uniq = np.unique(ygrid)
keep = np.zeros_like(x, dtype='bool')
where_and = lambda k1, k2: np.nonzero(np.logical_and(k1, k2))[0]
for xgi in xgrid_uniq:
for ygi in ygrid_uniq:
idx = where_and(xgrid == xgi, ygrid == ygi)
if idx.size == 0:
continue
low = rcf_jury(z[idx], width, tie=tie)
good = idx[where_and(z[idx] >= low, z[idx] < low + width)]
if good.size >= min_winners:
keep[good] = True
return keep