Im trying to make a sorting visualizer and everything is going smoothly, but i have a problem.
First of all, i know that there's a lot of similar post but not a single one that can help me.
I have this problem that when the size of the sorting data is to high(>40) the screen starts to flicker when I run the sorting algorithm
Here's a video I recorded with the problem i have
I have some ideas on what the problem might be, but since im kinda new to tkinter with python im struggling to find out what exactly is. Here's my python code on the graphing/drawing data function
def runSort():
global data
data=Algorithm.bubblesort(data, graphData)
print("Sorting...")
def graphData(data, colorData):
canvas.delete("all")
can_height = 530
can_width = 1177
x_width = can_width/(len(data)+1)
offset=5
spacing=10
normalized_data=[i /max(data) for i in data]
for i, height in enumerate(normalized_data):
x0=i*x_width+offset+spacing
y0=can_height- height * 480
x1=(i+1)*x_width+offset
y1=can_height
canvas.create_rectangle(x0,y0,x1,y1,fill=colorData[i])
if(len(data)<=50):
canvas.create_text(x0+2,y0, anchor=SW,text=str(data[i]))
root.update_idletasks()
And here it is my sorting algorithm code
import time
class Algorithm():
def bubblesort(array, drawData):
for i in range(len(array)):
for j in range(len(array)-1-i):
if array[j] > array[j+1]:
array[j], array[j+1] = array[j+1], array[j]
drawData(array, ["cyan2" if x==j or x==j+1 else "coral3" for x in range(len(array))])
if len(array)<50:
time.sleep(0.5)
else:
time.sleep(0.1)
drawData(array, ["OliveDrab2" for x in range(len(array))])
return array
I hope someone can help me because I have no idea on how to solve this, or if it is possible. If you need more of my code be free to ask and i will gladly give you my code. Thanks! and Greetings from Mexico.
Hey I've been stuck on this issue for quite a while and was hoping someone could help me out:
I'm using pyglet and have got all of the code working in my project (even what I was having the issue with) then I restarted my computer and suddenly it didn't work...
This is the loop that is instantiating my 'Letter' objects:
main_st = ut.makeString("EXNXYXAXDAADUXMDXLGEQTAQXDDQSVXUTSXKHXHRXYFUXLXJUTHXYVADSUXKHUQUIXSJHXHDPKXFQUXILNXORMXRPL")
letter_list = []
for i in range(len(main_st)):
letter_list.append(l.Letter(pyglet.resource.image("Letters/" + main_st[i] + ".png"),main_st[i],10,10))
And this is the Letter class constructor Letter is a subclass of pyglet.sprite.Sprite:
def __init__(self,im,iden,xx,yy):
super(Letter,self).__init__(img=im,x=xx,y=yy)
At no point in the program do I modify the x and y coordinates of sprite but when I go to draw them, no matter what I put in for xx and yy they're always drawn in the same place on the window UNLESS I do a very large number for yy, and in those cases it simply disappears (I assume it's outside of the window).
I'm having each letter flash on the screen for 1 second and in order to do that here's my on_draw method
def on_draw():
background.draw()
if not key_manager.cur_letter == None:
key_manager.cur_letter.draw()
(only key_manager.cur_letter gets drawn and that switches every second).
The problem might be related to older versions.
But after calling super(Letter, self)... you could do:
def __init__(self,im,iden,xx,yy):
super(Letter,self).__init__(img=im,x=xx,y=yy)
self.x = xx
self.y = yy
And that should do the trick.
I have a question .
I'm making a platformer game in tkinter and I have an issue :
I have for now : player , blocks and coins .
I'm updating the player's move and it's animation and the coin's animation and for some reason when I'm putting too much coins , the player's movement starts lagging.
Note: I'm using the after function of tkinter for animations for player's movement + animation and same goes for the coins .
For other things like gravity and etc I'm using just threads .
code of coins updating :
def coinsCheckCollision(self):
cRemove = None
indexRemove = -1
count = 0
for c in self.frame.coins:
x, y , width , height = c.getRectangle()
xP = self.player.getX; yP = self.player.getY; wP = self.player.getWidth; hP = self.player.getHeight
if collisionDetect(xP , x, yP , y, wP , width, hP , height) or collisionDetect(x , xP , y , yP , width , wP , height , hP):
if count not in coinsRemoved:
indexRemove = count
if indexRemove != -1:
if indexRemove not in coinsRemoved:
coinsRemoved.append(indexRemove)
count +=1
def coinsUpdateAnimations(self):
count = 0
for c in self.frame.coins:
if count not in coinsRemoved:
self.img = c.getAnimation()
self.img = ImageTk.PhotoImage(self.img)
self.frame.coinsImages[count] = self.img
else:
if self.frame.coinsImages[count] is not '' :
self.frame.coinsImages[count] = ''
self.frame.canvas.delete('coinB'+str(count))
what = self.frame.canvas.itemconfig('coin' + str(count), image=self.frame.coinsImages[count])
count += 1
self.coinsCheckCollision()
self.frame.frame.after(40 , self.coinsUpdateAnimations)
Anyway , the question in short is : why when I'm updating multiple things that aren't really "related" to each other , the gui starts lagging ?
Your design seems to expect your functions to run every 40ms. Maybe +/- a few ms, but averaging 25 times per second.
But that's not what happens.
First, how many coins do you have, and how complicated is that collisionDetect function? If it only takes a tiny fraction of 1ms to run through that loop, it's no big deal, but think about what happens if it takes, say, 15ms: You wait 40ms, then do 15ms of work, then wait another 40ms, then do 15ms of work, etc. So your work is running only 15 times per second, instead of 25.
Now imagine each coin takes, say, 0.2ms. At 3 coins, there's a lag of 0.6ms, which is barely noticeably. But at 100 coins, there's a lag of 20ms. That slows the coins down by 50%, which is pretty obviously noticeable.
Second, as the docs say:
Tkinter only guarantees that the callback will not be called earlier than that; if the system is busy, the actual delay may be much longer.
Being off a few ms randomly in either direction might be fine; it would all average out in the end. But after is always a few ms late, never a few ms early, so instead of averaging out, it just builds up and you get further and further behind.
And, worse, if one of your functions gets behind, it will tend to make the delay in each after a bit longer—so it won't just be your coin animation slowing down 50%, but the whole game slowing down by some unpredictable amount arbitrarily between 0-50%, but probably enough to be noticeable.
To solve both problems, you need to carry around something like the time you expected to run at, then, instead of doing after(40), you do something like this:
expected_time += 40
delay = expected_time - current_time
after(max(0, delay), func)
To put it in concrete (although untested) terms, using the datetime module:
def __init__(self):
self.next_frame_time = datetime.datetime.now()
self.schedule()
def schedule(self):
self.next_frame_time += datetime.timedelta(seconds=0.040)
now = datetime.datetime.now()
delta = max(datetime.timedelta(), now - self.next_frame_time)
self.frame.frame.after(delta.total_seconds * 1000, self.coinsUpdateAnimations)
def coinsUpdateAnimations(self):
# all the existing code before the last two lines
self.coinsCheckCollision()
self.schedule()
This still won't solve things if the total work you do takes more than 40ms, of course. Imagine that you spend 50ms, then do an after(0, func), which triggers at least 10ms late, and then spend another 50ms, then the next after(0, func) triggers at least 20ms late, and so on. If you can't do all of your work in something that's usually significantly less than 40ms, you won't be able to keep up. You have to either:
Find a way to optimize your code (e.g., maybe you can use a better algorithm, or use numpy instead of a for loop),
Redesign your game to do less work, or
Slow down your frame rate to something you actually can keep up with.
A possibly better solution is to stop trying to bend Tkinter into a gaming framework. It's not designed for that, doesn't help you get all the fiddly details right, and doesn't work all that well even once you do get them right.
By contrast, something like Pygame Zero is, as the name implies, designed for creating games. And designed to make it easy enough that people with a lot less Python experience than you seem to have can use it.
For example, instead of an event loop that runs at whatever speed your OS wants to run it, making it your responsibility to get everything timed right, Pygame Zero runs a frame loop that calls your update function N times per second, as close to evenly as possible. And it has built-in functions for things like collision detection, drawing animated sprites, etc.
I'm having trouble running the last part of my code here. Im using Raspberry Pi, OpenCV, PiCamera, and servo motors. NOT SHOWN i have the code to find the centroid, and from the centroid it will then determine how far off '160' it is. Im not totally sure if the centroid's middle point is 160, so do any of you know that? As well as I get a SyntaxError on the "if: cx>151 and cx<169", would any of you know why that it, or could you help me to figure out a different approach to telling it how to follow the line?
import RoboPiLib as RPL
import setup
motorL = 0
motorR = 1
#1500 = middle point
#The closer to '1500' the slower it will go
if: cx>151 and cx<169
print "straight"
RPL.servoWrite(motorL, 1000)
RPL.servoWrite(motorR, 2000)
time.sleep(2)
elif x<=150
print "left"
RPL.servoWrite(motorL, 1000)
RPL.servoWrite(motorR, 1750)
time.sleep(2)
elif x>=170
print "right"
RPL.servoWrite(motorL, 1250)
RPL.servoWrite(motorR, 1000)
time.sleep(2)
else print "stop"
The colon on this line needs to be moved to the end of the line:
if cx>151 and cx<169:
Also the elif lines have the same problem: a colon is missing at the end of the lines!
I'm running a model of a spring in python using a for loop over 50 iterations and want to plot it after 25 iterations, and again after 50 iterations.
Here's an excerpt of the code I've been using so far (I can post the whole thing if that would be helpful).
ts = np.array([0])
xs = f(ts)
for i in range(50):
tn = ts[i]+0.1
xn = f(tn)
ts = np.append(ts,tn)
xs = np.append(xs,xn)
while i == 24:
plt.plot(ts,xs)
plt.savefig('Weight plotted after 2.5 seconds.png')
while i == 49:
plt.plot(ts,xs)
plt.savefig('Spring plotted after 5 seconds.png')
I'm not getting any errors but it's just not returning anything. I'm pretty new to python and coding in general so any input that anyone might have would be much appreciated!
You need to replace your while statements with if statements.
while will repeat the indented code as long as the condition i == 24 is satisfied. Once your loop reaches i == 24, the program will repeatedly save your figure until you terminate the program because i does not change within the while loop.
if will execute the indented code once if the condition is satisfied--which is what you want.