I have a set of problems where I have multiple coordinates and I want to quickly detect where that coordinate lies within a list of pre-made boxes.
I provide a code for this type of problem. But I am using "for loop" iteration, which I think is quite slow given my current situation dealing with big data. That being set I might have thousands of boxes (rectangles/squares) and coordinates.
I am looking for any other alternative that may be efficient and fast for this type of problem?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
pad = 1
xn1 = np.linspace(0-(pad*2), 0+(pad*2), 3)
yn1 = np.linspace(0-(pad*2), 0+(pad*2), 3)
print(xn1, yn1)
xn1_list = []
yn1_list = []
xy1_list = []
# Create the coordinates
for p1 in range(0, len(xn1)):
for q1 in range(0, len(yn1)):
xn1_list.append(xn1[p1])
yn1_list.append(yn1[q1])
for pad1, coord1 in enumerate(zip(xn1_list, yn1_list)):
xy1_list.append(coord1)
print('\nxy1_list',xy1_list)
# Plot
fig, (ax1) = plt.subplots(figsize = (8,8))
for i in range(0, len(xy1_list)):
# print(len(xy3_list))
plt.scatter(xy1_list[i][0],xy1_list[i][1])
ax1.add_patch(Rectangle(xy=(xy1_list[i][0]-(pad*2)/2, xy1_list[i][1]-(pad*2)/2) ,width=pad*2, height=pad*2,
linewidth=1, color='blue', fill=False))
ax1.annotate(i, xy=(xy1_list[i][0], xy1_list[i][1]), textcoords='data', fontsize = 15)
plt.xticks(np.arange(-3, 3.1, step=1))
plt.yticks(np.arange(-3, 3.1, step=1))
# Current coordinate
X_cur, Y_cur = 0.5,2
plt.scatter(X_cur, Y_cur, color='r', marker='x')
# Iterate every possible box in the list
for i in range(0,len(xy1_list)):
Xmin_temp, Xmax_temp = xy1_list[i][0]-pad, xy1_list[i][0]+pad
Ymin_temp, Ymax_temp = xy1_list[i][1]-pad, xy1_list[i][1]+pad
# Check if the current coordinate is in one of the boxes
if (Xmin_temp < X_cur <= Xmax_temp) & (Ymin_temp < Y_cur <= Ymax_temp):
print('Current Coordinate is in Box'+str(i)+' with a centre coordinate of ('+str(xy1_list[i][0])+', '+str(xy1_list[i][1])+')')
Visualize the results: enter image description here
Edited version according to @Green Cloak Guy idea
from math import floor, ceil
subdivisions = {} # hashtable of subdivisions of the graph
# key format: 2-tuple (x, y)
# value format: 4-tuple (left, right, bottom, top)
...
# Plot
fig, (ax1) = plt.subplots(figsize = (8,8))
for i in range(0, len(xy1_list)):
print('\nCenter Coord of the box'+str(i)+' - '+str(xy1_list[i]))
# renaming your variables to be easier to work with
# assuming [x, y] is center of each square
width = height = pad * 2 # note that you could have differently-shaped rectangles
left = xy1_list[i][0] - (width / 2)
right = xy1_list[i][0] + (width / 2)
bottom = xy1_list[i][1] - (height / 2)
top = xy1_list[i][1] + (height / 2)
print('x1:'+str(left)+' x2: '+str(right)+' y1: '+str(bottom)+' y2: '+str(top))
# add rectangle to plot, as you do in your code
plt.scatter(xy1_list[i][0], xy1_list[i][1])
ax1.add_patch(Rectangle(xy=(xy1_list[i][0]-width/2, xy1_list[i][1]-height/2), width=width, height=height,
linewidth=1, color='blue', fill=False))
ax1.annotate(i, xy=(xy1_list[i][0], xy1_list[i][1]), textcoords='data', fontsize = 15)
# # add rectangle to the appropriate subdivision(s)
x, y = xy1_list[i][0], xy1_list[i][1]
subdivisions.setdefault((x,y), [])
subdivisions[(x,y)].append((left, right, bottom, top))
...
# Current coordinate
X_cur, Y_cur = 0.5,2
plt.scatter(X_cur, Y_cur, color='r', marker='x')
# find box(es) coordinate is in
# in this case, that would be the box going from (0, 0) to (2, 2),
# which, in the coordinate dictionary, would be (0, 0)
boxes_contained = [
box
for box in subdivisions.get((x,y),[])
if (box[0] <= X_cur <= box[1]) and (box[2] <= Y_cur <= box[3])
]
But it does not return anything in the boxes_contained. How can I fix this based on the new code?