How to display an Image with python, without pyglet or similar? - python

So, what I am trying to do in detail:
I have a device that acts as a display, although is technically not one (that's not really important, it can be handled like a normal display) and I want to display a series of images on it. When each image is displayed i call a function that takes readings from another device. So far I have used pyglet for that and I can get it to display the images in the correct order and where I want them, but the readings taken seem not to correspond to the right image.
The simplest way to explain what I want to do is:
for a in range(10):
display('image%d'%a)
values(a) = measure()
Imagine values being initiated in the correct form.
What I tried so far was:
import pyglet
import numpy as np
size = 64
no = 512/size
a,b,c = (0,0,0)
values = np.zeros((no,no,3))
display = pyglet.window.get_platform().get_default_display()
screens = []
for screen in display.get_screens():
screens.append(screen)
window = pyglet.window.Window(screen = screens[1], fullscreen=1)
#here i choose the mentioned device, since it is connected to my computer via display port
#window.event
def update(dt):
global a,b,c
if a == no/2. and b == no/2.:
values[a,b,c] = 0
window.clear()
else:
image = pyglet.image.load('folder_%d/grating_%d_%d_%d.bmp' % (size,a,b,c))
window.clear()
print (a,b,c)
image.blit(0,0)
values[a,b,c] = measure()
c+=1
if c == 3:
b += 1
c = 0
if b == no:
a += 1
b = 0
if a == no:
pyglet.app.exit()
pyglet.clock.schedule_interval(update, .2)
pyglet.app.run()
where measure() is my own function. "no" is an index for my images, they range from (0,0,0),(0,0,1),(0,0,2),(0,1,0)... to (no,no,2) and are called to be called one by one. Also the case of a = b = no/2 is a special case that is of no special importance to my problem, I think.
first of all: I am pretty sure this is neither elegant nor efficient but I am not creating software that anyone else is ever likely to use. I am also aware that using global variables is bad practice but their use is due to me not knowing how to use eventloops correctly.
I am not happy with this solution, because the readings i take always seem to correspond to the previous image.
I guess I misuse the eventloop badly, but the pyglet documentation does not really help me here.
Also I feel like I am building a whole truck just to carry a bag across the street...
I have already looked into pyplot as an alternative, since the imshow() function works in the way I want, but the plotting libraries seem to display images in random sizes, which I cannot figure out how to control properly.
I appreciate any help on using pyglet correctly as well as alternative libraries that can help.
Thank you already,
Mopsi

An extra-long comment, that requires formatted code
From your example, you don't need a,b,c outside of the update function and all the global stuff is about having values that stay alive across invocations. If I'm correct this is better suited by a closure, like
...
def make_update(no, window):
from itertools import product
abcs = product(range(no),range(no),range(3))
#window.event
def _update(...):
try:
a, b, c = next(abcs)
except StopIteration:
... wind up ...
...
return _update
update = make_update(no, window)
...

Alright, I did not actually solve the problem but found a workaround:
I just flatten my image nomenclature, e.g
0_0_0 -> 000
0_0_1 -> 001
0_0_2 -> 002
0_1_0 -> 003
etc.
With values now being an array with dimensions [no*no*3,1]
And since for the n-th iteration and therefore n-th measurement I see the (n-1)th image, I simply add a dummy image and assign the n-th measured value to values[n-1].
The first measurement being useless is no problem here, since values[-1] is the last element, which gets overwritten with a meaningful measurement in the end.
Since the number of images is known and predetermined I can reshape my array of values afterwards.
If anyone cares to explain why no the displayed image is shifted by one iteration (with no image at all being displayed at the first iteration) please go ahead.

Related

How can I stop QBarGraph data going off the edge of the graph?

I am using PySide2.QtCharts in order to get a graph to display.
I have scoured the internet for hours and nobody else appears to have this problem, which means it's either ridiculously obscure, or that I'm missing something painfully obvious.
The data I have displaying in my Graph is centering itself in the graph, and as a result is flowing off the side of the graph so that it is unviewable.
This is currently how it is displaying. The fact that the blue and green columns are going off to the right is fine, it's the fact the orange column is off the top so far that it is unviewable.
This is ideally how I want it to look. The columns are thinner and are actually viewable. The length of the columns in this one are statically placed just for my testing purposes to see if it was actually working or not.
I know what you are thinking, 'well you have a working version - just put the data in that' - the data being inputted in my not working example is taken from a for loop which it iterating over different data, which in theory should not be causing any issues, but evidently it is doing so.
I'm not concerned about the data causing issues if I can fix it after the fact, which is the crux of the question I am asking. Is there any way to set the column width manually, and change the position of where the graphing starts? (for example, the bottom rather than the middle)
My (not working) code:
series = QtCharts.QHorizontalBarSeries()
set = QtCharts.QBarSet(name)
if value != None and value != '0':
set << float(value)
series.append(set)
else:
pass
index_chart = QtCharts.QChart()
index_chart.addSeries(series)
x_axis = QtCharts.QValueAxis()
x_axis.setRange(0, 100)
index_chart.setMaximumHeight(500)
index_chart.createDefaultAxes()
index_chart.setAxisX(x_axis, series)
chartView = QtCharts.QChartView(index_chart)
The working example code:
testseries = QtCharts.QHorizontalBarSeries()
set0 = QtCharts.QBarSet('test')
set1 = QtCharts.QBarSet('test')
set2 = QtCharts.QBarSet('test')
set0 << 50
set1 << 25
set2 << 85
testseries.append(set0)
testseries.append(set1)
testseries.append(set2)
index_chart = QtCharts.QChart()
index_chart.addSeries(testseries)
x_axis = QtCharts.QValueAxis()
x_axis.setRange(0, 100)
index_chart.setMaximumHeight(500)
index_chart.createDefaultAxes()
index_chart.setAxisX(x_axis, series)
chartView = QtCharts.QChartView(index_chart)
There really isn't any difference in how the two are functioning, so this is more if anyone can see a reason why it would be acting the way it is. But, I'm the one having a problem, so I could be wrong. Thanks in advance!

How to choose the closest object considering size

I'm working on an agent based simulation. I want each agent to choose which other agent to focus on. There are a lot of different inputs, but here I'm asking about the vision one. So the agent has to see which other agent is closest also considering size. They should care about bigger things more than smaller things, a tiny agent very close is not as big of an issue as a huge agent a tiny bit away. It seems fine so far except that considering who is closest and big also considers others that are out of the visual range.
I have this so far:
# both seen and viewer are two different groups
def sight(seen, viewer)
for entity in viewer:
# This is needed later to decide which way to go, not used here
currentDir = entity.Direction
# Figure out where the viewer is
pos = pygame.math.Vector2(entity.rect.centerx, entity.rect.centery)
# Find out who is closest.
# Uses viewer location and location of each agent in the other group to see who is closest.
# At the end, divided by size*size of the agent in the other group (for height / width).
# Otherwise they'd pay attention to a tiny agent that's close by
# instead of a huge agent that's just a bit further away.
closeby = min([e for e in seen.sprites()], key=lambda e: (pos.distance_to(pygame.math.Vector2(e.rect.centerx, e.rect.centery)) / (e.size * e.size)))
vector = pygame.math.Vector2((entity.rect.centerx - closeby.rect.centerx), (entity.rect.centery - closeby.rect.centery))
# Get the distance to that other agent
distance = math.hypot(entity.rect.centerx - closeby.rect.centerx, entity.rect.centery - closeby.rect.centery)
# They can't see forever, so they have a sight limit
if distance < entity.sight:
Blah blah, rest of the code here
Here's the problem: The "if distance < entity.sight" coming AFTER they choose "closeby" means that they might "choose" a big agent as the closeby who is then eliminated because they're too far away.
Imagine this: I'm agent X. There's someone small I should worry about (agent Y) who is within my visual range. However, there's someone (agent Z) who is really big that is outside of my visual range. Agent Z is so big I choose him as the "closeby". Then he's outside of the visual range so no one gets selected by the "if distance < entity.sight". Now no one is selected even though agent Y is close enough he should have been selected.
I feel like either the search
closeby = min([e for e in etc etc etc
should be limited to who is within the visual range (but I don't know how to do that), or that if the agent chosen as "closeby" is outside of the visual range, the SECOND closest should be chosen. If they're again out of the visual range, the THIRD closest should be chosen, etc, until it gets someone in the visual range. But I'm not sure how to do that either.
Any help anyone can offer in restricting "min([e for e in blah blah" or for choosing the next min in that group if the first doesn't mean "entity.sight" criteria would be extremely appreciated. I feel like the second option (iterating through the group) is more likely to be possible, but I'm pretty new to python so I don't know.
Thank you all so much!
Either use the loop to find the closest and also visible element:
import math
def sight(seen, viewer)
for entity in viewer:
currentDir = entity.Direction
entityPos = pygame.math.Vector2(entity.rect.center)
minE = None
minCloseByDist = math.inf
for e for e in seen.sprites():
ePos = pygame.math.Vector2(e.rect.center)
distance = entityPos.distance_to(ePos)
if distance < entity.sight:
closeByDist = distance / (e.size * e.size)
if minE == None or closeByDist < minCloseByDist:
minE = e
minCloseByDist = minE
if minE != None:
# [...]
Or you can find all elements in view first and then the closest element:
def sight(seen, viewer)
for entity in viewer:
currentDir = entity.Direction
entityPos = pygame.math.Vector2(entity.rect.center)
inSight = [e for e in seen.sprites() if entityPos.distance_to(pygame.math.Vector2(e.rect.center)) < entity.sight]
if inSight:
closeby = min([e for e in inSight], key=lambda e: (pos.distance_to(pygame.math.Vector2(e.rect.center)) / (e.size * e.size)))
# [...]

Trialhandler and time measuring in psychopy

For a go-NoGo Task I want to organize pictures with the data.TrialHandler class from psychopy:
trials = data.TrialHandler(ImageList, nReps=1, method='random')
Now I want to code a loop in which psychopy is going into the dictionary, is presenting the first set of pictures (e.g. A_n) and afterwards is going to the second set until the sixth set. I tried the following:
import glob, os, random, sys, time
import numpy.random as rnd
from psychopy import visual, core, event, monitors, gui, logging, data
im_a = glob.glob('./a*') # upload pictures of the a-type, gives out a List of .jpg-files
im_n = glob.glob('./n*') # n-type
im_e = glob.glob('./e*') # e-type
# combining Lists of Pictures
A_n = im_a + im_n
N_a = im_n + im_a
A_e = im_a + im_e
E_a = im_e + im_a
E_n = im_e + im_n
N_e = im_n + im_e
# making a Dictionary of Pictures and Conditions
PicList = [A_n, N_a, A_e, E_a, E_n, N_e] # just the six Combinations
CondList = [im_a,im_n,im_a,im_e,im_e,im_n] # images that are in the GO-Condition
ImageList = []
for imagelist, condition in zip(PicList, CondList):
ImageList.append({'imagelist':imagelist,'condition':condition}) # to associate the picturelist with the GO Conditionlist
for the header I ask an extra question: Combining and associating multiple dictionaries
# Set Experiment
win = visual.Window(color='white',units='pix', fullscr=False)
fixCross=visual.TextStim(win,text='+',color='black',pos=(0.0,0.0), height=40)
corrFb = visual.TextStim(win,text='O',height=40,color='green',pos=[0,0])
incorrFb = visual.TextStim(win,text='X',height=40, color='red',pos=[0,0])
# Start Experiement
trials = data.TrialHandler(ImageList, nReps=1, method='random')
rt_clock = core.Clock()
bitmap = visual.ImageStim(win)
for liste in ImageList[0:5]: # to loop through all 6 conditions
keys = []
for i,Pictures in enumerate(liste): # to loop through all pictures in each condition
bitmap.setImage(Pictures) # attribute error occurs, not if I use Pictures[0][0], even though in this case every pictures is the same
bitmap.draw()
win.flip()
rt_clock.reset()
resp = False
while rt_clock.getTime() < 2.0: # timelimit is defined 2 s
if not resp:
resp = event.getKeys(keyList=['space'])
rt = rt_clock.getTime()
if bool(resp) is (Pictures in CondList): # at this point python should have access to the Dictionary in which the associated GO Pictures are saved
corrFb.draw()
accu=1 # doesn't work yet
else:
incorrFb.draw()
accu=0
win.flip()
core.wait(0.5)
trials.addData('rt_'+str(i), rt) # is working well when loop: if trial in trials: ...; in this case trialHAndler is not used, therefor trials.addData is not working
trials.addData('accu_'+str(i), accu)
trials.saveAsExcel(datanames)
core.quit()
There are a few problems in this code: first it only presents one pictuere for six times, but not six different pictures [1]
and secondly a totally different problem [2] ist the time measuring and the saving of the accuracy which the trialhandler is doing, but for each trial. So it adds up all the RT's for each trial. I want to get the RT's for each image. I tried a few things like an extra stimulus.trialhandler for the stimuli and an extraloop in the end which gives me the last RT but not each. --> is answered below!!!
for stimuli in stimulus: stimulus.addData('rt', rt)
I know these four questions are a lot for one question, but maybe somebody can give me some good ideas of how I can solve these... Thanks everybody!
The reason for your problem labelled [1] is that you set the image to PicList[0][0] which never changes. As Mike is suggesting above you need::
for i,thisPic in enumerate(PicList):
bitmap.setImage(thisPic) #not PicList[0][0]
But maybe you need to go back to basics so that you actually use the trial handler to handle your trials ;-)
Create a single list of dictionaries where one dictionary represents one trial, and then run through those in order (tell the TrialHandler to use the list 'sequential' rather than 'random'). So the loops that you're currently using should just be to create your list of condition dicts, not to run the trials. Then pass that one list to the trial handler::
trials = TrialHandler(trialTypes = myCondsListInOrder, nReps=1, method='sequential')
for thisTrial in trials:
pic = thisTrial['pic']
stim.setImage(pic)
...
trials.addData('rt', rt)
trials.addData('acc',acc)
Also, I would output your data not using the excel format, but the 'long wide' format::
trials.saveAsWideText('mydataFile.csv')
best wishes,
Jon
(A) This isn't relevant to your question but will improve performance.
The line:
bitmap = visual.ImageStim(win)
Shouldn't occur within the loop. i.e. you should initialise each stimulus only once, then within a loop you just update that the properties of that stimulus, e.g. with bitmap.setImage(…). So shift this initialisation line to the top, where you create the TextStims.
(B) [deleted: I hadn't paid attention to the first code block.]
(C)
bitmap.draw(pictures)
This line doesn't take any arguments. It should just be bitmap.draw(). And anyway, it isn't clear what 'pictures' refers to. Remember that Python is case sensitive. This isn't the same thing as 'Pictures' defined in the loop above. I'm guessing that you want to update what picture is being shown? In that case, then you need to be doing the bitmap.setImage(…) line within this loop, not above, where you will always be drawing a fixed picture as that is the only one that gets set on each trial.
(D) Re the RTs, you are saving this only once per trial (check the indentation). If you want to save one per image, you need to indent these lines again. Also, you only get one line per trial in the data output. If you want to record multiple RTs per trial, you will need to give them unique names, e.g. rt_1, rt_2, …, rt_6 so they each appear in a separate column. e.g. you could use an enumerator for this loop:
for i, picture in enumerate(Piclist)
# lots of code
# then save data:
trials.addData('rt_'+str(i), rt)

What is the most effective way to incremente a large number of values in Python?

Okay, sorry if my problem seems a bit rough. I'll try to explain it in a figurative way, I hope this is satisfactory.
10 children. 5 boxes. Each child chooses three boxes. Each box is opened:
- If it contains something, all children selected this box gets 1 point
- Otherwise, nobody gets a point.
My question is about what I put in bold. Because in my code, there are lots of kids and lots of boxes.
Currently, I proceed as follows:
children = {"child_1" : 0, ... , "child_10": 0}
gp1 = ["child_3", "child_7", "child_10"] #children who selected the box 1
...
gp5 = ["child_2", "child_5", "child_8", "child_10"]
boxes = [(0,gp1), (0,gp2), (1,gp3), (1,gp4), (0,gp5)]
for box in boxes:
if box[0] == 1: #something inside
for child in box[1]:
children[child] += 1
I worry mainly about the for loop that assigns each child an extra point. Because in my final code, I have many many children, I fear that doing so would slow the program too.
Is there a more efficient way for all children of the same group may have their point faster?
Represent children as indices into arrays, not as strings:
childrenScores = [0] * 10
gp1 = [2,6,9] # children who selected box 1
...
gp5 = [1,4,7,9]
boxes = [(0,gp1), (0,gp2), (1,gp3), (1,gp4), (0,gp5)]
Then, you can store childrenScores as a NumPy array and use advanced indexing:
childrenScores = np.zeros(10, dtype=int)
...
for box in boxes:
if box[0]:
childrenScores[box[1]] += 1 # NumPy advanced indexing
This still involves a loop somewhere, but the loop is deep inside NumPy instead, which should provide a meaningful speedup.
The only speed up that I can think of is to use numpy arrays and stream the sum operation.
children[child] += np.ones(len(children[child]))
You should benchmark the operation and see if that is too slow for your business case.
What I would do
In the gpX lists don't save the "name of the child" (e.g. "child_10") but save a reference to the child's number of points.
How to do that
Using the fact that lists are objects in python, you can:
Change the children dict to look like: children = {"child_0": [0], "child_1": [0], ...} and so on.
When you assign to group, don't assign the key but assign the value (e.g. gp1.append(children["child_0"])).
The loop should then look like: for child in box[1]: child[0]+=1. This WILL update the children dict.
EDIT:
Why this is faster:
Because you leave out the part where you search for children[child], which might be costly.
This technique works because by storing the totals in a mutable type, and appending those values to the group lists, both the dict value and each box's list value will point to the same list entries, and changing one will change the other.
Two general points:
(1) Based on what you've told us, there's no reason to focus your energy on minor performance optimizations. Your time would be better spent thinking about ways to make your data structures less awkward and more communicative. A bunch of interrelated dicts, lists, and tuples quickly becomes difficult to maintain. For an alternative, see the example below.
(2) As the game designer, you understand that events follow a certain sequence: first the kids select their boxes, and later they discover whether they get points for them. But you don't have to implement it that way. A kid can choose a box and get points (or not) immediately. If there's a need to preserve the child's ignorance about such outcomes, the parts of your algorithm that depend on such ignorance can enforce that veil of secrecy as needed. The upshot: there is no need for a box to loop through its children, awarding points to each one; instead, award the points immediately to kids as boxes are selected.
import random
class Box(object):
def __init__(self, name):
self.name = name
self.prize = random.randint(0,1)
class Child(object):
def __init__(self, name):
self.name = name
self.boxes = []
self.score = 0
self._score = 0
def choose(self, n, boxes):
bs = random.sample(boxes, n)
for b in bs:
self.boxes.append(b)
self._score += b.prize
def reveal_score(self):
self.score = self._score
boxes = [Box(i) for i in range(5)]
kids = [Child(i) for i in range(10)]
for k in kids:
k.choose(3, boxes)
# Later in the game ...
for k in kids:
k.reveal_score()
print (k.name, k.score), '=>', [(b.name, b.prize) for b in k.boxes]
One way or another, you're going to be looping over the children, and your answer appears to avoid looping over children who don't get any points.
It might be slightly faster to use filter or itertools.ifilter to pick the boxes that have something in them:
import itertools
...
for box in itertools.ifilter(lambda x: x[0], boxes):
for child in box[1]
children[child] += 1
If you don't need to immediately print the number of points for every child, you could calculate it on demand, thus saving time. This could help if you only need to query a child every now and then for how many points it has. You can cache each result as you obtain is so you don't go about calculating it again the next time you need it.
Firstly, you'll need to know which groups a child belongs to. We'll store this information as map we'll call childToGroupsMap, which will map each child to an array holding the boxes it belongs to, like so:
childToGroupsMap = {}
for child in children:
childToGroupsMap[child[0]] = []
for box in boxes:
for child in box[1]:
if (box[1] not in childToGroupsMap[child]):
childToGroupsMap[child].append(box[1])
This constructs the reverse map from children to boxes.
It'll also help to have a map from each box to a boolean representing whether it's been opened:
boxToOpenedMap = {}
for box in boxes:
boxToOpenedMap[box[1]] = box[0]
Now, when someone queries how many points a child has, you can go through each of the boxes it belongs to (using childToGroupsMap, of course), and simply count how many of those boxes have been mapped to 1 in the map boxes:
def countBoxesForChild(child):
points = 0
for box in childToGroupsMap[child]
if boxToOpenedMap[box] == 1:
points += 1
return points
To make this better, you can cache the resulting number of points. Make a map like so:
childToPointsCalculated = {}
for child in children:
childToPointsCalculated[child[0]] = -1
Where the -1 denotes that we don't yet know how many points this child has.
Finally, you can modify your countBoxesForChild function to exploit the cache:
def countBoxesForChild(child):
if childToPointsCalculated[child] != -1
return childToPointsCalculated[child]
points = 0
for box in childToGroupsMap[child]
if boxToOpenedMap[box] == 1:
points += 1
childToPointsCalculated[child] = points
return points

Python - How to track (add/remove) lots of class instances over mulitple iterations?

I am building a dynamic map of earthquakes, using the vtk library.
I've already made a static one, (see here: https://github.com/yacobuk/QuakeCloud and here: http://www.youtube.com/watch?v=4HVdTcI_ozI) so I know the basic idea works, but now I want to try and show the quakes over time.
I have some code examples that show me how to update the frame, and how to add / remove objects, but I'm stuck on figuring out how to spin up an instance, track it for a few periods, then remove it.
The basic add/ remove code looks like this:
for point_and_mag in pm.points_mag:
time.sleep(0.5)
mag = point_and_mag[1]
point = point_and_mag[0]
if mag > 2:
pointCloud = VtkPointCloud(pm)
pointCloud.addPoint(point, math.log(mag)*10)
renderer.AddActor(pointCloud.vtkActor)
renderer.ResetCamera()
renderWindow.Render()
time.sleep(0.3)
renderer.RemoveActor(pointCloud.vtkActor)
renderer.ResetCamera()
renderWindow.Render()
But of course, this only allows one object at a time (an instance of pointCloud.vtkActor via renderer.AddActor(pointCloud.vtkActor) waits a while, then removes it with renderer.RemoveActor(pointCloud.vtkActor)
How can I add a number of actors (I'm going to use 10 min interval, and there was as many as 5 quakes in that time), tag it with a counter, increment the counter at every loop iteration, and when it reaches 5 iterations, remove the actor?
There is some more context to this question here: Python/vtk - set each point size individually in a vtkPolyData object?
A possible(untested) solution might be:
from collections import deque
# The number 5 indicates for how many iterations the actors should be rendered.
rendered_actors = deque([None] * 5, maxlen=5)
for point_and_mag in pm.points_mag:
if rendered_actors[-1] is not None:
renderer.removeActor(rendered_actors[-1])
renderer.ResetCamera()
renderWindow.Render()
time.sleep(0.5)
mag = point_and_mag[1]
point = point_and_mag[0]
if mag > 2:
pointCloud = VtkPointCloud(pm)
pointCloud.addPoint(point, math.log(mag)*10)
rendered_actors.appendleft(pointcloud.vtkActor)
renderer.AddActor(pointCloud.vtkActor)
renderer.ResetCamera()
renderWindow.Render()
else:
rendered_actors.appendleft(None)
This code creates a deque(which is a double-linked list) of length 5. The actors are inserted at the left of this deque and at each iteration the rightmost value, if it is an "actor", it is removed from the scene and the scene is re-rendered.
Note that I don't have vtk so I cannot test this code.
A small style note: this is really unpythonic code-style:
for point_and_mag in pm.points_mag:
mag = point_and_mag[1]
point = point_and_mag[0]
Use tuple-unpacking:
for point, mag in pm.points_mag:
# ...
if mag > 2:
# ...

Categories