Skip to content

Instantly share code, notes, and snippets.

@Irfy
Created February 17, 2012 00:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Irfy/1849284 to your computer and use it in GitHub Desktop.
Save Irfy/1849284 to your computer and use it in GitHub Desktop.
Implement a cutoff window and a circular window on top of numpy's matrix.
"""
Demonstrates creating windows or views of two-dimensional arrays, in two ways:
* Cutting off parts of window that is outside
* Continuing windows on the opposite side (circular sliding)
'numpy' is a very useful numerical library for python which *already* supports
creating windows/views (actually sub-arrays, for multidimensional arrays). This
code demonstrates how to "wrap" such an underlying implementation to provide
specialized functionality.
The provided functions could have been implemented within classes that wrap
numpy arrays, providing true adapter feel, but that would have been too much for
someone who doesn't know Python. Everybody understands functions though.
"""
from numpy import array, empty
def normalize(dim, dim_max, dim_min=0):
"""
Make sure dim_min <= dim <= dim_max, return the best match.
"""
if dim < dim_min:
return dim_min
if dim > dim_max:
return dim_max
return dim
def window_cutoff(matrix, x_start, x_end, y_start, y_end):
"""
Return a view of the underlying 2D array, cutting off any part of the
window that falls outside. As with all sane indexing, start is inclusive,
end is exclusive.
"""
# _max assume 'F' option
x_max = len(matrix)
y_max = len(matrix[0])
# fix up to fit within matrix
x_start = normalize(x_start, x_max)
y_start = normalize(y_start, y_max)
# determine ends, fit within matrix
x_end = normalize(x_end, x_max)
y_end = normalize(y_end, y_max)
# coordinates have been fixed, use underlying implementation
return matrix[x_start:x_end, y_start:y_end]
def window_circular(matrix, x_start, x_end, y_start, y_end):
"""
Return a view of the underlying 2D array, repeating, in a circular fashion
any part of the window that falls outside, as if the window continued in the
same direction, from the opposite side.
"""
x_max = len(matrix)
y_max = len(matrix[0])
if (0 <= x_start < x_max and
0 <= x_end < x_max and
0 <= y_start < y_max and
0 <= y_end < y_max):
# All coordinates fit within the matrix, use underlying implementation
return matrix[x_start:x_end, y_start:y_end]
# Need manual intervention, coordinates outside normal range of matrix
window = empty((x_end - x_start, y_end - y_start),
dtype=matrix.dtype,
order='F')
for x_i in xrange(x_start, x_end):
for y_i in xrange(y_start, y_end):
window[x_i - x_start, y_i - y_start] = matrix[x_i % x_max, y_i % y_max]
return window
m = array([[1, 11, 111],
[2, 22, 222],
[3, 33, 333],
[4, 44, 444]])
def print_commented(comment, window):
print comment + ':\n', window, '\n'
print_commented("original", m)
print_commented("2nd row, 2nd and 3rd columns", window_cutoff(m, 1, 2, 1, 3))
print_commented("first two rows, first column", window_cutoff(m, -2, 2, -5, 1))
print_commented("nothing", window_cutoff(m, -2, -1, -2, 8))
print_commented("everything", window_cutoff(m, -2, 9, -2, 9))
print_commented("2nd row, 2nd and 3rd columns", window_circular(m, 1, 2, 1, 3))
print_commented("last two rows, first two rows; "
"last two columns, all columns, first column",
window_circular(m, -2, 2, -5, 1))
print_commented("second-to-last row; "
"last two columns, all columns, all columns, first two columns",
window_circular(m, -2, -1, -2, 8))
print_commented("last two rows, all rows, all rows, first row; "
"last two columns, all columns, all columns, all columns",
window_circular(m, -2, 9, -2, 9))
@Irfy
Copy link
Author

Irfy commented Feb 17, 2012

Output:

original:
[[  1  11 111]
 [  2  22 222]
 [  3  33 333]
 [  4  44 444]] 

2nd row, 2nd and 3rd columns:
[[ 22 222]] 

first two rows, first column:
[[1]
 [2]] 

nothing:
[] 

everything:
[[  1  11 111]
 [  2  22 222]
 [  3  33 333]
 [  4  44 444]] 

2nd row, 2nd and 3rd columns:
[[ 22 222]] 

last two rows, first two rows; last two columns, all columns, first column:
[[ 33 333   3  33 333   3]
 [ 44 444   4  44 444   4]
 [ 11 111   1  11 111   1]
 [ 22 222   2  22 222   2]] 

second-to-last row; last two columns, all columns, all columns, first two columns:
[[ 33 333   3  33 333   3  33 333   3  33]] 

last two rows, all rows, all rows, first row; last two columns, all columns, all columns, all columns:
[[ 33 333   3  33 333   3  33 333   3  33 333]
 [ 44 444   4  44 444   4  44 444   4  44 444]
 [ 11 111   1  11 111   1  11 111   1  11 111]
 [ 22 222   2  22 222   2  22 222   2  22 222]
 [ 33 333   3  33 333   3  33 333   3  33 333]
 [ 44 444   4  44 444   4  44 444   4  44 444]
 [ 11 111   1  11 111   1  11 111   1  11 111]
 [ 22 222   2  22 222   2  22 222   2  22 222]
 [ 33 333   3  33 333   3  33 333   3  33 333]
 [ 44 444   4  44 444   4  44 444   4  44 444]
 [ 11 111   1  11 111   1  11 111   1  11 111]] 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment