How to generate random points in a circular distribution - python

I am wondering how i could generate random numbers that appear in a circular distribution.
I am able to generate random points in a rectangular distribution such that the points are generated within the square of (0 <= x < 1000, 0 <= y < 1000):
How would i go upon to generate the points within a circle such that:
(x−500)^2 + (y−500)^2 < 250000 ?

import random
import math
# radius of the circle
circle_r = 10
# center of the circle (x, y)
circle_x = 5
circle_y = 7
# random angle
alpha = 2 * math.pi * random.random()
# random radius
r = circle_r * math.sqrt(random.random())
# calculating coordinates
x = r * math.cos(alpha) + circle_x
y = r * math.sin(alpha) + circle_y
print("Random point", (x, y))
In your example circle_x is 500 as circle_y is. circle_r is 500.
Another version of calculating radius to get uniformly distributed points, based on this answer
u = random.random() + random.random()
r = circle_r * (2 - u if u > 1 else u)

FIRST ANSWER:
An easy solution would be to do a check to see if the result satisfies your equation before proceeding.
Generate x, y (there are ways to randomize into a select range)
Check if ((x−500)^2 + (y−500)^2 < 250000) is true
if not, regenerate.
The only downside would be inefficiency.
SECOND ANSWER:
OR, you could do something similar to riemann sums like for approximating integrals. Approximate your circle by dividing it up into many rectangles. (the more rectangles, the more accurate), and use your rectangle algorithm for each rectangle within your circle.

What you need is to sample from (polar form):
r, theta = [math.sqrt(random.randint(0,500))*math.sqrt(500), 2*math.pi*random.random()]
You can then transform r and theta back to cartesian coordinates x and y via
x = 500 + r * math.cos(theta)
y = 500 + r * math.sin(theta)
Related (although not Python), but gives the idea.

You can use below the code and if want to learn more
https://programming.guide/random-point-within-circle.html
import random
import math
circle_x = 500
circle_y = 500
a = random.randint(0,500) * 2 * math.pi
r = 1 * math.sqrt(random.randint(0,500))
x = r * math.cos(a) + circle_x
y = r * math.sin(a) + circle_y

here's an example hope could help someone :).
randProba = lambda a: a/sum(a)
npoints = 5000 # points to chose from
r = 1 # radius of the circle
plt.figure(figsize=(5,5))
t = np.linspace(0, 2*np.pi, npoints, endpoint=False)
x = r * np.cos(t)
y = r * np.sin(t)
plt.scatter(x, y, c='0.8')
n = 2 # number of points to chose
t = np.linspace(0, 2*np.pi, npoints, endpoint=False)[np.random.choice(range(npoints), n, replace=False, p=randProba(np.random.random(npoints)))]
x = r * np.cos(t)
y = r * np.sin(t)
plt.scatter(x, y)

You can use rejection sampling, generate a random point within the (2r)×(2r) square that covers the circle, repeat until get one point within the circle.

I would use polar coordinates:
r_squared, theta = [random.randint(0,250000), 2*math.pi*random.random()]
Then r is always less than or equal to the radius, and theta always between 0 and 2*pi radians.
Since r is not at the origin, you will always convert it to a vector centered at 500, 500, if I understand correctly
x = 500 + math.sqrt(r_squared)*math.cos(theta)
y = 500 + math.sqrt(r_squared)*math.sin(theta)
Choose r_squared randomly because of this

Related

Python mayavi : How to draw spheres at random positions in 3D space

This is a code for generating random sized spheres with mayavi,
I want to make the spheres to be connected with each other by the surface or with a bond line:
Spheres must be at random positions in 3D space
Spheres must be with the same radius
from mayavi import mlab
import numpy as np
[phi,theta] = np.mgrid[0:2*np.pi:12j,0:np.pi:12j]
x = np.cos(phi)*np.sin(theta)
y = np.sin(phi)*np.sin(theta)
z = np.cos(theta)
def plot_sphere(p):
r,a,b,c = p
r=1
return mlab.mesh(r*x+a, r*y+b, r*z )
for k in range(8):
c = np.random.rand(4)
c[0] /= 10.
plot_sphere(c)
mlab.show()
From sphere equation:
So when passing arguments to mlab.mesh we would like to set [x_0, y_0, z_0] for each sphere such as they are at different positions from the axis.
The problem was that the numbers generated by np.random.rand(4) are random, but not distinct.
Let's modify so that the arguments [x_0, y_0, z_0] are random and distinct:
We use sample to get distinct index numbers in a cube
We convert using index_to_3d the index to an (x, y, z) coordinates
The radius, r, can be adjusted to have more or less spacing between the spheres.
Spheres at 3D space
Code:
import random
from itertools import product
from mayavi import mlab
import numpy as np
[phi, theta] = np.mgrid[0:2 * np.pi:12j, 0:np.pi:12j]
x = np.cos(phi) * np.sin(theta)
y = np.sin(phi) * np.sin(theta)
z = np.cos(theta)
def plot_sphere(x_0, y_0, z_0):
r = 0.5
return mlab.mesh(r * x + x_0, r * y + y_0, r * z + z_0)
SPHERES_NUMBER = 200
CUBE_SIZE = 10
def index_to_3d(i, SIZE):
z = i // (SIZE * SIZE)
i -= (z * SIZE * SIZE)
y = i // SIZE
x = i % SIZE
return x, y, z
random_tuples = [index_to_3d(i, CUBE_SIZE) for i in random.sample(range(CUBE_SIZE ** 3), SPHERES_NUMBER)]
for k in range(SPHERES_NUMBER):
x_0, y_0, z_0 = random_tuples[k]
plot_sphere(x_0, y_0, z_0)
mlab.show()
Output:
Spheres cluster
Let's utilize gauss to create coordinates for the cluster points.
Code:
import random
from itertools import product
from mayavi import mlab
import numpy as np
[phi, theta] = np.mgrid[0:2 * np.pi:12j, 0:np.pi:12j]
x = np.cos(phi) * np.sin(theta)
y = np.sin(phi) * np.sin(theta)
z = np.cos(theta)
def plot_sphere(x_0, y_0, z_0):
r = 0.5
return mlab.mesh(r * x + x_0, r * y + y_0, r * z + z_0)
SPHERES_NUMBER = 200
def create_cluster(CLUSTER_SIZE):
means_and_deviations = [(1, 1.5), (1, 1.5), (1, 1.5)]
def generate_point(means_and_deviations):
return tuple(random.gauss(mean, deviation) for mean, deviation in means_and_deviations)
cluster_points = set()
while len(cluster_points) < CLUSTER_SIZE:
cluster_points.add(generate_point(means_and_deviations))
return list(cluster_points)
cluster_points = create_cluster(SPHERES_NUMBER)
for k in range(SPHERES_NUMBER):
x_0, y_0, z_0 = cluster_points[k]
plot_sphere(x_0, y_0, z_0)
mlab.show()
Output:
What about just using the mayavi points3d function? By default the mode parameter is set to sphere and you can set the diameter by using the scale_factor parameter. You can also increase the resolution of the sphere by varying the resolution parameter.
Here is the code:
def draw_sphere(
center_coordinates,
radius,
figure_title,
color,
background,
foreground
):
sphere = mlab.figure(figure_title)
sphere.scene.background = background
sphere.scene.foreground = foreground
mlab.points3d(
center_coordinates[0],
center_coordinates[1],
center_coordinates[2],
color=color,
resolution=256,
scale_factor=2*radius,
figure=sphere
)
Regarding the connected with each other by the surface issue, your explanation is poor. Maybe you mean just tangent spheres, but I would need more details.

How to plot circles every 20 pixels between two randomly generated points in Pygame?

