Two consecutive animations synchronised with one longer animation - python

In particular, I would like to smoothly zoom out and then zoom in all the while an object rotates. I cannot seem to control runtimes separately and I couldn't figure out how to use LaggedStart or Succession to achieve this. I also couldn't make an updater work – the width does not change at all. I'm including the last try on the updater.
class Rectangles(MovingCameraScene):
def construct(self):
rect1 = Rectangle(height=4.2, width=9.3)
staticobj = Rectangle(height=8,width=2,fill_color=BLUE).shift(RIGHT*7)
self.add(rect1,staticobj)
self.camera.frame.set(width=20)
x = ValueTracker(-.99)
def zoom_level(inp):
inp.set(width=math.exp(10 / (x.get_value() ** 2 - 1) + 20))
self.camera.frame.add_updater(zoom_level)
self.play(Rotate(rect1, angle=PI / 2, about_point=ORIGIN),x.animate.set_value(0.99),run_time=5)
self.wait(1)

To whoever stumbles upon this: the solution I came up with in the end was to use UpdateFromAlphaFunc.
class Rectangles(MovingCameraScene):
def construct(self):
rect1 = Rectangle(height=4.2, width=9.3)
staticobj = Rectangle(height=8,width=2,fill_color=BLUE).shift(RIGHT*7)
self.add(rect1,staticobj)
self.camera.frame.set(width=20)
def zoom_level(inp,alpha):
inp.set(width=20+5-20*(alpha-0.5)**2)
self.play(Rotate(rect1, angle=PI / 2, about_point=ORIGIN),
UpdateFromAlphaFunc(self.camera.frame,zoom_level),run_time=5)
self.wait(1)

Related

PyQt Freezing while many graphs plotting

def initPlots(self):
print("init_Plots")
for S in range(self.sensor_num):
globals()["self.plot{0}".format(S)] = pg.PlotWidget()
globals()["self.plot{0}".format(S)].setYRange(-30,30)
self.layout.addWidget(globals()["self.plot{0}".format(S)],S//5,S%5)
def showPlot(self,number,x_axis):
print("init_showPlot")
'''x_axis : time(s) / y_axis : data(rgb)'''
globals()["self.plot{0}".format(number)].clear()
globals()["self.plot{0}".format(number)].plot(x=x_axis,y=self.y_domain_r[number],
pen=pg.mkPen(width=2,color='r'),name="sensor_"+str(number)) # R
globals()["self.plot{0}".format(number)].plot(x=x_axis,y=self.y_domain_g[number],
pen=pg.mkPen(width=2,color='g'),name="sensor_"+str(number)) # G
globals()["self.plot{0}".format(number)].plot(x=x_axis,y=self.y_domain_b[number],
pen=pg.mkPen(width=2,color='b'),name="sensor_"+str(number)) # B
#QtCore.pyqtSlot(np.ndarray)
def run(self, arr):
print("init_run(plot)")
self.time += 1
self.data = arr
self.t_domain.append(self.time)
for S in range(self.sensor_num):
self.y_domain_r[S].append(self.data[S][0])
self.y_domain_g[S].append(self.data[S][1])
self.y_domain_b[S].append(self.data[S][2])
self.showPlot(S,self.t_domain)
This is a program that receives the rgb change value of an image every frame and displays a graph for that value.
np.ndarray of delta RGBs Signal -> Slot
This program often shuts down when I press run. How to reduce memory usage?
Is that okay with that I'm using many globals()?
Is it an inevitable flaw in Python?
help me guys~
For anyone who see this, I delete my globals and I made a plot list.
It worked for me.

How does `double_wave.py` (custom shape feature from Locust) work?

I am trying to understand the math behind the following custom shape code: double_wave.py
The important piece of code is this:
min_users = 20
peak_one_users = 60
peak_two_users = 40
time_limit = 600
def tick(self):
run_time = round(self.get_run_time())
if run_time < self.time_limit:
user_count = (
(self.peak_one_users - self.min_users)
* math.e ** -(((run_time / (self.time_limit / 10 * 2 / 3)) - 5) ** 2)
+ (self.peak_two_users - self.min_users)
* math.e ** -(((run_time / (self.time_limit / 10 * 2 / 3)) - 10) ** 2)
+ self.min_users
)
return (round(user_count), round(user_count))
else:
return None
I know that they are setting a minimum amount of users and somehow generating two peaks. However, the function is not clear for me. I would like to understand where they come from so I can play around and adjust it for my needs.
Basically, I would like to know:
Is this some known equation with specific parameters?
Is it possible to determine when each peak should occur?
What is necessary in order to have this kind of behavior for other time_limit values?
From the Locust docs:
In this class you define a tick() method that returns a tuple with the desired user count and spawn rate (or None to stop the test). Locust will call the tick() method approximately once per second.
The feature works by allowing you to programmatically set the users and spawn rate. You can make tick() return whatever you want. The example is just making a wave form in the graph. Whatever math you want to use will work, just return user_count, _spawn_rate with whatever values you want.
I am not sure if they have sourced this equation from somewhere or written themselves but things can get clear if you see from mathematical function perspective.
Consider the function f(t) for number of users(y axis) with time(on x axis), with other constants like p1 (peak1), p2 (peak2), T (total time limit) and m (min users). If you try to put t = T/3 then f(T/3) -> p1 and f(2T/3) -> p2, so your two peaks are distributed uniformly over T period.

How does the 'with' statement work in kivy?

I have been playing with kivy, and I saw this:
with self.canvas:
Color(1, 1, 0) # <--- no assignment
d = 30.
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d)) # <--- no assignment
I don't quite understand how it works. I was expecting to see something like:
with self.canvas as c:
c.color = Color(1, 1, 0)
c.shape = Ellipse()
What am I missing?
with some_canvas sets an internal Kivy variable to that canvas. When canvas instructions are created they check if that variable is set to a canvas, and if so they automatically add themselves to it.
If you want to trace through how this works you can find the context entry function here, and the code that automatically adds instructions to a canvas when instantiated here.
I don't quite understand how it works. I was expecting to see something like:
with self.canvas as c:
c.color = Color(1, 1, 0)
c.shape = Ellipse()
In this case the with context wouldn't really be doing anything. If you want to explicitly manipulate the canvas you can do it directly without a context manager, e.g. self.canvas.add(Color(1, 1, 0)).
That said, the way you've written this may indicate a misunderstanding: a canvas doesn't have a specific colour as you've indicated with c.color, rather it's a list of instructions to apply in order. There could be many Color instructions, with different numbers of other instructions (e.g. representing different shapes) in between.

Using BindConstraint in Clutter to constrain the size of an actor

I recently discovered constraints in Clutter, however, I can't find information on how to constrain the size of actor by proportion. For example, I want an actor to keep to 1/2 the width of another actor, say it's parent. It seems like it can only force the width to scale 100% with the source.
Clutter.BindConstraint matches the positional and/or dimensional attributes of the source actor. for fractional positioning, you can use Clutter.AlignConstraint, but there is no Clutter.Constraint class that allows you to set a fractional dimensional attribute. you can implement your own ClutterConstraint that does so by subclassing Clutter.Constraint and overriding the Clutter.Constraint.do_update_allocation() virtual function, which gets passed the allocation's of the actor that should be modified by the constraint. something similar to this (untested) code should work:
class MyConstraint (Clutter.Constraint):
def __init__(self, source, width_fraction=1.0, height_fraction=1.0):
Clutter.Constraint.__init__(self)
self._source = source
self._widthf = width_fraction
self._heightf = height_fraction
def do_update_allocation(self, actor, allocation):
source_alloc = self._source.get_allocation()
width = source_alloc.get_width() * self._widthf
height = source_alloc.get_height() * self._heightf
allocation.x2 = allocation.x1 + width
allocation.y2 = allocation.y1 + height
this should illustrate the mechanism used by Clutter.Constraint to modify the allocation of an actor.

invalid syntax when using self.size = size

super, super new to Python and programming in general. I have a question that should be simple enough. I'm using a python beginners programming book using Python version 3.1.
I am currently writing out one of the programs in the book and I am learning about how important indentation is when using python so I was fixing those errors I found and then I get to where I put self.size = size and it highlights that self in the code block is invalid syntax but I'm typing this word for word from the manual so I am not sure what I'm doing wrong. Here is the code block:
def _init_(self, x, y, size):
""" Initialize asteroid sprite. """
super(Asteroid, self)._init_(
image = Asteroid.images[size],
x = x, y = y,
dx = random.choice([1, -1]) * Asteroid.SPEED * random.random()/size,
dy = random.choice([1, -1]) * Asteroid.SPEED * random.random()/size
self.size = size
The problem is that last line, it highlights self as invalid syntax but nothing else... Also one last note, when I put this particular block into the shell and try running it there it also gives me a syntax error but not the same one, it gives me one right after the colon on the first line of this block and highlights that entire blank area with red.....and I can't figure why. I was putting it in shell so it could highlight the self thing and help me, but instead shows me something completely different.
Any help will be greatly appreciated! thanks!
You forgot to close the parentheses.
Usually, when you forget to close some parentheses, the interpreted points the error as being in the following line:
def _init_(self, x, y, size):
""" Initialize asteroid sprite. """
super(Asteroid, self)._init_( <-- here you have a parentheses opening
image = Asteroid.images[size],
x = x, y = y,
dx = random.choice([1, -1]) * Asteroid.SPEED * random.random()/size,
dy = random.choice([1, -1]) * Asteroid.SPEED * random.random()/size <-- no more commas here
self.size = size <-- first line without a trailing comma OR parentheses: SYNTAX ERROR HERE! (even though the assignment itself is ok)
Perhaps what the book actually meant was this - as Martijn Pieters pointed out, some of the self.__init__ parameters (x and y) are being passed to the parent's __init__ method, for which other parameters are being read elsewhere (image) or created on-the-fly (dx and dy). Finally, one of the parameters (size) is passed only to the instance, in the body of self.__init__, assigning to self.size:
def __init__(self, x, y, size):
""" Initialize asteroid sprite. """
super(Asteroid, self)._init_(
image = Asteroid.images[size],
x = x,
y = y,
dx = (random.choice([1, -1]) * Asteroid.SPEED * random.random()/size),
dy = (random.choice([1, -1]) * Asteroid.SPEED * random.random()/size))
self.size = size
It is important to know that any method (routine defined inside a class) in Python receives a first argument automatically, which is the object instance itself. Although you might call it what you want, self is the universal Python convention for that. So, when you define __init__ and pass selfas first parameter, you can use it throughout this function to refer to the object you are creating. Thus, saying self.x = x means you want the object to have a x attribute, its value being the x argument you passed upon object creation.

Categories