I have a scatter plot that gets sorted into bins. There are 4 bins, two arcs separated by a line in the middle. It's sorted row by row into a list of lists. E.g. If there's one scatter point in each bin the export would be:
x[0],y[0] = [(x,y)],[(x,y)],[(x,y)],[(x,y)]
The problem is I have to manually export each row. So If I wanted to export the second row of scatter plot I would change to x[1],y[1] and add it to the 1st row. This isn't very efficient if I have multiple rows.
If I use x,y I get a Value Error: ValueError: operands could not be broadcast together with shapes (70,) (10,)
Is there a method to export the entire dataset row by row or alternatively, use the same code and loop through each row.
import math
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
x = np.random.randint(80, size=(400, 10))
y = np.random.randint(80, size=(400, 10))
fig, ax = plt.subplots()
ax.grid(False)
plt.scatter(x[0],y[0])
#Creating the arcs
BIN_23_X = 50
ang1 = 0, 50
ang2 = 100, 50
angle = math.degrees(math.acos(5.5/9.15))
#Adding the arcs and halfway line
Halfway = mpl.lines.Line2D((BIN_23_X,BIN_23_X), (0,100), c = 'black', lw = 2.5, alpha = 0.8, zorder = 1)
arc1 = mpl.patches.Arc(ang1, 65, 100, angle = 0, theta2 = angle, theta1 = 360-angle, lw = 2)
arc2 = mpl.patches.Arc(ang2, 65, 100, angle = 0, theta2 = 180+angle, theta1 = 180-angle, lw = 2)
ax.add_line(Halfway)
ax.add_patch(arc1)
ax.add_patch(arc2)
#Sorting the coordinates into bins
def get_nearest_arc_vert(x, y, arc_vertices):
err = (arc_vertices[:,0] - x)**2 + (arc_vertices[:,1] - y)**2
nearest = (arc_vertices[err == min(err)])[0]
return nearest
arc1v = ax.transData.inverted().transform(arc1.get_verts())
arc2v = ax.transData.inverted().transform(arc2.get_verts())
def classify_pointset(vx, vy):
bins = {(k+1):[] for k in range(4)}
for (x,y) in zip(vx, vy):
nx1, ny1 = get_nearest_arc_vert(x, y, arc1v)
nx2, ny2 = get_nearest_arc_vert(x, y, arc2v)
if x < nx1:
bins[1].append((x,y))
elif x > nx2:
bins[4].append((x,y))
else:
if x < BIN_23_X:
bins[2].append((x,y))
else:
bins[3].append((x,y))
return bins
#Bins Output
bins_red = classify_pointset(x[0], y[0])
all_points = [None] * 5
for bin_key in [1,2,3,4]:
all_points[bin_key] = bins_red[bin_key]
print(all_points)
The row that I want to sort into bins is:
bins = classify_pointset(x[0], y[0])
Can I change the bins = classify_pointset(x[0], y[0]) or add a loop to iterate through each row?
EXAMPLE OF WHAT I'M HOPING TO ACCOMPLISH
If we use the first row of the data to return the binned coordinates I would use:
bins = classify_pointset(x[0], y[0])
Output:
[None, [(17, 20), (20, 36), (23, 30), (0, 65), (15, 35)], [(44, 57), (45, 3), (43, 0)], [(61, 21)], [(78, 23)]]

As you can see there's 5 coordinates in the 1st bin [(17, 20), (20, 36), (23, 30), (0, 65), (15, 35)]. 3 in the 2nd [(44, 57), (45, 3), (43, 0)], 1 in the 3rd bin [(61, 21)] and 1 in the 4th bin [(78, 23)]
To return the 2nd row of binned coordinates I would change:
bins = classify_pointset(x[0], y[0]) to bins = classify_pointset(x[1], y[1]).
I would then append the 2nd row to the first row to create this:
0 = [(x,y)],[(x,y)],[(x,y)],[(x,y)]
1 = [(x,y)],[(x,y)],[(x,y)],[(x,y)]
This problem is I have to keep manually changing the row and appending. E.g
Return bins = classify_pointset(x[2], y[2]) and then append:
Output:
2 = [(x,y)],[(x,y)],[(x,y)],[(x,y)]
Append:
0 = [(x,y)],[(x,y)],[(x,y)],[(x,y)]
1 = [(x,y)],[(x,y)],[(x,y)],[(x,y)]
2 = [(x,y)],[(x,y)],[(x,y)],[(x,y)]
I need something that returns the entire xy dataset into their respective bins in a row by row format. Instead of exporting one row at a time and then appending.
Doe this make sense?
Okay, here is my stab at this. There are a few things that I'm unsure why you chose to do it that way so I've changed them. Feel free to let know if they needed to be that way, and I can change them back.
First, I'm not sure why you use a dictionary instead of a list for your bins in classify_pointset. I've changed it to use a list and it is now zero-indexed.
def classify_pointset(vx, vy):
bins = [[] for k in range(4)]
for (x,y) in zip(vx, vy):
nx1, ny1 = get_nearest_arc_vert(x, y, arc1v)
nx2, ny2 = get_nearest_arc_vert(x, y, arc2v)
if x < nx1:
bins[0].append((x,y))
elif x > nx2:
bins[3].append((x,y))
else:
if x < BIN_23_X:
bins[1].append((x,y))
else:
bins[2].append((x,y))
return bins
Next, I'm not sure why you are then turning the dictionary that you did have into a list. The changes that I made above accomplish this.
Now for going through each bin automatically, we can just use the range function and the shape of the arrays. I am calculating the first bin manually just so that we can compare it against the final bins and make sure that it matches.
first_bin = classify_pointset(x[0],y[0])
#Bins Output
all_points = []
for i in range(x.shape[0]):
bins = classify_pointset(x[i],y[i])
all_points.append(bins)
print first_bin
print all_points[0]
Any code that isn't listen above was left as is. Let me know if anything is off or unclear.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With