The homework question I'm working on is the following:
"Draw two randomly placed radius 10 circles on the screen then draw radius 2 circles every twenty pixels from the center of one to the center of the other."
I'm having no trouble randomly generating the two radius 10 circles, but I have no idea how to plot the radius 2 circles between them.
I've tried briefly to plot a line between them, and if there's a way to plot my points along that line, I could definitely do that. I've looked up similar issues and a lot of them mention Bresenham's line algorithm but I doubt that is the answer as it seems very advanced.
Here is the code I have so far for the problem:
import pygame
from random import randint
linecolour = 0,0,0
bgcolour = 255, 255, 255
width = 600
height = 600
screen = pygame.display.set_mode((width, height))
running = 1
x = []
y = []
for i in range (2):
x.append(randint(0,600))
y.append(randint(0,600))
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT: # or other types of events
done = True
screen.fill(bgcolour)
for i,j in zip(x,y):
pygame.draw.circle(screen,linecolour,(i,j),10)
pygame.draw.circle(screen,linecolour,(i,j),2)
pygame.display.flip()
Calculate the direction vector from 1 point to the other:
dir = x[1]-x[0], y[1]-y[0]
Calculate the Euclidean distance between the points. Note you've to import math:
dist = math.sqrt(dir[0]*dir[0] + dir[1]*dir[1])
or as pointed out in the answer of #MadPhysicist
dist = math.hypot(*dir)
the number of points to be drawn is int(dist) // 20. Calculate the points on the line in a loop:
for i in range(int(dist) // 20):
px = int(x[0] + dir[0] * i*20/dist)
py = int(y[0] + dir[1] * i*20/dist)
The code to draw the small points may look like this:
done = False
while not done:
# [...]
dir = x[1]-x[0], y[1]-y[0]
dist = math.hypot(*dir)
for i in range(1, int(dist) // 20 + 1):
pt = int(x[0] + dir[0] * i*20/dist), int(y[0] + dir[1] *i*20/dist)
pygame.draw.circle(screen, linecolour, pt, 2)
This is a very simple problem if you look at it the right way. I would recommend looking at it in terms of polar coordinates. If you have two circles centered at (x[0], y[0]) and (x[1], y[1]), the slope of the line between them is (y[1] - y[0]) / (x[1] - x[0]), but you can also look at the angle of the line:
phi = math.atan2(y[0] - y[1], x[0] - x[1])
The distance from one center to the other is given by
r = math.hypot(y[0] - y[1], x[0] - x[1])
Now you can easily step along the line from (x[0], y[0]) at an angle of phi in steps of 20 until your distance exceeds r. The x-coorindate of the i-th step will be
i * 20 * math.cos(phi)
Similarly the y-coordinate will be
i * 20 * math.sin(phi)
You can calculate the total number of steps as r // 20. Also, math.sin(math.atan2(y, x)) simplifies to y / math.hypot(y, x) and the similar cosine simplifies to x / math.hypot(y, x). So all in all, you get
sep = 20
dx = x[1] - x[0]
dy = y[1] - y[0]
r = math.hypot(dy, dx)
n = int(r // sep)
x_step = sep * dx / r
y_step = sep * dy / r
coords = [(x[0] + i * x_step, y[0] + i * y_step) for i in range(n)]
If you need integer coordinates:
coords = [(x[0] + int(i * x_step), y[0] + int(i * y_step)) for i in range(n)]
To plot:
for coord in [(x[0] + int(i * x_step), y[0] + int(i * y_step)) for i in range(n)]:
pygame.draw.circle(screen, linecolour, coord, 2)

How to draw cycloid on curve of other function (other cycloid)?

I would like to draw cycloid that is going on other cycloid but I don't know exactly how to do this. Here is my code.
import numpy as np
import matplotlib.pyplot as plt
import math
from matplotlib import animation
#r = float(input('write r\n'))
#R = float(input('write R\n'))
r = 1
R = 1
x = []
y = []
x2 = []
y2 = []
x3 = []
y3 = []
length=[0]
fig, ax = plt.subplots()
ln, = plt.plot([], [], 'r', animated=True)
f = np.linspace(0, 10*r*math.pi, 1000)
def init():
ax.set_xlim(-r, 12*r*math.pi)
ax.set_ylim(-4*r, 4*r)
return ln,
def update2(frame):
#parametric equations of cycloid
x0 = r * (frame - math.sin(frame))
y0 = r * (1 - math.cos(frame))
x.append(x0)
y.append(y0)
#derivative of cycloid
dx = r * (1 - math.cos(frame))
dy = r * math.sin(frame)
#center of circle
a = dy * dy + dx * dx
b = (-2 * x0 * dy) - (2 * frame * dy * dy) + (2 * y0 * dx) - (2 * frame * dx * dx)
c = (x0 * x0) + (2 * frame * x0 * dy) + (frame * frame * dy * dy) + (y0 * y0) - (2 * frame * y0 * dx) + (frame * frame * dx * dx) -1
t1 = (-b - math.sqrt(b * b - 4 * a * c)) / (2 * a)
#t2 = (-b + math.sqrt(b * b - 4 * a * c)) / (2 * a)
center1x=(x0-dy*(t1-x0))*R
center1y=(y0+dx*(t1-x0))*R
#center2x=(x0-dy*(t2-x0))*R
#center2y=(y0+dx*(t2-x0))*R
#length of cycloid
length.append(math.sqrt(x0*x0 + y0*y0))
dl=sum(length)
param = dl / R
W1x = center1x + R * math.cos(-param)
W1y = center1y + R * math.sin(-param)
#W2x = center2x + R * math.cos(-param)
#W2y = center2y + R * math.sin(-param)
x2.append(W1x)
y2.append(W1y)
#x3.append(W2x)
#y3.append(W2y)
ln.set_data([x, x2], [y, y2])
return ln,
ani = animation.FuncAnimation(fig, update2, frames=f,init_func=init, blit=True, interval = 0.1, repeat = False)
plt.show()
In my function update2 I created parametric equations of first cycloid and then tried to obtain co-ordinates of points of second cycloid that should go on the first one.
My idea is based on that that typical cycloid is moving on straight line, and cycloid that is moving on other curve must moving on tangent of that curve, so center of circle that's creating this cycloid is always placed on normal of curve. From parametric equations of normal I have tried to obtain center of circle that creating cycloid but I think that isn't good way.
My goal is to get something like this:
Here is one way. Calculus gives us the formulas to find the direction angles at any point on the cycloid and the arc lengths along the cycloid. Analytic Geometry tells us how to use that information to find your desired points.
By the way, a plot made by rolling a figure along another figure is called a roulette. My code is fairly simple and could be optimized, but it works now, can be used for other problems, and is broken up to make the math and algorithm easier to understand. To understand my code, use this diagram. The cycloid is the blue curve, the black circles are the rolling circle on the cycloid, point A is an "anchor point" (a point where the rim point touches the cycloid--I wanted to make this code general), and point F is the moving rim point. The two red arcs are the same length, which is what we mean by rolling the circle along the cycloid.
And here is my code. Ask if you need help with the source of the various formulas, but the direction angles and arc lengths use calculus.
"""Numpy-compatible routines for a standard cycloid (one caused by a
circle of radius r above the y-axis rolling along the positive x-axis
starting from the origin).
"""
import numpy as np
def x(t, r):
"""Return the x-coordinate of a point on the cycloid with parameter t."""
return r * (t - np.sin(t))
def y(t, r):
"""Return the y-coordinate of a point on the cycloid with parameter t."""
return r * (1.0 - np.cos(t))
def dir_angle_norm_in(t, r):
"""Return the direction angle of the vector normal to the cycloid at
the point with parameter t that points into the cycloid."""
return -t / 2.0
def dir_angle_norm_out(t, r):
"""Return the direction angle of the vector normal to the cycloid at
the point with parameter t that points out of the cycloid."""
return np.pi - t / 2.0
def arclen(t, r):
"""Return the arc length of the cycloid between the origin and the
point on the cycloid with parameter t."""
return 4.0 * r * (1.0 - np.cos(t / 2.0))
# Roulette problem
def xy_roulette(t, r, T, R):
"""Return the x-y coordinates of a rim point on a circle of radius
R rolling on a cycloid of radius r starting at the anchor point
with parameter T currently at the point with parameter t. (Such a
rolling curve on another curve is called a roulette.)
"""
# Find the coordinates of the contact point P between circle and cycloid
px, py = x(t, r), y(t, r)
# Find the direction angle of PC from the contact point to circle's center
a1 = dir_angle_norm_out(t, r)
# Find the coordinates of the center C of the circle
cx, cy = px + R * np.cos(a1), py + R * np.sin(a1)
# Find cycloid's arc distance AP between anchor and current contact points
d = arclen(t, r) - arclen(T, r) # equals arc PF
# Find the angle φ the circle turned while rolling from the anchor pt
phi = d / R
# Find the direction angle of CF from circle's center to rim point
a2 = dir_angle_norm_in(t, r) - phi # subtract: circle rolls clockwise
# Find the coordinates of the final point F
fx, fy = cx + R * np.cos(a2), cy + R * np.sin(a2)
# Return those coordinates
return fx, fy
import matplotlib.pyplot as plt
r = 1
R = 0.75
T = np.pi / 3
t_array = np.linspace(0, 2*np.pi, 201)
cycloid_x = x(t_array, r)
cycloid_y = y(t_array, r)
roulette_x, roulette_y = xy_roulette(t_array, r, T, R)
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.axhline(y=0, color='k')
ax.axvline(x=0, color='k')
ax.plot(cycloid_x, cycloid_y)
ax.plot(roulette_x, roulette_y)
plt.show()
And here is the resulting graphic. You can pretty this up as you choose. Note that this only has the circle rolling along one arch of the cycloid. If you clarify what should happen at the cusps, this could be extended.
Or, if you want a smaller circle and a curve that ends at the cusps (here r = 1, T = 0 n = 6 (the number of little arches), and R = 4 * r / np.pi / n),
You can generate coordinates of the center of rolling circle using parallel curve definition. Parametric equations for this center are rather simple (if I did not make mistakes):
for big cycloid:
X = R(t - sin(t))
Y = R(1 - cos(t))
X' = R(1 - cos(t))
Y' = R*sin(t)
parallel curve (center of small circle):
Sqrt(X'^2+Y'^2)=R*Sqrt(1-2*cos(t)+cos^2(t)+sin^2(t)) =
R*Sqrt(2-2*cos(t))=
R*Sqrt(4*sin^2(t/2))=
2*R*sin(t/2)
x(t) = X(t) + r*R*sin(t)/(2R*sin(t/2)) =
R(t - sin(t)) + r*2*sin(t/2)*cos(t/2) / (2*sin(t/2)) =
R(t - sin(t)) + r*cos(t/2)
y(t) = Y(t) - r*R*(1-cos(t))/(2*R*sin(t/2)) =
R(1 - cos(t)) - r*(2*sin^2(t/2)/(2*sin(t/2)) =
R(1 - cos(t)) - r*sin(t/2)
But trajectory of point on the circumference is superposition of center position and rotation around it with angular velocity that depends on length of main cycloid plus rotation of main tangent.
Added from dicussion in comments:
cycloid arc length
L(t) = 4R*(1-cos(t/2))
to use it for small circle rotation, divide by r
tangent rotation derivation
fi(t) = atan(Y'/X') = atan(sin(t)/(1-cos(t)) =
atan(2*sin(t/2)*cos(t/2)/(2(sin^2(t/2))) =
atan(ctg(t/2)) = Pi/2 - t/2
so tangent direction change is proportional to big cycloid parameter
and final result is (perhaps some signs are not correct)
theta(t) = L(t)/r + t/2 + Phase
ox(t) = x(t) + r * cos(theta(t))
oy(t) = y(t) + r * sin(theta(t))
Thanks everyone. Somehow I have managed to accomplish that. Solution is maybe ugly but sufficient for me.
import numpy as np
import matplotlib.pyplot as plt
import math
from matplotlib import animation
r = float(input('write r\n'))
R = float(input('write R\n'))
#r=1
#R=0.1
x = []
y = []
x2 = []
y2 = []
x_1=0
x_2=0
lengthX=[0]
lengthY=[0]
lengthabs=[0]
fig, ax = plt.subplots()
ln, = plt.plot([], [], 'r', animated=True)
f = np.linspace(0, 2*math.pi, 1000)
def init():
ax.set_xlim(-r, 4*r*math.pi)
ax.set_ylim(0, 4*r)
return ln,
def update2(frame):
#cycloid's equations
x0 = r * (frame - math.sin(frame))
y0 = r * (1 - math.cos(frame))
x.append(r * (frame - math.sin(frame)))
y.append(r * (1 - math.cos(frame)))
#arc's length
lengthabs.append(math.sqrt((x0-lengthX[-1])*(x0-lengthX[-1])+(y0-lengthY[-1])*(y0-lengthY[-1])))
lengthX.append(x0)
lengthY.append(y0)
dl=sum(lengthabs)
param = dl / R
#center of circle
center1x = r * (frame - math.sin(frame)) + R * math.cos((frame+2*math.pi) / 2)
center1y = r * (1 - math.cos(frame)) - R * math.sin((frame+2*math.pi) / 2)
if(frame<2*math.pi):
W1x = center1x + R * math.cos(-param)
W1y = center1y + R * math.sin(-param)
else:
W1x = center1x + R * math.cos(param)
W1y = center1y + R * math.sin(param)
x2.append(W1x)
y2.append(W1y)
ln.set_data([x,x2], [y,y2])
return ln,
ani = animation.FuncAnimation(fig, update2, frames=f,init_func=init, blit=True, interval = 0.1, repeat = False)
plt.show()

Generate random point positons on a torus

I'm working on a code to simulate propagation of particles on a torus surface. Initially, particles are gather on a "local" space, as shown on the following pic :
Blue points are initial particles. The problem is, when I zoom in, particles don't seem to be spread randomly :
First, I see they form like raws. Moreover, I'm working with N = 5 particles, but there seems to be 25 particles here (5 raws of 5). I suppose it comes from meshgrid() since 25 = 5^2, but I don't really understand how this function works to be honest.
Here is my code :
Creating the red torus :
angle = np.linspace(0, 2*np.pi, 32)
theta, phi = np.meshgrid(angle, angle)
X = (R + r * np.cos(phi)) * np.cos(theta)
Y = (R + r * np.cos(phi)) * np.sin(theta)
Z = r * np.sin(phi)
Placing initial points :
thetaInit = ((np.random.rand(N)-0.5)*np.pi/16)
phiInit = ((np.random.rand(N)-0.5)*np.pi/32)
theta2, phi2 = np.meshgrid(phiInit, thetaInit)
Xinit = (R + r * np.cos(phi2)) * np.cos(theta2)
Yinit = (R + r * np.cos(phi2)) * np.sin(theta2)
Zinit = r * np.sin(phi2)
Where N is the number of particles, and r, R are respectively minor and major radius of the torus.

Python program to create sphere coordinates not working

I am trying to generate points that lies on the surface of a sphere centered on (0,0) in python.
# r - the radius of the sphere
def createSphere(r):
lst = []
for z in range(-r, r+1):
r_ = r - abs(z)
if r_ == 0:
lst.append((0,0,r*np.sign(z)))
else:
for d in range(r_):
lst.append((r_ * cos(d * (360/float(r_))), r_ * sin(d * 360/float(r_))), z) )
return lst
It will return a list [(x1,y1,z1),...].
This is how the result looks like:
The surface isn't smooth, and it looks kinda like a cube with extra sharp corners.
Does anyone know whats wrong?
Thanks
Use the standard spherical to cartesian coordinate transformation:
import math
pi = math.pi
sin = math.sin
cos = math.cos
def createSphere(r, N=10):
lst = []
thetas = [(2*pi*i)/N for i in range(N)]
phis = [(pi*i)/N for i in range(N)]
for theta in thetas:
for phi in phis:
x = r * sin(phi) * cos(theta)
y = r * sin(phi) * sin(theta)
z = r * cos(phi)
lst.append((x, y, z))
return lst
Per the comments below: If you wish to vary the number of points depending on the height (or phi), you could let thetas depend on phi:
def createSphere(r, N=10):
lst = []
for phi in [(pi*i)/(N-1) for i in range(N)]:
M = int(sin(phi)*(N-1))+1
for theta in [(2*pi*i)/M for i in range(M)]:
x = r * sin(phi) * cos(theta)
y = r * sin(phi) * sin(theta)
z = r * cos(phi)
lst.append((x, y, z))
return lst
Above, the key line is
M = int(sin(phi)*(N-1))+1
M will equal 1 when phi is 0 or pi, and it will equal N when phi equals pi/2 (at the "equator"). Note that this is just one possible way to define M. Instead of using sin, you could instead define a piecewise linear function with the same boundary values, for example...

Categories

Resources