Search code examples
pythonmatplotlibscatter-plotuniform-distribution

How to create a circle with uniformly distributed dots in the perimeter of it with scatterplot in python


Suppose I have a circle x**2 + y**2 = 20. Now I want to plot the circle with n_dots number of dots in the circles perimeter in a scatter plot. So I created the code like below:

n_dots = 200
x1 = np.random.uniform(-20, 20, n_dots//2)
y1_1 = (400 - x1**2)**.5
y1_2 = -(400 - x1**2)**.5
plt.figure(figsize=(8, 8))
plt.scatter(x1, y1_1, c = 'blue')
plt.scatter(x1, y1_2, c = 'blue')
plt.show()

But this shows the dots not uniformly distributed all the places in the circle. The output is :

output scatter plot

So how to create a circle with dots in scatter plot where all the dots are uniformly distributed in the perimeter of the circle?


Solution

  • for a very generalized answer that also works in 2D:

    import numpy as np
    import matplotlib.pyplot as plt
    
    
    def u_sphere_pts(dim, N):
        """
        uniform  distribution points on hypersphere
        from uniform distribution in n-D (<-1, +1>) hypercube,
        clipped by unit 2 norm to get the points inside the insphere,
        normalize selected points to lie on surface of unit radius hypersphere
        """
        # uniform points in hypercube
        u_pts = np.random.uniform(low=-1.0, high=1.0, size=(dim, N))
    
        # n dimensional 2 norm squared
        norm2sq = (u_pts**2).sum(axis=0)
    
        # mask of points where 2 norm squared  < 1.0
        in_mask = np.less(norm2sq, np.ones(N))
    
        # use mask to select points, norms inside unit hypersphere
        in_pts = np.compress(in_mask, u_pts, axis=1)
        in_norm2 = np.sqrt(np.compress(in_mask, norm2sq))  # only sqrt selected
    
        # return normalized points, equivalently, projected to hypersphere surface
        return in_pts/in_norm2
    
    
    # show some 2D "sphere" points
    N = 1000
    dim = 2
    fig2, ax2 = plt.subplots()
    ax2.scatter(*u_sphere_pts(dim, N))
    ax2.set_aspect('equal')
    plt.show()
    

    enter image description here

    # plot histogram of angles
    
    pts = u_sphere_pts(dim, 1000000)
    theta = np.arctan2(pts[0,:], pts[1,:])
    num_bins = 360
    fig1, ax1 = plt.subplots()
    n, bins, patches = plt.hist(theta, num_bins, facecolor='blue', alpha=0.5)
    plt.show()
    

    enter image description here

    similar/related: https://stackoverflow.com/questions/45580865/python-generate-an-n-dimensional-hypercube-using-rejection-sampling#comment78122144_45580865

    Python Uniform distribution of points on 4 dimensional sphere

    http://mathworld.wolfram.com/HyperspherePointPicking.html

    Sampling uniformly distributed random points inside a spherical volume