def assert_traj_equal(actual, expected, pos_atol=1): assert_equal(len(actual), len(expected)) actual = pandas_sort(actual, 'frame').reset_index(drop=True) expected = pandas_sort(expected, 'frame').reset_index(drop=True) actual_order = [] for frame_no in expected['frame'].unique(): actual_f = actual[actual['frame'] == frame_no] expected_f = expected[expected['frame'] == frame_no] assert_equal(len(actual_f), len(expected_f), err_msg='Actual and expected numbers of features ' 'differ in frame %i' % frame_no) tree = cKDTree(actual_f[['y', 'x']].values) devs, argsort = tree.query(expected_f[['y', 'x']].values) assert_allclose(devs, 0., atol=pos_atol) actual_order.extend(actual_f.index[argsort].tolist()) actual = actual.loc[actual_order].reset_index(drop=True, inplace=False) for p_actual in actual.particle.unique(): actual_ind = actual.index[actual['particle'] == p_actual] p_expected = expected.loc[actual_ind[0], 'particle'] expected_ind = expected.index[expected['particle'] == p_expected] assert_array_equal(actual_ind, expected_ind, err_msg='Actual and expected linking results ' 'differ for actual particle %i/expected particle %i' '' % (p_actual, p_expected))
def sort_positions(actual, expected): tree = cKDTree(actual) deviations, argsort = tree.query([expected]) if len(set(range(len(actual))) - set(argsort[0])) > 0: raise AssertionError("Position sorting failed. At least one feature is " "very far from where it should be.") return deviations, actual[argsort][0]
def sort_positions(actual, expected): tree = cKDTree(actual) deviations, argsort = tree.query([expected]) if len(set(range(len(actual))) - set(argsort[0])) > 0: raise AssertionError( "Position sorting failed. At least one feature is " "very far from where it should be.") return deviations, actual[argsort][0]
def eliminate_overlapping_locations(f, separation): """ Makes sure that no position is within `separation` from each other, by deleting one of the that are to close to each other. """ separation = validate_tuple(separation, f.shape[1]) assert np.greater(separation, 0).all() # Rescale positions, so that pairs are identified below a distance of 1. f = f / separation while True: duplicates = cKDTree(f, 30).query_pairs(1) if len(duplicates) == 0: break to_drop = [] for pair in duplicates: to_drop.append(pair[1]) f = np.delete(f, to_drop, 0) return f * separation
def compare_pos_df(actual, expected, pos_atol=0.001, lost_atol=1): """Returns indices of equal and different positions inside dataframes `actual` and `expected`.""" lost0 = [] appeared1 = [] dev0 = [] dev1 = [] equal0 = [] equal1 = [] for frame_no, expected_frame in expected.groupby('frame'): coords0 = expected_frame[['y', 'x']].values actual_frame = actual[actual['frame'] == frame_no] coords1 = actual_frame[['y', 'x']].values # use a KDTree to find nearest neighbors tree = cKDTree(coords1) devs, inds = tree.query(coords0) # find nearest neighbors i_lost0 = np.argwhere(devs > lost_atol).ravel() # features that are equal i_equal0 = np.argwhere(devs < pos_atol).ravel() i_equal1 = inds[i_equal0] # features that are the same, but deviate in position i_dev0 = np.argwhere((devs < lost_atol) & (devs >= pos_atol)).ravel() i_dev1 = inds[i_dev0] # features that present in f1 and not in f0 i_appeared1 = np.argwhere(~np.in1d(np.arange(len(coords1)), np.concatenate( [i_equal0, i_dev0]))).ravel() lost0.append(pandas_iloc(expected_frame, i_lost0).index.values) appeared1.append(pandas_iloc(actual_frame, i_appeared1).index.values) dev0.append(pandas_iloc(expected_frame, i_dev0).index.values) dev1.append(pandas_iloc(actual_frame, i_dev1).index.values) equal0.append(pandas_iloc(expected_frame, i_equal0).index.values) equal1.append(pandas_iloc(actual_frame, i_equal1).index.values) return np.concatenate(lost0), np.concatenate(appeared1), \ (np.concatenate(dev0), np.concatenate(dev1)), \ (np.concatenate(equal0), np.concatenate(equal1)),
def _find_pairs(pos, max_dist, max_dist_3): """Determine isolated pairs of particles: closer than ``max_dist`` together with a possible third particle farther than ``max_dist_3`` from any of them. Optimal for few features. Should use cKDTree or something else for many features Returns array of pair indices (shape N x 2)""" # matrix of all combinations pos = np.atleast_2d(pos) kdt = cKDTree(pos) sparse_mat = kdt.sparse_distance_matrix(kdt, max_distance=max_dist) dist = dist_eucl(pos[..., np.newaxis], pos[np.newaxis, ...]) compare_3 = (dist <= max_dist_3).sum(0) # particles having 0 neighbors closer than the three-body limit # they are free to pair with any particle from this list neighbors_0 = np.where(compare_3 == 1)[0] if len(neighbors_0) > 1: dist_masked = dist[neighbors_0][:, neighbors_0] pairs_0 = np.nonzero(np.tril(dist_masked <= max_dist, k=-1)) else: pairs_0 = ([], []) pairs_0 = [neighbors_0[ind] for ind in pairs_0] # particles having 1 neighbor closer than the three-body limit # this neighbor is directly the pair neighbors_1 = np.where(compare_3 == 2)[0] if len(neighbors_1) > 1: dist_masked = dist[neighbors_1][:, neighbors_1] pairs_1 = np.nonzero(np.tril(dist_masked <= max_dist_3, k=-1)) else: pairs_1 = ([], []) pairs_1 = [neighbors_1[ind] for ind in pairs_1] pairs = np.concatenate([pairs_0, pairs_1], axis=1) pairs_dist = dist[pairs[0], pairs[1]] return pairs.T, pairs_dist