Random function in python to generate random pair inside a circle - python-3.x

In python how to generate a random pair of points (x,y) that lies inside a circle of radius r.
Basically the x and y should satisfy the condition x^2 + y^2 = r^2.

To generate uniformly distributed point inside origin-centered circle of radius r, you can generate two uniform values t,u in range 0..1 and use the next formula:
import math, random
r = 4
t = random.random()
u = random.random()
x = r * math.sqrt(t) * math.cos(2 * math.pi * u)
y = r * math.sqrt(t) * math.sin(2 * math.pi * u)
print (x,y)

Using numpy to generate more than one point at a time:
import numpy as np
import matplotlib.pyplot as plt
n_samples = 1000
r = 4
# make a simple unit circle
theta = np.linspace(0, 2*np.pi, n_samples)
a, b = r * np.cos(theta), r * np.sin(theta)
t = np.random.uniform(0, 1, size=n_samples)
u = np.random.uniform(0, 1, size=n_samples)
x = r*np.sqrt(t) * np.cos(2*np.pi*u)
y = r*np.sqrt(t) * np.sin(2*np.pi*u)
# Plotting
plt.figure(figsize=(7,7))
plt.plot(a, b, linestyle='-', linewidth=2, label='Circle', color='red')
plt.scatter(x, y, marker='o', label='Samples')
plt.ylim([-r*1.5,r*1.5])
plt.xlim([-r*1.5,r*1.5])
plt.grid()
plt.legend(loc='upper right')
plt.show(block=True)
which results in:

Related

Slider is not updating my diagram correctly

I am trying to plot the biffurcation diagram and its equation.
My problem is that I want to put a slider for when I change the rate in the logistic map equation, but I can't seem to understand what I need to code in the update function.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
rate = np.linspace(1, 4, 1000)
N = 1000
x = np.zeros(N) + 0.5
count = np.arange(round(N*0.9), N)
y = np.zeros(N) + 0.5
#t = 1
# Biffurcation
for rs in range(len(rate)):
for n in range(N-1):
x[n+1] = rate[rs] * x[n] * (1-x[n])
u = np.unique(x[count])
r = rate[rs] * np.ones(len(u))
for i in range(N - 1):
y[i + 1] = rate[rs] * y[i] * (1 - y[i])
# plotting
plt.plot(r, u, '.', markersize=2)
plt.ylabel(ylabel='X')
plt.xlabel(xlabel='r')
plt.title('Biffurcation')
# Plotting
fig, ax = plt.subplots()
axes, = ax.plot(y, 'o-')
ax.set_ylabel(ylabel='X')
ax.set_xlabel(xlabel='Time')
ax.set_title('$x_{n+1}$ = r * $x_{n}$ * (1-$x_{n}$)')
# defining axSlider
fig.subplots_adjust(bottom=0.25)
ax_slider = fig.add_axes([0.15, 0.1, 0.65, 0.03])
slider = Slider(ax_slider, label='r', valmin=1, valmax=4, valinit=1, valstep=rate)
# updating the plot
def update(val):
current_v = slider.val
rate[rs] = current_v
axes.set_ydata(rate[rs])
fig.canvas.draw()
slider.on_changed(update)
plt.show()
I tried to update my plot for when I change the rate on my slider, but it is not working properly.
def update(val):
current_v = slider.val
rate[rs] = current_v
axes.set_ydata(rate[rs])
fig.canvas.draw()

Function to generate more than one random point in a given circle

