Python Forum

Full Version: Can't get graph code to work properly.
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi people. I have a problem, I'm working on a code for a school project, it has to analyze the graph in real time (the blue one) and depending on the percentage it has, write it in the notepad, I'm using pyautogui and win32api/con to verify if a pixel is blue or blue-green and depending on how many I see, write the percentage. My problem is that although it reads the pixels correctly, it only activates if the graph reaches 100 and therefore only writes 100, I have not been able to get it to work correctly, if you could help me I would greatly appreciate it because my knowledge is limited, the project is supported only by YT and Chatgpt tutorials.
from pyautogui import *
import pyautogui
import time
import keyboard
import random
import win32api, win32con

# Máxima posición (100%)
MAX_Y = 875
# Mínima posición (1%)
MIN_Y = 715
# Coordenada X fija
X_COORDINATE = 1500

# Duración máxima en segundos
MAX_DURATION = 60

# Colores esperados con tolerancia
COLORS_EXPECTED = [(0, 50, 61), (0, 0, 100)]  # Ajusta estos valores
COLOR_TOLERANCE = 30  # Aumentar tolerancia para colores similares

def color_similar(r1, g1, b1, r2, g2, b2, tolerance):
    """Compara si dos colores son similares dentro de una tolerancia."""
    return abs(r1 - r2) <= tolerance and abs(g1 - g2) <= tolerance and abs(b1 - b2) <= tolerance

def click(x, y):
    win32api.SetCursorPos((x, y))
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)
    time.sleep(0.01)  # Pausa
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0)

def calcular_porcentaje(pos_y):
    # Calcular porcentaje en función de la posición entre MIN_Y y MAX_Y
    if pos_y >= MIN_Y and pos_y <= MAX_Y:
        porcentaje = ((pos_y - MIN_Y) / (MAX_Y - MIN_Y)) * 100
        return round(porcentaje)  # Redondear sin decimales
    else:
        return None

# Esperar 5 segundos antes de comenzar
time.sleep(5)

# Almacenar el tiempo de inicio
start_time = time.time()

while not keyboard.is_pressed('q'):
    # Verificar si ha pasado más de 1 minuto
    elapsed_time = time.time() - start_time
    if elapsed_time > MAX_DURATION:
        print("Se ha alcanzado el tiempo límite de 1 minuto. Saliendo del loop.")
        break

    highest_percentage = None  # Para almacenar el valor más alto
    highest_y = None  # Para almacenar la posición Y del valor más alto

    # Leer el color en la coordenada (X_COORDINATE, Y) sin mover el mouse
    for current_y in range(MIN_Y, MAX_Y + 1):
        r, g, b = pyautogui.pixel(X_COORDINATE, current_y)
        
        # Imprimir color leído para depuración
        print(f"Color detectado en Y={current_y}: R={r}, G={g}, B={b}")

        # Comparar el color leído con los colores esperados usando la función de tolerancia
        for color in COLORS_EXPECTED:
            if color_similar(r, g, b, *color, COLOR_TOLERANCE):
                porcentaje = calcular_porcentaje(current_y)

                if porcentaje is not None:
                    # Si encontramos un porcentaje mayor, lo guardamos
                    if highest_percentage is None or porcentaje > highest_percentage:
                        highest_percentage = porcentaje
                        highest_y = current_y

    # Si hemos encontrado algún porcentaje válido
    if highest_percentage is not None:
        # Clic y escribir el porcentaje más alto encontrado
        click(410, 988)
        pyautogui.write(str(highest_percentage))  # Escribir el porcentaje redondeado sin decimales
        pyautogui.press('enter')
    else:
        print("No se detectó concentración en este ciclo.")

    # Pequeña pausa para evitar consumo excesivo de CPU
    time.sleep(0.1)
[attachment=3041]
There is an error in how you calculate percentage.

Coordinates for the screen are like this (from the pyautogui documentation):
Output:
0,0 X increases --> +---------------------------+ | | Y increases | | | | 1920 x 1080 screen | | | | V | | | | +---------------------------+
But most graphs are like this:
Output:
+---------------------------+ | | Y increases | | ^ | 1920 x 1080 screen | | | | | | | | | +---------------------------+ 0,0 X increases -->
You need to change your porcentaje calculation:
porcentaje = (MAX_Y - pos_y) / (MAX_Y - MIN_Y) * 100
Your code only reads the graph at X = 1500. Peaks that are not at x = 1500 are ignored. Is that what you want?

This code is inefficient.
    # Leer el color en la coordenada (X_COORDINATE, Y) sin mover el mouse
    for current_y in range(MIN_Y, MAX_Y + 1):
        r, g, b = pyautogui.pixel(X_COORDINATE, current_y)
         
        # Imprimir color leído para depuración
        print(f"Color detectado en Y={current_y}: R={r}, G={g}, B={b}")
 
        # Comparar el color leído con los colores esperados usando la función de tolerancia
        for color in COLORS_EXPECTED:
            if color_similar(r, g, b, *color, COLOR_TOLERANCE):
                porcentaje = calcular_porcentaje(current_y)
 
                if porcentaje is not None:
                    # Si encontramos un porcentaje mayor, lo guardamos
                    if highest_percentage is None or porcentaje > highest_percentage:
                        highest_percentage = porcentaje
                        highest_y = current_y
 
    # Si hemos encontrado algún porcentaje válido
    if highest_percentage is not None:
        # Clic y escribir el porcentaje más alto encontrado
        click(410, 988)
        pyautogui.write(str(highest_percentage))  # Escribir el porcentaje redondeado sin decimales
        pyautogui.press('enter')
    else:
        print("No se detectó concentración en este ciclo.")
Because you are scanning downward from the top, the first pixel that matches one of your colors is also the highest pixel to match one of the colors. You should stop scanning once a color match is found. This eliminates testing all the pixels below the peak, cutting the average time spent finding the peak value in half. It also eliminates the need for highest_percentage and highest_y.

Staring from the stop and scanning down until you find the first pixel that matches one of the colors is inefficient. Not knowing anything about your graph other than it is 160 pixels high, on average you'll sample 80 pixels to find the peak. A binary search would reduce the number of pixels you need to check to 8. When I ran your code it takes about 2.8 seconds to check 80 pixels (average for a linear search) and 0.32 seconds to check 8 pixels (max for a binary search).