I need help to make an optimization graph in 3 dimensions with manim. I am having difficulty understanding how to use the projection methods and to represent the axes and data in three-dimensional space. If anyone has experience with manim and can help me understand how to do it, I would greatly appreciate it. Thank you
Note: I am trying to graph the schewefel function below I attach part of the code that I have been working on
%%manim -qm -v WARNING AckleyAnimation
class Schewefel(ThreeDScene):
def func(self,u,v):
return x * np.sin(np.sqrt(np.abs(x))) + y * np.sin(np.sqrt(np.abs(y)))
def construct(self):
cielo = '#C4DDFF'
azul = '#001D6E'
rojo = "#B20600"
axes = ThreeDAxes()
self.set_camera_orientation(phi=65*DEGREES,theta=60*DEGREES)
# self.add(axes,x,y)
name_function = Tex(r"Schwefel function." ,font_size=38).to_corner(UL)
self.add_fixed_in_frame_mobjects(name_function)
funcion = MathTex(r"f(x) = 418.9829d - \sum_{i=1}^{d} x_i \sin \sqrt{|x_i|}", font_size=30).to_corner(UL)
self.play(Write(name_function))
self.play(FadeOut(name_function))
self.add_fixed_in_frame_mobjects(funcion)
self.play(Write(funcion))
surface_plane = Surface(
lambda u, v: np.array([u, v, self.func(u, v)]),
u_range=[-100,100],
v_range=[-100,100],
resolution=(50, 50))
self.play(Write(surface_plane))
Graphics
function Schewefel
Correction:
So far I modified the script and I have the following
%%manim -qm -v WARNING PlotSurfaceExample
class PlotSurfaceExample(ThreeDScene):
def construct(self):
resolution_fa = 16
self.set_camera_orientation(phi=75 * DEGREES, theta=-60 * DEGREES)
axes = ThreeDAxes(x_range=(-500, 500, 1800), y_range=(-500, 500, 1800), z_range=(-500, 500, 1800))
def param_trig(u, v):
x = u
y = v
z = x * np.sin(np.sqrt(np.abs(x))) + y * np.sin(np.sqrt(np.abs(y)))
return z
trig_plane = axes.plot_surface(
param_trig,
resolution=(resolution_fa, resolution_fa),
u_range = (-500, 500),
v_range = (-500, 500),
colorscale = [BLUE, GREEN, YELLOW, ORANGE, RED],
)
self.add(axes)
self.play(Write(trig_plane))
but it gives me this result
but nevertheless I hope this
Related
I'm trying to straiting out a ring using Manim Community. I want to acheive an animation exactly like this straiting a ring. I followed the code source of this video but the out put is not exactly the same (I used Manim Community and manimgl). Here is the code
class CircleScene(Scene):
def get_ring(self, radius=1, dR=0.1, color = GREEN):
ring = Circle(radius = radius + dR)
inner_ring = Circle(radius = radius)
inner_ring.rotate(np.pi,RIGHT)
ring.append_vectorized_mobject(inner_ring)
ring.set_stroke(width = 0)
ring.set_fill(color,1)
ring.R = radius
ring.dR = dR
return ring
def get_unwrapped(self, ring, to_edge = LEFT, **kwargs):
R = ring.R
R_plus_dr = ring.R + ring.dR
n_anchors = ring.get_num_curves()
result = VMobject()
points=[
interpolate(np.pi*R_plus_dr*LEFT, np.pi*R_plus_dr*RIGHT, a)
for a in np.linspace(0, 1, n_anchors // 2)
]+[
interpolate(np.pi*R*RIGHT+ring.dR*UP, np.pi*R*LEFT+ring.dR*UP, a)
for a in np.linspace(0, 1, n_anchors//2)
]
result.set_points_as_corners(points)
result.set_stroke(color=ring.get_fill_color(), width= ring.get_stroke_width()),
result.set_fill( color=ring.get_fill_color() , opacity=ring.get_fill_opacity()),
return result
class Example(CircleScene):
def construct(self,**kwargs):
circle=self.get_ring(1.5,0.1).rotate(PI/2);
line=self.get_unwrapped(circle).to_edge(DOWN)
self.play(Transform(circle,line))
I know that we can strait a circle to a line using the following code
circle=Circle(1).rotate(PI/2);
line=Line((-PI,-2,0),(PI,-2,0))
self.play(Transform(circle,line))
I pretty much deleted the last code and started new. I added a new class called Object which is the replacement for the lists called body_1 and body_2. Also all the calculations are now done from within the Object class. Most previous existing issues were resolved through this process but there is still one that presists. I believe its inside the StartVelocity() function which creates the v1/2 needed to start the Leapfrog algorithm. This should give me a geostationary Orbit but as clearly visible the Satelite escapes very quickly after zooming through earth.
Codes are:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from object import Object
import numpy as np
class Simulation:
def __init__(self):
# Index: 0 Name, 1 Position, 2 Velocity, 3 Mass
body_1 = Object("Earth", "g", "r",
np.array([[0.0], [0.0], [0.0]]),
np.array([[0.0], [0.0], [0.0]]),
5.9722 * 10**24)
body_2 = Object("Satelite", "b", "r",
np.array([[42164.0], [0.0], [0.0]]),
np.array([[0.0], [3075.4], [0.0]]),
5000.0)
self.bodies = [body_1, body_2]
def ComputePath(self, time_limit, time_step):
time_range = np.arange(0, time_limit, time_step)
for body in self.bodies:
body.StartVelocity(self.bodies, time_step)
for T in time_range:
for body in self.bodies:
body.Leapfrog(self.bodies, time_step)
def PlotObrit(self):
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for body in self.bodies:
body.ReshapePath()
X, Y, Z = [], [], []
for position in body.path:
X.append(position[0])
Y.append(position[1])
Z.append(position[2])
ax.plot(X, Y, Z, f"{body.linecolor}--")
for body in self.bodies:
last_pos = body.path[-1]
ax.plot(last_pos[0], last_pos[1], last_pos[2], f"{body.bodycolor}o", label=body.name)
ax.set_xlabel("x-Axis")
ax.set_ylabel("y-Axis")
ax.set_zlabel("z-Axis")
ax.legend()
fig.savefig("Leapfrog.png")
if __name__ == "__main__":
sim = Simulation()
sim.ComputePath(0.5, 0.01)
sim.PlotObrit()
import numpy as np
class Object:
def __init__(self, name, bodycolor, linecolor, pos_0, vel_0, mass):
self.name = name
self.bodycolor = bodycolor
self.linecolor = linecolor
self.position = pos_0
self.velocity = vel_0
self.mass = mass
self.path = []
def StartVelocity(self, other_bodies, time_step):
force = self.GetForce(other_bodies)
self.velocity += (force / self.mass) * time_step * 0.5
def Leapfrog(self, other_bodies, time_step):
self.position += self.velocity * time_step
self.velocity += (self.GetForce(other_bodies) / self.mass) * time_step
self.path.append(self.position.copy())
def GetForce(self, other_bodies):
force = 0
for other_body in other_bodies:
if other_body != self:
force += self.Force(other_body)
return force
def Force(self, other_body):
G = 6.673 * 10**-11
dis_vec = other_body.position - self.position
dis_mag = np.linalg.norm(dis_vec)
dir_vec = dis_vec / dis_mag
for_mag = G * (self.mass * other_body.mass) / dis_mag**2
for_vec = for_mag * dir_vec
return for_vec
def ReshapePath(self):
for index, position in enumerate(self.path):
self.path[index] = position.reshape(3).tolist()
Im aware that Body 2's position has to be multiplied by 1000 to get meters but it would just fly in a straight line if i would do that and there would be no signs of gravitational forces what so ever.
The constant G is in kg-m-sec units. The radius of the satellite orbit however only makes sense in km, else the orbit would be inside the Earth core. Then the speed in m/sec gives a near circular orbit with negligible eccentricity. (Code from a math.SE question on Kepler law quantities)
import math as m
G = 6.673e-11*1e-9 # km^3 s^-2 kg^-1
M_E = 5.9722e24 # kg
R_E = 6378.137 # km
R_sat = 42164.0 # km from Earth center
V_sat = 3075.4/1000 # km/s
theta = 0
r0 = R_sat
dotr0 = V_sat*m.sin(theta)
dotphi0 = -V_sat/r0*m.cos(theta)
R = (r0*V_sat*m.cos(theta))**2/(G*M_E)
wx = R/r0-1; wy = -dotr0*(R/(G*M_E))**0.5
E = (wx*wx+wy*wy)**0.5; psi = m.atan2(wy,wx)
T = m.pi/(G*M_E)**0.5*(R/(1-E*E))**1.5
print(f"orbit constants R={R} km, E={E}, psi={psi} rad")
print(f"above ground: min={R/(1+E)-R_E} km, max={R/(1-E)-R_E} km")
print(f"T={2*T} sec, {T/1800} h")
with output
orbit constants R=42192.12133271948 km, E=0.0006669512550867562, psi=-0.0 rad
above ground: min=35785.863 km, max=35842.14320159004 km
T=86258.0162673565 sec, 23.960560074265697 h
for r(phi)=R/(1+E*cos(phi-psi))
Implementing these changes in your code and calling with
sim.ComputePath(86e+3, 600.0)
gives a nice circular orbit
I am trying to draw a rectangle which would have an edge next to each of its sides (it should represent a building with a fence) for one building it goes quite well, but when I am trying to add a new building it messes itself up completely.
I have this code to create buildings:
class Building():
def __init__(self, Box_2_World,shape, position, sensor= None):
self.Box_2_World = Box_2_World
self.shape = shape
self.position = position
if sensor == None:
sensor = False
self.sensor = sensor
self.footprint = self.Box_2_World.CreateStaticBody(position = position,
angle = 0.0,
fixtures = b2FixtureDef(
shape = b2PolygonShape(box=(self.shape)),
density = 1000,
friction = 1000))
self.Lower_Fence = self.Box_2_World.CreateStaticBody(position=(self.footprint.position[0],self.footprint.position[1] -1.75*self.shape[1]))
self.Lower_Fence.CreateEdgeChain([(self.Lower_Fence.position[0]-4.25*self.shape[0],self.Lower_Fence.position[1]),
(self.Lower_Fence.position[0]-2.25*self.shape[0],self.Lower_Fence.position[1]),
])
self.Right_Fence = self.Box_2_World.CreateStaticBody(position=(self.footprint.position[0]-1*self.shape[0],self.footprint.position[1]))
self.Right_Fence.CreateEdgeChain([(self.Right_Fence.position[0],self.Right_Fence.position[1] - 1.25*self.shape[1]),
(self.Right_Fence.position[0],self.Right_Fence.position[1]-3.25*self.shape[1]),
])
self.Upper_Fence = self.Box_2_World.CreateStaticBody(position=(self.footprint.position[0],self.footprint.position[1] -0.45* self.shape[1]))
self.Upper_Fence.CreateEdgeChain([(self.Upper_Fence.position[0] - 4.25* self.shape[0],self.Upper_Fence.position[1]),
(self.Upper_Fence.position[0]- 3.25* self.shape[0]+ self.shape[0],self.Upper_Fence.position[1]),
])
self.Left_Fence = self.Box_2_World.CreateStaticBody(position=(self.footprint.position[0]-2.25*self.shape[0],self.footprint.position[1]))
self.Left_Fence.CreateEdgeChain([(self.Left_Fence.position[0],self.Left_Fence.position[1] - 1.25*self.shape[1]),
(self.Left_Fence.position[0],self.Left_Fence.position[1]-3*self.shape[1]),
])
Skyscrapers = []
Rectangles = [(pos_X-5, pos_Y-5),(pos_X+15, pos_Y -5),(pos_X - 5,pos_Y + 15),(pos_X+15, pos_Y + 15)]
for i in range(4):
Skyscrapers.append(Building(Box_2_World,shape = (5,5), position = Rectangles[i]))
and these functions to draw it using PyGame:
SCREEN_OFFSETX, SCREEN_OFFSETY = SCREEN_WIDTH/16, SCREEN_HEIGHT
def fix_vertices(vertices):
return [(int(SCREEN_OFFSETX + v[0]), int(SCREEN_OFFSETY - v[1])) for v in vertices]
def _draw_polygon(polygon, screen, body, fixture):
transform = body.transform
vertices = fix_vertices([transform * v * PPM for v in polygon.vertices])
pygame.draw.polygon(
screen, [c / 2.0 for c in colors[body.type]], vertices, 0)
pygame.draw.polygon(screen, colors[body.type], vertices, 1)
polygonShape.draw = _draw_polygon
def _draw_edge(edge, screen, body, fixture):
vertices = fix_vertices(
[body.transform * edge.vertex1 * PPM, body.transform * edge.vertex2 * PPM])
pygame.draw.line(screen, colors[body.type], vertices[0], vertices[1])
edgeShape.draw = _draw_edge
And the output is this: Blue rectangles represent buildings, blue lines are fences, first building fits quite nice, but the others are for some reason out of desired positions
Also, if you find out a way how to create the fences using for loop, it would be great (that's the reason why I put for-loop tag into this question)
Any help appreciated
The coordinates which are passed to CreateEdgeChain have to be relative to the body.
The position of the body is set when the object is constructed e.g:
self.Lower_Fence = self.Box_2_World.CreateStaticBody(
position=(self.footprint.position[0], self.footprint.position[1] -1.75*self.shape[1]))
And the edges have to be relative to this position rather than an absolute position.e.g:
self.Lower_Fence.CreateEdgeChain([(-4.25*self.shape[0], 0), (-2.25*self.shape[0], 0)])
To create the fences in a for-loop, you've to define a list of the edges. With the list of the edges you can create a list of fences:
fence_edges = [
[(-4.25, -1.75), (-2.25, -1.75)],
[(-1.00, -1.25), (-1.00, -3.25)],
[(-4.25, -0.45), (-2.25, -0.45)],
[(-2.25, -1.25), (-2.25, -3.25)]
]
self.Fences = []
for edge in fence_edges:
p1, p2 = edge
fence = self.Box_2_World.CreateStaticBody(position=self.footprint.position[:])
fence.CreateEdgeChain(
[(p1[0] * self.shape[0], p1[1] * self.shape[1]),
(p2[0] * self.shape[0], p2[1] * self.shape[1])])
self.Fences.append(fence)
self.Lower_Fence, self.Right_Fence, self.Upper_Fence, self.Left_Fence = self.Fences
I'm trying to achieve the pattern below.
Got as far as doing the first line, then I have no clue how to code the rest of the pattern.
Here's what I've done so far:
#Timothy Shek
from graphics import*
#open Graph Window
def main():
win = GraphWin("Example",100,100)
x = 7
y = 7
radius = 5
while x<=30 :
centre = Point(x,y)
circle1 = Circle(centre,radius)
circle1.setFill("red")
circle1.draw(win)
x = x+10
while x>=35 and x<=65 :
centre = Point(x+5,y)
circle2 = Circle(centre,radius)
circle2.setFill("red")
circle2.draw(win)
x = x+10
print(x)
while x>=67:
centre = Point(x+10,y)
circle1 = Circle(centre,radius)
circle1.setFill("red")
circle1.draw(win)
x = x+10
main()
I got it guys, thanks
Heres the solution
#Timothy Shek
from graphics import*
#open Graph Window
def main():
win = GraphWin("Patch2" ,100,100)
for x in (5, 15, 25, 40,50,60,75,85,95):
for y in (5, 15, 25, 40,50,60,75,85,95):
c = Circle(Point(x+2,y), 5)
d = Circle(Point(x+2,y), 5)
c.draw(win)
d.draw(win)
c.setFill("Red")
d.setFill("Red")
if x==15 or x==50 or x== 85:
if y==15 or y==50 or y== 85:
c2 = Circle(Point(x+2,y),5)
c2.draw(win)
c2.setFill("White")
main()
While there is nothing wrong with your solution, this is a bit more performant
from graphics import *
def main():
win = GraphWin("Patch2" ,100,100)
coords = [5, 15, 25, 40, 50, 60, 75, 85, 95]
centers = set([coords[i] for i in range(1, len(coords), 3)])
for i in xrange(len(coords)):
for j in xrange(i+1):
x, y = (coords[i], coords[j])
c1 = Circle(Point(x+2,y), 5)
c2 = Circle(Point(y+2,x), 5)
c1.draw(win)
c2.draw(win)
if x in centers and y in centers:
c1.setFill("White")
c2.setFill("White")
else:
c1.setFill("Red")
c2.setFill("Red")
main()
Update: "Better" version
And since I got bored and I liked this problem (yes, I program when I'm bored) I made a fully parameter-ized version which you can do some fun stuff with, like.
Probably over your head :) But maybe you learn something from it, so I'm posting it.
from graphics import *
def drawPattern(scale):
# Inner method: Draw a square of circles given the top-left point
def drawSquare(win, xCoord, yCoord, squareSize=30, numCircles=3, scale=1, scaleCircles=False, outer_color="Red", inner_color="White"):
# Overwrite the default scaling
if scale > 1:
squareSize *= scale
if scaleCircles:
numCircles *= scale
radius = squareSize/(numCircles*2) # Divide by 2 since it's the radius
from math import sqrt, floor
centerDiff = (2*radius) * floor(sqrt(numCircles)) # Used for drawing off-color circles
# xrange uses an exclusive stop value, so go one value past to make inclusive
for x in xrange(radius, squareSize+radius, radius*2):
for y in xrange(squareSize-radius, x-radius, -radius*2):
c1 = Circle(Point(x+xCoord+2,y+yCoord), radius)
c2 = Circle(Point(y+yCoord+2,x+xCoord), radius)
c1.draw(win)
c2.draw(win)
if (centerDiff < x < squareSize - centerDiff) and (centerDiff < y < squareSize - centerDiff):
c1.setFill(inner_color)
c2.setFill(inner_color)
else:
c1.setFill(outer_color)
c2.setFill(outer_color)
win = GraphWin("Patch2 (x{})".format(scale), 100*scale,100*scale)
coords = [0, 35, 70]
for x in coords:
for y in coords:
drawSquare(win, x*scale, y*scale, scale=scale) # normal (boring) version
# drawSquare(win, x*scale, y*scale, scale=scale, scaleCircles=True, outer_color="Blue") # Picture version
def main():
drawPattern(3)
main()
I am trying to dynamically modify the tube radius of a 3D line plot in Mayavi2. For example
from traits.api import HasTraits, Float, Instance, on_trait_change
from traitsui.api import View, Item, Group
from mayavi.core.api import PipelineBase
from mayavi.core.ui.api import MayaviScene, SceneEditor, MlabSceneModel
import numpy
def curve():
n_mer, n_long = 6, 11
pi = numpy.pi
dphi = pi / 1000.0
phi = numpy.arange(0.0, 2 * pi + 0.5 * dphi, dphi)
mu = phi * n_mer
x = numpy.cos(mu) * (1 + numpy.cos(n_long * mu / n_mer) * 0.5)
y = numpy.sin(mu) * (1 + numpy.cos(n_long * mu / n_mer) * 0.5)
z = numpy.sin(n_long * mu / n_mer) * 0.5
t = numpy.sin(mu)
return x, y, z, t
class MyModel(HasTraits):
radius = Float(0.025)
scene = Instance(MlabSceneModel, ())
plot = Instance(PipelineBase)
#on_trait_change('radius,scene.activated')
def update_plot(self):
x, y, z, t = curve()
if self.plot is None:
self.plot = self.scene.mlab.plot3d(x, y, z, t,
tube_radius=self.radius, colormap='Spectral')
else:
print self.radius
self.plot.mlab_source.set(tube_radius=self.radius)
self.scene.mlab.draw()
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
height=250, width=300, show_label=False),
Group(
'radius',
),
resizable=True,
)
my_model = MyModel()
my_model.configure_traits()
This gives:
However, when I change the radius nothing happens with the visual line plot.
Don't use trait.set or trait.reset to set mayavi or vtk attributes. Indeed the MLineSource that you are using doesn't have such an attribute, but it probably wouldn't work even if it did.
It's usually useful to find the mayavi attribute manually that controls this feature to see what mayavi object it is assigned to. In this case, going through the mayavi pipeline GUI shows that it is on the tube filter.
mlab.plot3d is a helper function that tries to do everything for you and doesn't maintain a
reference to the filters used. But in general it is good practice to keep references to each step in the mayavi pipeline if you construct the pipeline yourself. That way you can easily access the mayavi object which controls this.
If you don't construct the pipeline yourself you can always get to it in the pipeline by manually navigating the tree of parent and child objects. In this case you can access it like so:
#on_trait_change('radius,scene.activated')
def update_plot(self):
x, y, z, t = curve()
if self.plot is None:
self.plot = self.scene.mlab.plot3d(x, y, z, t,
tube_radius=self.radius, colormap='Spectral')
else:
self.plot.parent.parent.filter.radius = self.radius