Related
Programming in Python (Blender):
I want to create a square and print all vertices (A;B;C;D) into my console on top of a given Vector. The square should be orthogonal to this vector, like this:
def create_verts_around_point(radius, vert):
# given Vector
vec = np.array([vert[0], vert[1], vert[2]])
# side_length of square
side_length = radius
# Vctor x-direction (1,0,0)
x_vec = np.array([1,0,0])
# Vekctor y-direction (0,1,0)
y_vec = np.array([0,1,0])
# Vector z-direction (0,0,1)
z_vec = np.array([0,0,1])
p1 = vec + (side_length/2) * x_vec + (side_length/2) * y_vec + (side_length/2) * z_vec
p2 = vec - (side_length/2) * x_vec + (side_length/2) * y_vec + (side_length/2) * z_vec
p3 = vec - (side_length/2) * x_vec - (side_length/2) * y_vec + (side_length/2) * z_vec
p4 = vec + (side_length/2) * x_vec - (side_length/2) * y_vec + (side_length/2) * z_vec
But my output looks like this in the end (Square is always parallel to my x-axis and y-axis):
I don't think you're really thinking about this problem in 3D, but see if this is close.
I create a square, perpendicular to the X axis. I then rotate that square based on the angles in x, y, and z. I then position the square at the end of the vector and plot it. I add plot points for the origin and the end of the vector, and I duplicate the last point in the square do it draws all the lines.
import math
import numpy as np
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
def create_verts_around_point(sides, vert):
x0, y0, z0 = vert
# Here is the unrotated square.
half = sides/2
square = [
[0, -half,-half],
[0, -half, half],
[0, half, half],
[0, half,-half],
]
# Now find the rotation in each direction.
thetax = math.atan2( z0, y0 )
thetay = math.atan2( z0, x0 )
thetaz = math.atan2( y0, x0 )
# Now rotate the cube, first in x.
cubes = []
txcos = math.cos(thetax)
txsin = math.sin(thetax)
tycos = math.cos(thetay)
tysin = math.sin(thetay)
tzcos = math.cos(thetaz)
tzsin = math.sin(thetaz)
for x,y,z in square:
x,y,z = (x, y * txcos - z * txsin, y * txsin + z * txcos)
x,y,z = (x * txcos - z * txsin, y, x * txsin + z * txcos)
x,y,z = (x * txcos - y * txsin, x * txsin + y * txcos, z)
cubes.append( (x0+x, y0+y, z0+z) )
return cubes
point = (10,10,10)
square = create_verts_around_point(5, point)
points = [(0,0,0),point] + square + [square[0]]
x = [p[0] for p in points]
y = [p[1] for p in points]
z = [p[2] for p in points]
ax = plt.figure().add_subplot(111, projection='3d')
ax.plot( x, y, z )
plt.show()
Output:
I am using holoviews+bokeh, and I would like to encircle my scatter plot data with a measure of standard deviation. Unfortunately I can't seem to get the orientation setting right. I am confused by the available descriptions:
Orientation in the Cartesian coordinate system, the
counterclockwise angle in radians between the first axis and the
horizontal
and
you can set the orientation (in radians, rotating anticlockwise)
My script and data example:
def create_plot(x, y, nstd=5):
x, y = np.asarray(x), np.asarray(y)
cov_matrix = np.cov([x, y])
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
order = eigenvalues.argsort()[0]
angle = np.arctan2(eigenvectors[1, order], eigenvectors[1, order])
x0 = np.mean(x)
y0 = np.mean(y)
x_dir = np.cos(angle) * x - np.sin(angle) * y
y_dir = np.sin(angle) * x + np.cos(angle) * y
w = nstd * np.std(x_dir)
h = nstd * np.std(y_dir)
return hv.Ellipse(x0, y0, (w, h), orientation=-angle) * hv.Scatter((x, y))
c2x = np.random.normal(loc=-2, scale=0.6, size=200)
c2y = np.random.normal(loc=-2, scale=0.1, size=200)
combined = create_plot(c2x, c2y)
combined.opts(shared_axes=False)
Here is a solution, which draws Ellipse around the data. You math is just simplified.
import numpy as np
import holoviews as hv
from holoviews import opts
hv.extension('bokeh')
x = np.random.normal(loc=-2, scale=0.6, size=200)
y = np.random.normal(loc=-2, scale=0.1, size=200)
def create_plot(x, y, nstd=5):
x, y = np.asarray(x), np.asarray(y)
x0 = np.mean(x)
y0 = np.mean(y)
w = np.std(x)*nstd
h = np.std(y)*nstd
return hv.Ellipse(x0, y0, (w, h)) * hv.Scatter((x, y))
combined = create_plot(c2x, c2y)
combined.opts()
This gives you a plot which looks like a circle. To make it more visiable that it is a Ellipse your could genereate the plot calling
def hook(plot, element):
plot.handles['x_range'].start = -4
plot.handles['x_range'].end = 0
plot.handles['y_range'].start = -2.5
plot.handles['y_range'].end = -1
combined.opts(hooks=[hook])
which set fixed ranges and deactivates the auto focus.
In your example w and h were nearly the same, that means, you drawed a cercle. The orientation didn't have any effect. With the code above you can turn the Ellipse like
hv.Ellipse(x0, y0, (w, h), orientation=np.pi/2)
to see that it is working, but there is no need to do it anymore.
I am trying to simulate a particle under the central force $a_c = - k_r r^n \hat r$
however, I am encountering the error that my angle theta would be divided by zero sometimes
theta = np.arctan((r_US[1]-y_0)/(r_US[0]-x_0))
as well as the invalid value error for my definition of my distance
distance = np.sqrt((r_US[0]-x_0) + (r_US[1] - y_0))
what would be a better definition suited for the python code? Thanks for the answers, below is the complete code
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams["animation.html"] = 'jshtml'
import matplotlib.animation
import numpy as np
from ipywidgets import interactive
def MotionAnimation4(xstart,ystart,vxstart,vystart, n, k): #4
xMin = 0.
xMax = 5.
yMin = 0.
yMax = 5.
x_0 = 2.5
y_0 = 2.5 #defining the center of the circle
def UpdatedState(r_US, v_US, a_US, Delta_t_US):
distance = np.sqrt((r_US[0]-x_0)**2 + (r_US[1] - y_0)**2) #updating the distance to the center of the circle
theta = np.arctan((r_US[1]-y_0)/(r_US[0]-x_0)) #defining angle relative to the center of the circle
r_US = r_US + v_US * Delta_t_US
a_x = -k * (distance**n) * np.cos(theta)
a_y = -k * (distance**n) * np.sin(theta)
central_acceleration = np.array([[a_x, a_y]]) #defining central acceleration in cartesian coordinate
if r_US[0] > xMax:
r_US[0] = xMax - (r_US[0] - xMax)
v_US[0] = -v_US[0]
if r_US[0] < xMin:
r_US[0] = xMin - (r_US[0] - xMin)
v_US[0] = -v_US[0]
if r_US[1] > yMax:
r_US[1] = yMax - (r_US[1] - yMax)
v_US[1] = -v_US[1]
if r_US[1] < yMin:
r_US[1] = yMin - (r_US[1] - yMin)
v_US[1] = -v_US[1]
a_US = central_acceleration
v_US = v_US + a_US * Delta_t_US
return r_US, v_US, a_US
Delta_t = 0.05
NumFrames = 100
Frames = np.arange(NumFrames)
xStart = xstart
yStart = ystart
vxStart = vxstart
vyStart = vystart
r = np.array([[xStart , yStart]])
v = np.array([[vxStart , vyStart]])
a = np.array([[0, 0]])
for i in Frames:
rnew, vnew, anew = UpdatedState(r[-1], v[-1], a[-1], Delta_t)
r = np.vstack((r,rnew))
v = np.vstack((v,vnew))
a = np.vstack((a, anew))
fig, ax = plt.subplots()
dot, = plt.plot([],[],'-ro')
def InitAniPlot():
ax.axis([xMin,xMax,yMin,yMax])
ax.set_aspect('equal')
return dot,
def UpdatedAniPlot(i):
dot.set_data(r[i,0], r[i,1])
return dot,
ani = matplotlib.animation.FuncAnimation(fig,UpdatedAniPlot, frames = Frames, init_func = InitAniPlot)
return ani
MotionAnimation4(2.5, 4., 1., 1., 2., 2)
p.s how would I apply latex for formulas in this stack exchange?
I replaced
theta = np.arctan((r_US[1]-y_0)/(r_US[0]-x_0))
with
theta = np.arctan2((r_US[1]-y_0), (r_US[0]-x_0))
and the code worked as intended
I am trying to rewrite this article:We draw, programming. Machine-generated generation of artistic patterns in vector fields (Russian language) from pseudo-code in Python. I am new to ML, hence the following question arises: How to build a grid of angles and output it through PyCharm? I am at this stage:
import numpy as np
import math
import matplotlib.pyplot as plt
width = 100
height = 100
left_x = int(width * -0.5)
right_x = int(width * 1.5)
top_y = int(height * -0.5)
bottom_y = int(height * 1.5)
resolution = int(width * 0.01)
num_columns = int((right_x - left_x) / resolution)
num_rows = int((bottom_y - top_y) / resolution)
grid=np.ndarray((num_columns, num_rows))
grid[:,:]=math.pi * 0.25
In this code, I create a grid array in which 200 rows and 200 columns, into which the angle 'default_angle' is inserted. Please tell me whether I’m moving in the right direction and how to "draw" a grid, as in an attached link. So far I think I need to use matplotlib.
I believe you need to take a look at meshgrid from numpy
from the meshgrid documentation examples:
x = np.arange(-5, 5, 0.1)
y = np.arange(-5, 5, 0.1)
xx, yy = np.meshgrid(x, y, sparse=True)
z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2)
h = plt.contourf(x,y,z)
Edit. After seeing you r link a better resource is the matplotlib quiver demo
import matplotlib.pyplot as plt
import numpy as np
X = np.arange(-10, 10, 1)
Y = np.arange(-10, 10, 1)
U, V = np.meshgrid(X, Y)
fig, ax = plt.subplots()
q = ax.quiver(X, Y, U, V)
ax.quiverkey(q, X=0.3, Y=1.1, U=10,
label='Quiver key, length = 10', labelpos='E')
plt.show()
You need to make several steps to recreate this:
create vector field based on some function or equation
normalize arrows for proper display
draw line
3.1. set starting parameters
3.2. set while out condition
3.3. calculate new position based on angle from starting point
3.4. get new position index --> net new angle
3.5. update starting positions
draw vector field and line
import numpy as np
import matplotlib.pyplot as plt
size = 50
X = np.arange(1, size, 1)
Y = np.arange(1, size, 1)
U, V = np.meshgrid(X, Y)
# Normalize the arrows:
U = U / np.sqrt(U**2 + V**2)
V = V / np.sqrt(U**2 + V**2)
# create angles field
data = []
for i in np.linspace(0, 180, Y.shape[0]):
data.append([i]*X.shape[0])
angle = np.array(data)
# set starting parameters
x_start_position = 2
y_start_position = 2
step_length = 1.0
point_angle = angle[x_start_position, y_start_position]
line_coordinates = [[x_start_position, y_start_position]]
# collect line points for each step
while x_start_position >= 2:
# calculate tep based on angle
x_step = step_length * np.cos(point_angle*np.pi/180)
y_step = step_length * np.sin(point_angle*np.pi/180)
# calculate new position
x_new_position = x_start_position + x_step
y_new_position = y_start_position + y_step
# get array index of new position
x_new_index = int(x_new_position)
y_new_index = int(y_new_position)
# get new angle
point_angle = angle[y_new_index, x_new_index]
# update start position
x_start_position = x_new_position
y_start_position = y_new_position
# collect results
line_coordinates.append([x_new_position, y_new_position])
# set line coordinates
line_data = np.array(line_coordinates)
x_line = line_data[:,0]
y_line = line_data[:,1]
# plot field
plt.quiver(X, Y, U, V, color='black', angles=angle, width=0.005)
# plot line
plt.plot(x_line, y_line, '-', color='red')
plt.show()
Output:
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()