So I have defined a fucntion to generate a random number in a given circle:
def rand_gen(R,c):
# random angle
alpha = 2 * math.pi * random.random()
# random radius
r = R * math.sqrt(random.random())
# calculating coordinates
x = r * math.cos(alpha) + c[0]
y = r * math.sin(alpha) + c[1]
return (x,y)
Now I want to add a parameter n (rand_gen(R,c,n)) such that we can get n such numbers instead of one
You can achieve that goal also using generator function:
import random
import math
def rand_gen(R,c,n):
while n:
# random angle
alpha = 2 * math.pi * random.random()
# random radius
r = R * math.sqrt(random.random())
# calculating coordinates
x = r * math.cos(alpha) + c[0]
y = r * math.sin(alpha) + c[1]
n -= 1
yield (x,y)
points_gen = rand_gen(10, (3,4), 4)
for point in points_gen:
print(point)
points = [*rand_gen(10, (3,4), 4)]
print(points)
If you want to generate n random points, you can extend your function with a parameter and for-loop:
import math
import random
def rand_gen(R, c, n):
out = []
for i in range(n):
# random angle
alpha = 2 * math.pi * random.random()
# random radius
r = R * math.sqrt(random.random())
# calculating coordinates
x = r * math.cos(alpha) + c[0]
y = r * math.sin(alpha) + c[1]
out.append((x,y))
return out
print(rand_gen(10, (3, 4), 3))
Prints (for example):
[(-4.700562169626218, 5.62666979720004), (6.481518730246707, -1.849892172014873), (0.41713910134636345, -1.9065302305716285)]
But better approach in my opinion would be leave the function as is and generate n points using list comprehension:
lst = [rand_gen(10, (3, 4)) for _ in range(3)]
print(lst)
Prints:
[(-1.891474340814674, -2.922205399732765), (12.557063558442614, 1.9323688240857821), (-5.450160078420653, 7.974550456763403)]

How to draw a semicircle using matplotlib

I want to draw a semicircle using matplotlib.
Here I have a court
import numpy as np
import matplotlib.pyplot as plt
x_asix = np.array([0,0,100,100, 0])
y_asix = np.array([0,100,100,0, 0])
x_coordenates = np.concatenate([ x_asix])
y_coordenates = np.concatenate([y_asix])
plt.plot(x_coordenates, y_coordenates)
See image here:
I want to add one semicircle that stars at point (0,50) with radius = 10.
The result should be something like this:
Here is a function that draws semicircles, using numpy:
import matplotlib.pyplot as plt
import numpy as np
def generate_semicircle(center_x, center_y, radius, stepsize=0.1):
"""
generates coordinates for a semicircle, centered at center_x, center_y
"""
x = np.arange(center_x, center_x+radius+stepsize, stepsize)
y = np.sqrt(radius**2 - x**2)
# since each x value has two corresponding y-values, duplicate x-axis.
# [::-1] is required to have the correct order of elements for plt.plot.
x = np.concatenate([x,x[::-1]])
# concatenate y and flipped y.
y = np.concatenate([y,-y[::-1]])
return x, y + center_y
example:
x,y = generate_semicircle(0,50,10, 0.1)
plt.plot(x, y)
plt.show()
You could simply use the equation of the ellipse, to easily draw the portion of the ellipse you are interested in.
If you want to draw the part of the ellipse you have in your image, unfortunately you cannot simply write it as: y = f(x), but you can use the common trick of plotting x = f(y) instead:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1)
ax.set_aspect('equal')
x_asix = np.array([0,0,100,100, 0])
y_asix = np.array([0,100,100,0, 0])
x_coordenates = np.concatenate([ x_asix])
y_coordenates = np.concatenate([y_asix])
ax.plot(x_coordenates, y_coordenates)
# ((x - x0) / a) ** 2 + ((y - y0) / b) ** 2 == 1
a = 20
b = 15
x0 = 50
y0 = 0
x = np.linspace(-a + x0, a + x0)
y = b * np.sqrt(1 - ((x - x0) / a) ** 2) + y0
ax.plot(y, x)

How to plot equation

How to plot these equations please? The output is empty - there are only axes but no line
import numpy as np
import matplotlib.pyplot as plt
r = 50
a = 5
n = 20
t = 5
x = (r + a * np.sin(n * t * 360 )) * np.cos (t * 360 )
y = (r + a * np.sin(n * t * 360 )) * np.sin (t * 360 )
fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()
You are currently just calculating single values for x and y:
>>> import numpy as np
>>> r, a, n, t = 50, 5, 20, 5
>>> x = (r + a * np.sin(n * t * 360 )) * np.cos (t * 360 )
>>> y = (r + a * np.sin(n * t * 360 )) * np.sin (t * 360 )
>>> print(x, y)
-47.22961311822641 6.299155241288046
This means there is no line for matplotlib to plot.
To plot a line, you have to pass two or more points for matplotlib to draw lines between.
import matplotlib.pyplot as plt
import numpy as np
t = np.linspace(0, 2*np.pi, 100) # create an array of 100 points between 0 and 2*pi
x = np.sin(2*t)
y = np.cos(t)
plt.plot(x, y)
plt.show()
Or in your case:
t = np.linspace(0, 2*np.pi, 1000)
# removed the factor *360 as numpy's sin/cos works with radians by default
x = (r + a * np.sin(n * t)) * np.cos(t)
y = (r + a * np.sin(n * t)) * np.sin(t)
plt.plot(x, y)
plt.show()
You are evaluating the function just at t=5. You should give a range of values to evaluate. If you change t variable to, for example
t= np.array([0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1])
you will see a graph. But it is up to you to define the range and the step for your needs

