Skip to content

Commit 7849e1a

Browse files
committed
defined function torusW
1 parent 3f3ff6d commit 7849e1a

File tree

2 files changed

+120
-66
lines changed

2 files changed

+120
-66
lines changed

libpysal/weights/tests/test_util.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,16 @@ def test_lat2W(self):
2929
self.assertEqual(w9.pct_nonzero, 29.62962962962963)
3030
self.assertEqual(w9[0], {1: 1.0, 3: 1.0})
3131
self.assertEqual(w9[3], {0: 1.0, 4: 1.0, 6: 1.0})
32-
w9t = lat2W(3, 3,torus=True)
33-
self.assertEqual(w9t.pct_nonzero, 44.44444444444444)
34-
self.assertEqual(w9t[0], {1: 1.0, 2: 1.0, 3: 1.0, 6: 1.0})
35-
self.assertEqual(w9t[3], {0: 1.0, 4: 1.0, 5: 1.0, 6: 1.0})
32+
33+
def test_torusW(self):
34+
wt = torusW(3, 3)
35+
self.assertEqual(wt[0], {1: 1.0, 2: 1.0, 3: 1.0, 6: 1.0})
36+
self.assertEqual(wt[3], {0: 1.0, 4: 1.0, 5: 1.0, 6: 1.0})
37+
38+
def test_torusW(self):
39+
wh = hexLat2W(5, 5)
40+
self.assertEqual(wh[1], {0: 1.0, 6: 1.0, 2: 1.0, 5: 1.0, 7: 1.0})
41+
self.assertEqual(wh[21], {16: 1.0, 20: 1.0, 22: 1.0})
3642

3743
def test_lat2SW(self):
3844
w9 = util.lat2SW(3, 3)

libpysal/weights/util.py

Lines changed: 110 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
'shimbel', 'remap_ids', 'full2W', 'full', 'WSP2W',
2424
'insert_diagonal', 'get_ids', 'get_points_array_from_shapefile',
2525
'min_threshold_distance', 'lat2SW', 'w_local_cluster',
26-
'higher_order_sp', 'hexLat2W', 'attach_islands',
26+
'higher_order_sp', 'hexLat2W', 'torusW', 'attach_islands',
2727
'nonplanar_neighbors', 'fuzzy_contiguity']
2828

2929

@@ -113,35 +113,121 @@ def hexLat2W(nrows=5, ncols=5, **kwargs):
113113

114114
return W(w, **kwargs)
115115

