#πŸ”’ Optimise drawing on the screen

69 messages Β· Page 1 of 1 (latest)

quiet sand
#

how could I make it so with each sys.stdout.write I write all those that are next to each other in rows positions?
my code: ```py
def draw(self, *extra_texts: str):
move_cursor(0,0)
sys.stdout.write("\n".join(extra_texts))

    rows, cols = np.where(self.old_value != self.value)
    for i, j in zip(rows, cols):
        move_cursor(j + self.offset, i)
        sys.stdout.write(self.value[i, j])
thorn folioBOT
#

@quiet sand

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

eternal plover
#

I'd group it first; something like

groups = [] # (i, (j_from, j_to))
for i,j in zip(rows, cols):
    if groups and groups[-1][0] == i and groups[-1][1][1]==j:
        groups[-1] = (groups[-1][0], (groups[-1][1][0], j+1)))
    else:
        groups.append((i, (j, j+1)))
#

and then, well,

for i,(j_from, j_to) in groups:
    move_cursor(j_from + self.offset, i)
    sys.stdout.write(self.value[i, j_from:j_to])
quiet sand
#

I adjusted sys.stdout.write("".join(self.value[i, j_from:j_to])) (self.value is a np.array)

#

and it wooorks!!

#

thank you

#

at first I did something like that but it didn't work: (```py
grouped_numbers = {}
for number in numbers:
first_position = number[0]
if first_position in grouped_numbers:
grouped_numbers[first_position].append(number[1])
else:
grouped_numbers[first_position] = [number[1]]
pass
# print(grouped_numbers)

    for key in grouped_numbers.keys():
        move_cursor(grouped_numbers[key][0] + self.offset,key)
        sys.stdout.write("".join(self.value[key,grouped_numbers[key][0]: grouped_numbers[key][-1]+1]) + col.Back.RESET + col.Fore.RESET)
do you have any idea why this wouldn't work?
#

now how do I optimise it to use numpy stuff?

eternal plover
#

I don't think there's a numpy function to do grouping like this, but you could use an itertools.groupby.

#

Consider first though whether it's even worth optimizing.

#

(like, if this is for printing to console, value has at most, like, ~10 thousand elements)

#

(If I had to optimize this heavily for some reason, I'd turn my way of grouping into a numba function.)

quiet sand
#

it counts because this is the draw function in my console game

#

that draws updates on the screen

#

I checked with cprofiner every other function call has less than 0.000 time per call and this has ~ 0.015

eternal plover
#

how many frames per second do you draw?

quiet sand
#

currently I don't limit it

#

now it takes ~ 0.007 per call thank you :)

eternal plover
#

well, on my old CPU for a 100x100 array this way of grouping takes <10ms

#

so it should be good for 100FPS. Quite possible the limiting factor isn't the grouping but the writes to stdout

quiet sand
eternal plover
# eternal plover (If I had to optimize this heavily for some reason, I'd turn my way of grouping ...

I expected this to be harder but it looks like numba is totally fine with tuples and lists these days:

from numba import njit
@njit
def getruns(arr):
    rows, cols = arr.nonzero()
    groups = []
    for i, j in zip(rows, cols):
        if groups and groups[-1][0] == i and groups[-1][1][1] == j:
            groups[-1] = (groups[-1][0], (groups[-1][1][0], j + 1))
        else:
            groups.append((i, (j, j + 1)))
    return groups

This takes 0.3 ms on a 100x100 array, another ~30 times faster.

quiet sand
#

btw do you know how to implement an fps system?, I tried multiple times but every time it became really fluctuates like 20-120 fps

#

is numba better than numpy?

#

bc importing both would be a waste of memory I think (numpy is 15MB)

eternal plover
eternal plover
# quiet sand is numba better than numpy?

