2

I am trying to create a single point within a polygon using a class for use in an agent based model.

Currently I am able to create random points constrained to the bounds of the polygon, but not the polygon itself. My code at present appears to ignore the if statement within the while loop. I am very new to python so this could be a limitation I am missing.

Here is my current code:

import geopandas as gpd
import matplotlib.pyplot as plt
import random
import pandas as pd

bounds = gpd.read_file("./data/liverpool_bounds.gpkg")


class Agent():
    def __init__(self, bounds):
        x_min, y_min, x_max, y_max = bounds.total_bounds

        counter = 0
        while counter != 1:
            x = random.uniform(x_min, x_max)
            y = random.uniform(y_min, y_max)
            df = pd.DataFrame({'x': [x], 'y': [y]})
            self.agent = gpd.GeoDataFrame(
                df, geometry=gpd.points_from_xy(df.x, df.y))

            if self.agent.within(bounds) is True:
                counter = 1

            # counter does not increase
            print(counter)
            # gives both True and False
            print(self.agent.within(bounds))


Agent(bounds).agent

This code gives an infinite loop. Expected behavior would be to stop given a Boolean True value, and to continue with False, until a True value.

1 Answer 1

4

Don't use the counter variable, but a break statement when the point is sampled within the polygon. The counter variable will always be one on exit so this does not carry new information. I'm not really familiar with the Geopandas library, but you can achieve a solution with Shapely, which is a very nice library imo. With this program structure your object becomes more generally useable.

from shapely.geometry import Point, Polygon
import random


bounds = [(0, 0), (1, 0), (1, 1), (0, 1)]


class Agent():
    def __init__(self, bounds):
        self.polygon = Polygon(bounds)

        # implement your object wide dataframe here to which you can append

    def add_random_point(self):
        xmin, ymin, xmax, ymax = self.polygon.bounds
        while True:
            x = random.uniform(xmin, xmax)
            y = random.uniform(ymin, ymax)

            if Point(x, y).within(self.polygon):
                # if this condition is true, add to a dataframe here

                print(x, y)
                break


obj = Agent(bounds)
obj.add_random_point()
Sign up to request clarification or add additional context in comments.

6 Comments

Hi, thank you for your reply. This does not appear to work however, I still get an infinite loop with self.agent.within(bounds) values of both True and False
The return value of self.agent.within() is a geopandas.Series object, but you need a atomic value in this conditional for it to pass.
@CillianBerragan this update may solve your problem.
Thanks for the update, I personally want to stick with geopandas for my application, but your advise regarding the output of within() gave the solution. I basically just had to convert to a boolean value for the if loop to work; within = int(gdf.within(self.bounds). May not be the best way but it works.
Even better: gdf.within(self.bounds)[0] works as boolean.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.