'Cluster objects by geometric coordinates (Y axis)

I've got a pandas DataFrame with records describing rectangles with absolute coordinates of all the 4 points: TL (top-left), TR (top-right), BL (bottom-left) and BR (bottom-right). As it is, the rects seem to follow a row-like pattern, where there are conspicuous clusters forming "rows", like in this picture:

enter image description here

The data look like this:

    tl_x  tl_y  tr_x  tr_y  br_x  br_y  bl_x  bl_y  ht   wd
0   1567   136  1707   136  1707   153  1567   153  17  140
1   1360   154  1548   154  1548   175  1360   175  21  188
2   1567   154  1747   154  1747   174  1567   174  20  180
3   1311   175  1548   175  1548   196  1311   196  21  237
4   1565   174  1741   174  1741   199  1565   199  25  176
5   1566   196  1753   196  1753   220  1566   220  24  187
...

I need to cluster these objects along the bl_y or br_y column (bottom Y coordinate) to produce a 2D list of "rows" like:

enter image description here

As you see, objects in each "row" may have slightly varying Y coordinates (not exactly equivalent in each cluster). What I basically need is some function to add a separate e.g. clustered_y column to the DF and then sort by this column.

What's the simplest way to go?



Solution 1:[1]

Following my comment on your question.

This is how you should be using a state variable.

function UserManagement({ history }) {
 
  const dispatch = useDispatch();
  
  const userList = useSelector((state) => state.userList);
 
  useEffect(() => {
    dispatch(getUsers());
  },[dispatch, history]);

  useEffect(() => {
    console.log(userList);
  },[userList]);

  ...
}

If you still need to create another variable, you need to assign it a value every time userList changes - by adding this line to the useEffect method just like this.

function UserManagement({ history }) {
 
  const dispatch = useDispatch();
  
  const userList = useSelector((state) => state.userList);
  let users = userList;
 
  useEffect(() => {
    dispatch(getUsers());
  },[dispatch, history]);

  useEffect(() => {
    users = userList;
  },[userList]);

  ...
}

Notice that when you assign a value to a variable like this:

The value assigned to that variable is the initial value of the assigned variable (undefined) because the reducer has not yet updated the state value. And when it actually updates it, nothing updates the second variable you created "users"

  const userList = useSelector((state) => state.userList);
  const users = userList;

And you can use it to manipulate your UI by:

{userList &&
    userList.map((users) => (
        <MyComponent/>
    )
}

Solution 2:[2]

I added a comment to this question,so check that too.

However I just noticed something else that should help you.

Due the the way state works your users are probably returning as undefined

You have two choices here.

  1. Change your users.map() to userList.users.map() as userList.

  2. If you really want it to just be users.map() then you might have to use some react state. For example

import { useSelector } from 'react-redux';
import { useEffect, useState } from 'react'; 
import { MyUserComponent } from 'some_file';

const YourComponent = () => {
  // grab your userList from redux
  const userList = useSelector(state => state.userList);
  
  // create some state for use the users
  // an empty array to start
  const [users, setUsers] = useState([]);
  
  // watch the userList for changes
  useEffect(() => {
    // update the users state whenever 
    // there is a change to useList
    setUsers(userlist.users)
    
  }, [userList])
  
  
  // do whatever you want in your return
  return (
    <div>
      { 
        users.map(user => <MyUserComponent {...user} key={`user-${index}`}) />
      }
    </div>
  )
}

Honestly I'd just do option 1

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Shaded