numba is a very different sort of library - it lets you compile python functions (though only ones that do a limited set of things; it's quite restrictive) to machine code. numpy arrays are among the things it can work on.

quiet sand
#

by machine code u mean binary or asm or c?

eternal plover
#

I mean machine code. the thing that CPUs can execute. the thing that compiled languages like C compile to. (and ASM is just a human-readable representation of machine code, sure)

quiet sand
#

hmm sometimes I get 20 fps and sometimes 250 :D

eternal plover
#

try making a drawing benchmark (draw a totally random array on the screen each frame), see how good that goes

quiet sand
#

and write an fps script for that and try until the limitation of fps works?

eternal plover
#

No, I meant just to benchmark the drawing

quiet sand
#

I think I won't optimise it further yet

#

its fine for now

eternal plover
#

as for the FPS, I'd say you're calculating it wrong - you're essentially measuring the time it took to do one iteration of the loop, not counting the sleep from the last iteration. So even though you're drawing at most N frames per second, if you're on a sufficiently fast computer you'll see arbitrarily high FPS scores

quiet sand
#

so where should I change and what?

eternal plover
#

Perhaps something like

last_frame_time = 0
while not keyboard.is_pressed("esc"):
    since_last_frame = time.time() - last_frame_time
    if since_last_frame < FRAME_TIME:
        time.sleep(FRAME_TIME - since_last_frame)
    # [main loop elided]
    SCREEN.draw(
        f"score: {timetick}",
        f"speed: {player.speed}",
        f"player_x: {player.x}",
        f"player_y: {player.y}",
        f"FPS: {round(1/(time.time() - last_frame_time))}",
    )
    last_frame_time = time.time()
#

wait, no, that's not valid is it. uhh

quiet sand
#

its kinda working

#

how do people overcome the fluctiating of the fps?

eternal plover
#

btw, msvcrt is windows-only

quiet sand
#

yeah, I know that's a problem for an other day :D

quiet sand
eternal plover
#

I think you need to show something like this in order to both show good fps and limit it:

last_frame_start = prev_frame_start = 0
while not keyboard.is_pressed("esc"):
    since_last_frame = time.time() - last_frame_start
    if since_last_frame < FRAME_TIME:
        time.sleep(FRAME_TIME - since_last_frame)
    last_frame_start,prev_frame_start = time.time(), last_frame_start

    # entire main loop

    SCREEN.draw(
        f"score: {timetick}",
        f"speed: {player.speed}",
        f"player_x: {player.x}",
        f"player_y: {player.y}",
        f"FPS: {round(1/(last_frame_start-prev_frame_start))}",
    )
eternal plover
#

but if you want to show more useful info, then store the last, say, 10 frame timings (that's last_frame_start-prev_frame_start) in a deque, and show the mean, min and max fps over these last few frames.

quiet sand
#

you are a genius :D

#

really really thanks

eternal plover
#

Nice, I couldn't test it myself

#

I tried getting it to work for me on linux, and I had to remove mention of msvcrt and replace keyboard with pynput (the former works on linux, but only under root, which is silly), and replace cls with os.system("cls" if os.system=="nt" else "clear"), but after that it launches but doesn't render right in my terminal, not sure why.

#

specifically, the text gets written after the screen, and also the clears and writes are kinda desynced

#

i think the curses-based rendering is broken for some reason

#

(Personally I'd be using blessed which is cross-platform, but maybe there's a reason why you need a special API on windows.)

quiet sand
#

wait what could does blessed do?

#

I always wanted to do closs-platform but I could never get it right bc I only have win pc

eternal plover
#

It's basically a fancy modern wrapper over curses (and replicates the same capabilities for other platforms like windows).

#

!pypi blessed

thorn folioBOT
#

Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities.

Released on <t:1675477545:D>.

quiet sand
#

and what does it do when I try to use a color that in windows terminal doesn't exist?

#

(on windows cmd there's only 16 colors)

quiet sand
#

@eternal plover why is blessed so slow?

thorn folioBOT
#
Python help channel closed

This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.