116+
def torusW(nrows=5, ncols=5, rook=True, **kwargs):
117+
"""
118+
Create a W object for a torus lattice.
119+
120+
Parameters
121+
----------
122+
nrows : int
123+
number of rows
124+
ncols : int
125+
number of columns
126+
rook : boolean
127+
type of contiguity. Default is rook. For queen, rook = False
128+
**kwargs : keyword arguments
129+
optional arguments for :class:`pysal.weights.W`
130+
131+
Returns
132+
-------
133+
w : W
134+
instance of spatial weights class W
135+
136+
Notes
137+
-----
138+
Observations are row ordered: first k observations are in row 0, next k in row 1, and so on.
139+
140+
Examples
141+
--------
142+
>>> from libpysal.weights import lat2W, torusW
143+
>>> w = lat2W(3,3)
144+
>>> w.neighbors[0]
145+
[3, 1]
146+
>>> w.neighbors[3]
147+
[0, 6, 4]
148+
>>> wt = torusW(3,3)
149+
>>> wt.neighbors[0]
150+
[3, 1, 2, 6]
151+
>>> wh.neighbors[3]
152+
[0, 6, 4, 5]
153+
"""
154+
155+
n = nrows * ncols
156+
r1 = nrows - 1
157+
c1 = ncols - 1
158+
lat_pts = range(n)
159+
rid = [i // ncols for i in range(n)] #must be floor!
160+
cid = [i % ncols for i in range(n)]
161+
162+
w = lat2W(nrows, ncols, rook).neighbors
163+
for i in range(n):
164+
if rid[i] == r1 and r1 not in [0, 1]:
165+
below = rid[i] + 1
166+
r = lat_pts[(below * ncols + cid[i]) - n]
167+
w[i] = w.get(i, []) + [r]
168+
w[r] = w.get(r, []) + [i]
169+
if cid[i] == c1 and c1 not in [0, 1]:
170+
c = lat_pts[(rid[i] * ncols) - n]
171+
w[i] = w.get(i, []) + [c]
172+
w[c] = w.get(c, []) + [i]
173+
if not rook:
174+
if r1 not in [0, 1]:
175+
if cid[i] < c1 and rid[i] == r1:
176+
r = lat_pts[((rid[i] + 1) * ncols + 1 + cid[i]) - n]
177+
w[i] = w.get(i, []) + [r]
178+
w[r] = w.get(r, []) + [i]
179+
if cid[i] > 0 and rid[i] == r1:
180+
r = lat_pts[((rid[i] + 1) * ncols - 1 + cid[i]) - n]
181+
w[i] = w.get(i, []) + [r]
182+
w[r] = w.get(r, []) + [i]
183+
if c1 not in [0, 1]:
184+
if cid[i] == c1:
185+
r = lat_pts[i + 1 - n]
186+
w[i] = w.get(i, []) + [r]
187+
w[r] = w.get(r, []) + [i]
188+
if cid[i] == 0:
189+
below = rid[i] + 2
190+
r = lat_pts[(below * ncols - 1) - n]
191+
w[i] = w.get(i, []) + [r]
192+
w[r] = w.get(r, []) + [i]
193+
194+
return W(w, **kwargs)
116195

117-
def lat2W(nrows=5, ncols=5, rook=True, torus=False, id_type='int', **kwargs):
196+
def lat2W(nrows=5, ncols=5, rook=True, id_type='int', **kwargs):
118197
"""
119198
Create a W object for a regular lattice.
199+
120200
Parameters
121201
----------
202+
122203
nrows : int
123204
number of rows
124205
ncols : int
125206
number of columns
126207
rook : boolean
127208
type of contiguity. Default is rook. For queen, rook =False
128-
torus : boolean
129-
generates weights for circles, spheres. Default is set to False
130209
id_type : string
131210
string defining the type of IDs to use in the final W object;
132211
options are 'int' (0, 1, 2 ...; default), 'float' (0.0,
133212
1.0, 2.0, ...) and 'string' ('id0', 'id1', 'id2', ...)
134213
**kwargs : keyword arguments
135214
optional arguments for :class:`pysal.weights.W`
215+
216+
136217
Returns
137218
-------
219+
138220
w : W
139221
instance of spatial weights class W
222+
140223
Notes
141224
-----
225+
142226
Observations are row ordered: first k observations are in row 0, next k in row 1, and so on.
227+
143228
Examples
144229
--------
230+
145231
>>> from libpysal.weights import lat2W
146232
>>> w9 = lat2W(3,3)
147233
>>> "%.3f"%w9.pct_nonzero
@@ -150,24 +236,14 @@ def lat2W(nrows=5, ncols=5, rook=True, torus=False, id_type='int', **kwargs):
150236
True
151237
>>> w9[3] == {0: 1.0, 4: 1.0, 6: 1.0}
152238
True
153-
154-
>>> w9t = lat2W(3,3,torus=True)
155-
>>> "%.3f"%w9t.pct_nonzero
156-
'44.444'
157-
>>> w9t[0] == {1: 1.0, 2: 1.0, 3: 1.0, 6: 1.0}
158-
True
159-
>>> w9t[3] == {0: 1.0, 4: 1.0, 5: 1.0, 6: 1.0}
160-
True
161239
"""
162-
163240
n = nrows * ncols
164241
r1 = nrows - 1
165242
c1 = ncols - 1
166-
lat_pts = range(n)
167243
rid = [i // ncols for i in range(n)] #must be floor!
168244
cid = [i % ncols for i in range(n)]
169245
w = {}
170-
for i in range(n):
246+
for i in range(n - 1):
171247
if rid[i] < r1:
172248
below = rid[i] + 1
173249
r = below * ncols + cid[i]
@@ -189,38 +265,6 @@ def lat2W(nrows=5, ncols=5, rook=True, torus=False, id_type='int', **kwargs):
189265
r = (rid[i] + 1) * ncols - 1 + cid[i]
190266
w[i] = w.get(i, []) + [r]
191267
w[r] = w.get(r, []) + [i]
192-
if torus:
193-
if rid[i] == r1 and r1 not in [0, 1]:
194-
below = rid[i] + 1
195-
r = lat_pts[(below * ncols + cid[i]) - n]
196-
w[i] = w.get(i, []) + [r]
197-
w[r] = w.get(r, []) + [i]
198-
if cid[i] == c1 and c1 not in [0, 1]:
199-
c = lat_pts[(rid[i] * ncols) - n]
200-
w[i] = w.get(i, []) + [c]
201-
w[c] = w.get(c, []) + [i]
202-
if not rook:
203-
if r1 not in [0, 1]:
204-
# southeast bishop
205-
if cid[i] < c1 and rid[i] == r1:
206-
r = lat_pts[((rid[i] + 1) * ncols + 1 + cid[i]) - n]
207-
w[i] = w.get(i, []) + [r]
208-
w[r] = w.get(r, []) + [i]
209-
# southwest bishop
210-
if cid[i] > 0 and rid[i] == r1:
211-
r = lat_pts[((rid[i] + 1) * ncols - 1 + cid[i]) - n]
212-
w[i] = w.get(i, []) + [r]
213-
w[r] = w.get(r, []) + [i]
214-
if c1 not in [0, 1]:
215-
if cid[i] == c1:
216-
r = lat_pts[i + 1 - n]
217-
w[i] = w.get(i, []) + [r]
218-
w[r] = w.get(r, []) + [i]
219-
if cid[i] == 0:
220-
below = rid[i] + 2
221-
r = lat_pts[(below * ncols - 1) - n]
222-
w[i] = w.get(i, []) + [r]
223-
w[r] = w.get(r, []) + [i]
224268

225269
neighbors = {}
226270
weights = {}
@@ -245,7 +289,6 @@ def lat2W(nrows=5, ncols=5, rook=True, torus=False, id_type='int', **kwargs):
245289
return W(w, weights, ids=ids, id_order=ids[:], **kwargs)
246290

247291

248-
249292
def block_weights(regimes, ids=None, sparse=False, **kwargs):
250293
"""
251294
Construct spatial weights for regime neighbors.
@@ -1205,22 +1248,27 @@ def lat2SW(nrows=3, ncols=5, criterion="rook", row_st=False):
12051248
diagonals = []
12061249
offsets = []
12071250
if criterion == "rook" or criterion == "queen":
1208-
d = np.ones((1, n))
1209-
for i in range(ncols - 1, n, ncols):
1210-
d[0, i] = 0
1211-
diagonals.append(d)
1212-
offsets.append(-1)
1213-
1214-
d = np.ones((1, n))
1215-
diagonals.append(d)
1216-
offsets.append(-ncols)
1251+
if ncols>1:
1252+
d = np.ones((1, n))
1253+
for i in range(ncols - 1, n, ncols):
1254+
d[0, i] = 0
1255+
if criterion == "queen" and ncols==2:
1256+
d = np.ones((1, n))
1257+
diagonals.append(d)
1258+
offsets.append(-1)
1259+
1260+
if ncols>=1:
1261+
d = np.ones((1, n))
1262+
diagonals.append(d)
1263+
offsets.append(-ncols)
12171264

12181265
if criterion == "queen" or criterion == "bishop":
1219-
d = np.ones((1, n))
1220-
for i in range(0, n, ncols):
1221-
d[0, i] = 0
1222-
diagonals.append(d)
1223-
offsets.append(-(ncols - 1))
1266+
if (criterion == "bishop" and ncols>=2) or ncols>2:
1267+
d = np.ones((1, n))
1268+
for i in range(0, n, ncols):
1269+
d[0, i] = 0
1270+
diagonals.append(d)
1271+
offsets.append(-(ncols - 1))
12241272

12251273
d = np.ones((1, n))
12261274
for i in range(ncols - 1, n, ncols):

0 commit comments

Comments
 (0)