2

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?

Rahat Zaman
  • 1,322
  • 14
  • 32
  • You have fixed radius `=sqrt(400)`. Change it to random values in the range (0, 20). – swatchai Jun 20 '18 at 02:02
  • @swatchai , I may could not make you understand. I do not want to FILL the circle with dots. I want to distribute the dots evenly in the perimeter of the circle. I have edited to further remove this confusion. Thank you – Rahat Zaman Jun 20 '18 at 02:06
  • 2
    Make use of polar coordinate system. Begin with `np.linspace(0, np.pi, n_dots)` to get all the angles. – swatchai Jun 20 '18 at 02:52
  • 1
    With each angle and a radius (say 20), compute `x=20cos(t)` and `y=20sin(t)`. – swatchai Jun 20 '18 at 02:55
  • @swatchai, Thank you. This is what I needed. You can add the answer in this question and I will mark is as correct answer and upvote it :) – Rahat Zaman Jun 20 '18 at 08:21

2 Answers2

4

A simple way to plot evenly-spaced points along the perimeter of a circle begins with dividing the whole circle into equally small angles where the angles from circle's center to all points are obtained. Then, the coordinates (x,y) of each point can be computed. Here is the code that does the task:

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(8, 8))

n_dots = 120   # set number of dots
angs = np.linspace(0, 2*np.pi, n_dots)  # angles to the dots
cx, cy = (50, 20)  # center of circle
xs, ys = [], []    # for coordinates of points to plot
ra = 20.0          # radius of circle

for ang in angs:
    # compute (x,y) for each point
    x = cx + ra*np.cos(ang)
    y = cy + ra*np.sin(ang)
    xs.append(x)   # collect x
    ys.append(y)   # collect y

plt.scatter(xs, ys, c = 'red', s=5)  # plot points 
plt.show()

The resulting plot: enter image description here

Alternately, numpy's broadcasting nature can be used and shortened the code:

import matplotlib.pyplot as plt
import numpy as np

fig=plt.figure(figsize=(8, 8))

n_dots = 120   # set number of dots
angs = np.linspace(0, 2*np.pi, n_dots)  # angles to the dots
cx, cy = (50, 20)  # center of circle
ra = 20.0          # radius of circle

# with numpy's broadcasting feature...
# no need to do loop computation as in above version
xs = cx + ra*np.cos(angs)
ys = cy + ra*np.sin(angs)

plt.scatter(xs, ys, c = 'red', s=5)  # plot points 
plt.show()
swatchai
  • 17,400
  • 3
  • 39
  • 58
1

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

f5r5e5d
  • 3,656
  • 3
  • 14
  • 18