Animating multiple Circles in each frames in Python

I am trying to create the animation in this video using Python. But I stuck on the very first step. Till now I've created a Circle and a point rotating around its circumference. My code is given below. Now I want to plot the y values corresponding to x=np.arange(0, I*np.pi, 0.01) along the x-axis (as shown in update() function in the code). For this I have to define another function to plot these x and y and pass that function inside a new animation.FuncAnimation().
Is there any way to plot everything using only the update() function?
Note I have found a code of this animation in here. But it is written in Java!
My Code
import matplotlib.pyplot as plt
from matplotlib import animation
import numpy as np
W = 6.5
H = 2
radius = 1
I = 2
T = 3
N = 2
plt.style.use(['ggplot', 'dark_background'])
def create_circle(x, y, r):
circle = plt.Circle((x, y), radius=r, fill=False, alpha=0.7, color='w')
return circle
def create_animation():
fig = plt.figure()
ax = plt.axes(xlim=(-2, W + 2), ylim=(-H, H))
circle = create_circle(0, 0, radius)
ax.add_patch(circle)
line1, = ax.plot(0, 1, marker='o', markersize=3, color='pink', alpha=0.7)
def update(theta):
x = radius * np.cos(theta)
y = radius * np.sin(theta)
line1.set_data([0, x], [0, y])
return line1,
anim = []
anim.append(animation.FuncAnimation(fig, update,
frames=np.arange(0, I * np.pi, 0.01),
interval=10, repeat=True))
# anim.append(animation.FuncAnimation(fig, update_line, len(x),
# fargs=[x, y, line, line1], interval=10))
plt.grid(False)
plt.gca().set_aspect('equal')
plt.gca().spines['left'].set_visible(False)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['bottom'].set_visible(False)
plt.gca().set_xticks([])
plt.gca().set_yticks([])
plt.show()
if __name__ == '__main__':
create_animation()
Edit. I've improved the task by defining a global variable pos and changing the update() function in the following manner ...The animation now looks better but still having bugs!
Improved Portion
plot, = ax.plot([], [], color='w', alpha=0.7)
level = np.arange(0, I * np.pi, 0.01)
num = []
frames = []
for key, v in enumerate(level):
num.append(key)
frames.append(v)
def update(theta):
global pos
x = radius * np.cos(theta)
y = radius * np.sin(theta)
wave.append(y)
plot.set_data(np.flip(level[:pos] + T), wave[:pos])
line1.set_data([0, x], [0, y])
pos += 1
return line1, plot,
Edit Till now I've done the following:
def update(theta):
global pos
x, y = 0, 0
for i in range(N):
prev_x = x
prev_y = y
n = 2 * i + 1
rad = radius * (4 / (n * np.pi))
x += rad * np.cos(n * theta)
y += rad * np.sin(n * theta)
wave.append(y)
circle = create_circle(prev_x, prev_y, rad)
ax.add_patch(circle)
plot.set_data(np.flip(level[:pos] + T), wave[:pos])
line2.set_data([x, T], [y, y])
line1.set_data([prev_x, x], [prev_y, y])
pos += 1
return line1, plot, line2,
Output
Please help to correct this animation. Or, is there any efficient way to do this animation?
Edit Well, now the animation is partially working. But there is a little issue: In my code (inside the definition of update()) I have to add circles centered at (prev_x, prev_y) of radius defined as rad for each frame. For this reason I try to use a for loop in the definition of update() but then all the circles remains in the figure (see the output below). But I want one circle in each frame with the centre and radius as mentioned above. Also the same problem is with the plot. I try to use ax.clear() inside the for loop but it didn't work.

Resources