is there any possibility to move the cursor in Python with % starting from a certain coordinate like (1,1)?
I am using pyautogui atm to automate and I thought it would be quite convenient if this is independent from the monitor size making it universal.
Thanks for your help in advance!
It's possible indirectly. As detailed at the top of the Mouse Control Functions page of the documentation, you can get the screen size using the size() function (which returns a tuple of (X, Y)). You can then do the math to figure out how many screen pixels equal the percentage you're looking for, then call moveTo() to go there.
# script to move mouse 50% to the right and down
import pyautogui as pag
percentage = 0.5
cur_X, cur_Y = pag.position() # current X and Y coordinates
size_X, size_Y = pag.size() # screen size
goto_X = (size_X - cur_X) * percentage + cur_X # current location plus half
goto_Y = (size_Y - cur_Y) * percentage + cur_Y # the distance to the edge
pag.moveTo(goto_X, goto_Y, 1) # move to new position, taking 1 second
Environment:
Python: 3.6.6
pyglet version: 1.3.2
Code base:
abstract_model.py
import pyglet
def get_texture_group(file, order_group_index):
texture = pyglet.image.load(file).texture
order_group = pyglet.graphics.OrderedGroup(order_group_index)
return pyglet.graphics.TextureGroup(texture, order_group)
class AbstractModel(object):
def _create_as_vertex(self):
v_x = self.cell_data.get("x") * 32
v_y = self.cell_data.get("y") * -1 * 32
texture_group = self.map_type_iamge.get(self.cell_data.get("t"))
x_offset = self.x_offset * self.scale
x, y, z = v_x + x_offset, v_y, self.z
x_ = (texture_group.texture.width * self.scale + x_offset + v_x)
y_ = (texture_group.texture.height * self.scale + v_y)
tex_coords = ('t2f', (0, 0, 1, 0, 1, 1, 0, 1))
self.vertices = self.batch.add(
4, pyglet.gl.GL_QUADS,
texture_group,
('v3f', (x, y, z,
x_, y, z,
x_, y_, z,
x, y_, z)),
tex_coords)
def _animate(self, dt):
# lets assume that I have list of pyglet.graphics.TextureGroup
# and they should somehow be drawn one after other
print("I need change image. dt=", dt, self)
pyglet.clock.schedule_once(self._animate, 1)
ground3d.py
import os
import pyglet
import settings
from models import abstract_model
GROUND_DIR = os.path.join(settings.STATIC_DIR, "ground")
order_group_index = 0
map_type_iamge = {
1: abstract_model.get_texture_group(os.path.join(GROUND_DIR, "w1.png"), order_group_index),
2: abstract_model.get_texture_group(os.path.join(GROUND_DIR, "t1.png"), order_group_index),
1001: abstract_model.get_texture_group(os.path.join(GROUND_DIR, "t1_direction.png"), order_group_index),
}
class Ground3D(abstract_model.AbstractModel):
def __init__(self, cell_data, batch):
self.batch = batch
self.cell_data = cell_data
self.map_type_iamge = map_type_iamge
self.scale = 1
self.x_offset = 0
self.z = 0
self.entity = None
self._create_as_vertex()
pyglet.clock.schedule_once(self._animate, 1)
Explanation:
I have models(just flat rect for an example) which should be placed on 3 dimensions. And these models should be animated, like picture_1, after second picture_2, ... etc.
As I understood from my previous question using pyglet.sprite.Sprite() in 3D batch is not a good idea.
Question:
How I can change pictures(using TextureGroup or any other approaches) on self.vertices?
Or which arroach/classes I use use to implement it. I can't find any examples for such (as for my simple vision) usual case as animation for some flat models in 3 dimensions.
There are many example about rotating/moving/resizing of vertices, but how to build a correct question(is animation aspect) for getting answer in google - I don't know.
PS: If you, reader, have any usefull links on this subject(for pyglet or just for OpenGL) I would be very appreciated you share this link(s) in comment.
Texture coordinates.
You should have a single texture atlas for all frames of all different things that are animated ever.
Preferably, everything should have same animation speed and same amount of frames all the time.
Let's say there's two sprites that have 2 frames for entire animation, and they are stored in 64x64 texture atlas. (EDIT: sorry for ambiguity, 64x64 PIXELS, just because it could imply that we have 64x64 tile atlas, same everywhere else where I mention this)
Now, you need to have a global timer with global value which indicates current animation frame, not game frame. It should be independent of framerate.
Said value should be updated every once in a while at your desired speed like this:
current_frame = (current_frame + 1) % animation_length
Since we have 2 frames in this example, it will turn out like this:
# init
animation_length = 2
current_frame = 0
# updates:
current_frame = (0 + 1) % 2 # 1 % 2 -> 1
current_frame = (1 + 1) % 2 # 2 % 2 -> 0
...
Now, you need to update UV's of all your sprites only when the frame changes.
UV's start from left right and go from 0 to 1 (as far as I remember, for the sake of this example, they do, shhh).
Since we have 2 frames each, we can calculate "tiles" in the UV coordinates like this:
tile_width = 1.0 / frames # 2 frames each, width will be 0.5
tile_height = 1.0 / sprites # 2 sprites each, height will be 0.5 too, perfect
Now, on first frame, you generate your UV's like normal, you just take vertical ID or something, and use tile_height * sprite_id to get current V coordinate, and your U is calculated like tile_width * current_frame.
This assumes that you already have sprite batching so what you do is go over every sprite on update, and basically just recalculate new UV's with new frame, meaning all sprites change their frame to the next one, yay!
If you want to have systems that are independent of eachother, say, very slow animations for some, and faster for others, you'll need different sprite batches or proper calculation on from where to where you need to update UV's in vertex buffer array. Everything else is exactly the same, except now current_frame won't be global but rather contained, preferebly in some list or separate object that manages timers for animations.
You don't need to change anything in your shaders, they just need right UV's for the frames and you're set.
By the way, this is very basic, you could apply some logic yourself so you could instead have 16x16 grid of 32x32 pixels in your texture, each line of sprites having 4 different animations, these could be either sprite's states (attack, run, etc), but how you do it is entirely on you, most importantly, get it to work. Goodluck.
But if you do it the way I said, then state will be another integer, and UV for state, assuming all states have exactly the same width, it would be like this:
state_width = 1 / states
tile_width = 1 / (states * frames_per_state)
U = state_width * current_state + tile_width * current_frame
Now, one issue arises, player could start his animation at the last attack frame.
It's normal, entities with actions should all have individual timers, what I described above, is for tons of sprites that are just background, like grass. Now when you divided it up, you could have a proper way to reset current frame to 0 when new state is assigned.
If your entities are objects, you could write proper methods that recalculate UV's every time you rebuild the sprite batch using those sprites, and then timers itselves could be contained in objects.
We need to draw something? Check animation state, has it changed, no? Send UV's that were calculated before, otherwise, wait a bit, we need to recalculate, only then add those to VBO, and well, render your thing, in the end, it will appear as if you have animations, even though really, it's just a simple, but great UV manipulation.
Goodluck.
So I'm trying to plot real time data with PyQt. I have it working in a sense, but matplotlib seems to be slowing it down a lot. If I reduce the number of plots I can get the sample rate I want. I have two timer events, one that gathers data and another that plots, with a ratio of 10 to 1.
Searching for a fix I found about Blitting with Matplotlib from SO, and was led to tutorials like this. The problem I'm seeing is that this is only dealing with the plotting part. Every attempt I have made at sampling and plotting a portion of the data I've gathered ends in a crash.
So an outline of what I'd like to do would be this
class graph(ParentMplCanvas):
def __init__(self, *args, **kwargs):
self.axes = fig.add_subplot(111)
self.x = range(1000)
self.data = np.zeros(1000)
#set timer for data to be sampled once every 10ms.
self.updateData()
self.line, = self.ax.plot(self.x,self.data, animated=True)
# Update the plot every second
self.gTimer = fig.canvas.new_timer(interval=1000)
self.gTimer.add_callback(self.update_figure)
self.gtimer.start()
def updateData(self):
self.i += 1
#append with 0's if self.i > 1000
self.data[self.i] = self.funcToGrabCurrentValFromDevice()
self.updateTimer()
def updateTimer(self):
self.dTimer = Timer(0.01,updateData)
self.dTimer.start()
class ApplicationWindow(gui.QMainWindow):
some stuff to call docked windows and the above graph in a docked window see [how I did it here][2]
Maybe I am just not understanding the blitting, but everything I'm seeing there they already have all the data. Any time I've tried to just access a portion of the data it seems to crash the program. I'm trying to just plot a 100 sample region at a time and have it continuously update.
Where I am lost:
How do I properly write update_figure so that I can plot the last 100 (or n) data points that were sampled?
This is a code problem for Python 3.5.2 using John Zelle's graphics.py:
I have spent a good amount of time looking for the answer here, but just can not figure it out. The function undraw() exists just like getMouse(). But it seems like it do not work for the plot() command, only the draw() command. What am I doing wrong? And how can I keep the window open, but erase the previous the plot before the next one is drawn?
pdf documentation for the functions of graphics:
http://mcsp.wartburg.edu/zelle/python/graphics/graphics.pdf
win = GraphWin("Plot",500,500) # Creates a window
for m in range(0,j): # Loop for each function
# Randomizes a color for each function
color = random.choice( ['red','black','green','yellow','pink','blue'] )
for h in range(0,t): # Loop for each pair of values "x,y"
# Find points and plot each point in win
win.plot(axis[h],points[m][h],color)
win.getMouse() # Pause before clicking
win.undraw() # AttributeError: 'GraphWin' object has no attribute 'undraw'
The first issue is that undraw() is a method of GraphicsObject, not GraphWin, so win.undraw() is simply incorrect.
The second issue is that plot() is a low level pixel setting method that does not keep track of what it did at the Zelle Graphics level, unlike objects that are drawn.
However, the underpinning is Tkinter which does keep track of objects that it draws, and GraphWin is a subclass of Canvas, so you can do:
win = GraphWin("Plot", 500, 500) # Creates a window
for m in range(j): # Loop for each function
color = random.choice(['red', 'black', 'green', 'yellow', 'pink', 'blue']) # Randomizes a color for each function
for h in range(t): # Loop for each pair of values "x, y"
win.plot(axis[h], points[m][h], color) # Find points and plot each point in win
win.getMouse() # Pause before clicking
win.delete("all") # Clear out old plot
I have a bit of code that draws an array of lines (32X32 grid). The actual code that draws it starts from #Nested loop to draw anti-aliased lines in a 32X32 grid. Because I have a patch within it that has lines of different orientation, the codes is a few lines long.
At the moment, I have a .draw() at the end of the nested loop that draws my array.
It doesn't seem like a good way to do this.
Is there a way to create a variable for this entire nested loop so i can call it as and when I want? For instance myStim.draw()
# Import what is needed
import numpy as np
from psychopy import visual, event, core, logging
from math import sin, cos
import random, math
# Create space variables and a window
lineSpaceX = 0.55
lineSpaceY = 0.55
patch_orientation = 45 # zero is vertical, going anti-clockwise
surround_orientation = 90
#Jitter values
g_posJitter = 0.05 #gaussian positional jitter
r_posJitter = 0.05 #random positional jitter
g_oriJitter = 5 #gaussian orientation jitter
r_oriJitter = 5 #random orientation jitter
#Region where the rectangular patch would appear
x_rand=random.randint(6,13) #random.randint(Return random integers from low (inclusive) to high (inclusive).
y_rand=random.randint(6,16)
#rectangular patch dimensions
width=15
height=12
message = visual.TextStim(win,pos=(0.0,-12.0),text='...Press SPACE to continue...')
# Initialize clock to record response time
rt_clock = core.Clock()
#Nested loop to draw anti-aliased lines in a 32X32 grid
for x in xrange(1,33): #32x32 grid.
for y in xrange(1,33):
##Define x & y value (Gaussian distribution-positional jitter)
x_pos = (x-32/2-1/2 )*lineSpaceX + random.gauss(0,g_posJitter) #random.gauss(mean,s.d); -1/2 is to center even-numbered stimuli; 32x32 grid
y_pos = (y-32/2-1/2 )*lineSpaceY + random.gauss(0,g_posJitter)
if (x >= x_rand and x < x_rand+width) and (y >= y_rand and y < y_rand+height): # note only "=" on one side
Line_Orientation = random.gauss(patch_orientation,g_oriJitter) #random.gauss(mean,s.d) - Gaussian func.
else:
Line_Orientation = random.gauss(surround_orientation,g_oriJitter) #random.gauss(mean,s.d) - Gaussian func.
#stimOri = random.uniform(xOri - r_oriJitter, xOri + r_oriJitter) #random.uniform(A,B) - Uniform func.
visual.Line(win, units = "deg", start=(0,0), end=(0.0,0.35), pos=(x_pos,y_pos), ori=Line_Orientation, autoLog=False).draw() #Gaussian func.
frameN = 0
for frameN in range(80): #for exactly 80 frames; 1 frame = 16.67ms on the 1920 x 1080 monitor
if frameN == 0:
rt_clock.reset() # set reaction time clock to 0
message.draw()
win.flip()# display stimulus
frameN = frameN + 1
keys = event.waitKeys(keyList=['space', 'escape','q']) #create key list response
# handle key responses
if len(keys)>0:
rt = rt_clock.getTime()
if keys == ['space']:
event.clearEvents()
break
else:
print 'Stopped Early'
win.close()
core.quit()
print x_rand, y_rand
print keys, rt #display response and reaction time on screen output window
It's not a variable you want, but a function.
The way you are currently doing things (via visual.Line(...).draw()) is very inefficient. You're creating a new line on very iteration, just to draw it once, and not storing a reference to it. A much more time-efficient scheme is to create just a single line object instance, referenced with a variable name, and then on every iteration, simply update its attributes (orientation etc), before drawing it.
An alternative would be to create multiple line object instances once, but store each in a list. Then drawing them again as required is a simple matter of:
for line_instance in line_list:
line_instance.draw()