How do i make a moving polygon disappear at a certain position? - python

I'm new to Python and Psychopy and have to do a project for university. I think it's a rather easy question, but i can't seem to figure it out.
I'm supposed to make a time-to-contact-task. The idea is that i have a polygon (a triangle) that moves on the x-axis from the left side of the screen to the right. At the right side of the screen is another polygon (a vertical line) that doesn't move. The testperson should press a key if the triangle is at the same position as the line. The moving triangle should disappear at a certain point (around the middle of the screen), so that the testperson should have to guess the arrival time of the triangle at the line.
Right now, this is my code:
at 'Begin routine':
Zeit = core.MonotonicClock()
origpos = meinPolygon.pos
aktpos = origpos
at 'Each frame':
aktpos[0] = origpos[0] + float(Geschwindigkeit) *(Zeit.getTime()*Beschleunigung)
aktpos[1] = origpos[1] + float(0) * Zeit.getTime()
meinPolygon.pos = aktpos
if aktpos = [1]:
polygon.opacity(0)
if aktpos[0] = polygon.pos[0]:
print(Zeit)
So i was thinking, that if the moving polygon reaches a certain position (eg. x=1), the opacity should change to 0, so that the polygon isn't visible anymore. But my code doesn't seem to work this way (Syntax Error). And i'm not sure how to put the x and y value of the position? I don't care about y, because its always 0.
And we want the time printed, when the triangle meets the line, so that we can calculate the reaction-time of the testperson.
I hope i described the situation understandable.
Thanks in advance for your help!

here is a version for using PsychoPy without the Builder tool:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from psychopy import core, info, visual, event
from psychopy import monitors
from psychopy.constants import NOT_STARTED, STARTED, FINISHED
from psychopy.iohub.client import launchHubServer
#INIT
io = launchHubServer()
display = io.devices.display
kb = io.devices.kb; mouse = io.devices.mouse
mon = monitors.Monitor(name = display.getPsychopyMonitorName(), autoLog = True)
win = visual.Window([1440, 900], units='pix', monitor = mon, winType='pyglet',
fullScr = False, waitBlanking = True, useFBO = True, useLights = False,
allowStencil=False, allowGui = True, screen = display.getIndex())
win._setupGL(); core.wait(.1)
runtime_info = info.RunTimeInfo(win = win, refreshTest = 'grating', verbose = True)
win_w = runtime_info['windowSize_pix'][0]; win_h = runtime_info['windowSize_pix'][1]
#suppose BEGIN ROUTINE?
LOCATION_TOLERANCE = 4 #screen pixels
POLYGON_SPEED = 0.1 #pixels per frame
POLYGON_ACCEL = 1.005
mainPolygon = visual.Polygon(win, edges=3, radius=50, units='pix', pos=(-win_w/2*0.75,0),
lineColor=[0, 1, 0], fillColor=[0, 1, 0], interpolate=False, autoDraw=True)
targetPolygon = visual.Polygon(win, edges=4, radius=20, units='pix', pos=(win_w/2*0.60,0), ori=45,
lineColor=[1, 1, 1], fillColor=[1, 1, 1], interpolate=False, autoDraw=True)
#ROUTINE
global_monotonic = core.MonotonicClock(); trial_clock = core.Clock()
future_flip_time = win.getFutureFlipTime(clock='now')
trial_clock.reset(-future_flip_time)
t = 0; frame_n = -1
mainPolygon.status = NOT_STARTED; routine_running = True
mainPolygon.t_thresholded, mainPolygon.t_targetreached, mainPolygon.t_keypressed = 0.0, 0.0, 0.0
while routine_running:
t = trial_clock.getTime(); frame_n = frame_n + 1
#suppose EACH FRAME?
if routine_running:
curr_xpos, curr_ypos = mainPolygon.pos[0], mainPolygon.pos[1]
mainPolygon.setPos((curr_xpos + POLYGON_SPEED, curr_ypos), log=True)
POLYGON_SPEED *= POLYGON_ACCEL
if curr_xpos > LOCATION_TOLERANCE and not mainPolygon.t_thresholded:
mainPolygon.t_thresholded = global_monotonic.getTime()
mainPolygon.setOpacity(0)
print(f"THRESHOLD LOCATION: trial_clock = {t:.3f}, frame_n = {frame_n:d}")
#FIXME use psychopy.visual.helpers.pointInPolygon() or polygonsOverlap()
if targetPolygon.pos[0] - curr_xpos < LOCATION_TOLERANCE and not mainPolygon.t_targetreached:
mainPolygon.t_targetreached = global_monotonic.getTime()
print(f"TARGET REACHED: trial_clock = {t:.3f}; monotonic = {mainPolygon.t_targetreached:.3f}")
if len(event.getKeys(keyList=['space'])) and not mainPolygon.t_keypressed:
mainPolygon.t_keypressed = global_monotonic.getTime()
print(f"KEY PRESSED: trial_clock = {t:.3f}; frame_n = {frame_n:d}")
win.flip()
if (mainPolygon.t_keypressed and mainPolygon.t_targetreached):
POLYGON_SPEED = 0; mainPolygon.setOpacity(1)
routine_running = False;
if not routine_running:
break
#REPORT
print(f"")
print(f"REACTION DIFFERENCE: monotonic_diff = {mainPolygon.t_keypressed-mainPolygon.t_targetreached:.3f}")
win.flip(); event.waitKeys()
#FINALIZE
io.quit(); win.close()
core.quit()

A syntax error indicates you haven't got the characters correct in your code, like brackets that don't match etc. The logic may be fine. Take note of what the syntax error is pointing you to and check that line as well as the lines just above (sometimes an error on one line only shows up on the next).
In your case you have if aktpos = [1]: but a single = is for assignment. To test equality you need ==. This is a really common syntax error, even for experienced will make this typo so watch out for it.
There's actually at least one more problem though in your code because aktpos is always going to be a position with an x,y value. It will never be equal to [1] which is what you're currently (trying) to test. So the comparison isn't quite right. And how exact do you need that location to be? Think about what distance in x and y before you consider it to be a single location because I expect it will never be EXACTLY the same given that the stimulus can make sub-pixel movements

Related

How do I change my symbology in arcpy to have a clear outline point?

I am not sure why my arcpy result's point outline is not changing to clear in ArcGIS Pro. Everything else works, except for the outline syntax. Is there anything wrong with my syntax or this may be a ArcPro bug?
`#Add spatial join layer to the current map
p = arcpy.mp.ArcGISProject('CURRENT')
m = p.listMaps('CompTool')[0]
layer = Stream_Comp.getOutput(0)
m.addDataFromPath(layer)
#Format symbology rendering
l = m.listLayers(StreamComp_Name)[0]
sym = l.symbology
if sym.renderer.type == 'SimpleRenderer':
sym.updateRenderer('GraduatedColorsRenderer')
sym.renderer.classificationField = Comp_Field
sym.renderer.classificationMethod = 'NaturalBreaks'
sym.renderer.breakCount = 7
#Updating Symbology Rendering - error:nothing happens to the symbol outline
for brk in sym.renderer.classBreaks:
brk.symbol.size = 6
brk.symbol.outlineColor = {'RGB' : [0, 0, 0, 0]}`
I'm not sure if you put it there by mistake, but you have a " ' " at the end of your brk.symbol.outlineColor line. Not sure if it's in your code or not, but if that single quote is there, you're probably getting a mismatched quotes syntax error.

How to get instance objects to change position horizontally

I'm creating an instance python command where the primary purpose is to generate objects in neat horizontal rows. Even though I can randomize rotation and set the range, I still can't figure out how to get the objects to appear in horizontal rows.
I already tried to use the xform command to get the objects to move along the x coordinates.
import maya.cmds as MC
import random as RN
def ChainmailGenerator():
thing = MC.ls(sl=True)
print thing
if not thing:
MC.error (" ***Error - you need to select an object *** ")
# create a group node
grp = MC.group(empty=True, name=thing[0] + '_grp#')
#Loop though the items below with the range of a
for i in range (0,25):
instanceObj = MC.instance(thing, name=thing[0]+'instance#', smartTransform=True)
rx = RN.uniform(-1,1)*5
ry = RN.uniform(-1,1)*5
rz = RN.uniform(-1,1)*5
MC.rotate (rx,ry,rz, instanceObj)
MC.xform (r=True, ro=(90, 0, 0) )
tx = 5
MC.xform ( instanceObj, t=(0,15+1,0))
MC.parent (instanceObj,grp)
print "*** chainmail ***"
ChainmailGenerator()
The expectations are for the objects to generate in horizontal increments as if they're forming neat rows.
here is an example to create 10 spheres along x, moving them with xform :
step = 1
tx = 0
for x in range(10):
sphere = cmds.polySphere()[0]
cmds.xform(sphere, t=[tx,0,0])
tx+= step
The reason yours is placing everything in the same place now is because you aren't multiplying it against a value that keeps increasing. Normally you could hard-code some random value to space each one out, but this would yield inconsistent results.
Here's a generic way to go about it that seems to work with any object.
The idea is to use the mesh's bounding box to determine what the spacing should be by looking at the size of its x axis. You can also move it in place with xform, but you do need to include its worldspace parameter so that it doesn't move it relative to its current position.
import maya.cmds as cmds
def cloneInRow(count):
# Get selection.
thing = cmds.ls(sl=True)
if not thing:
cmds.error("You need to select an object")
# Get selection's mesh shape.
mesh = cmds.listRelatives(thing[0], shapes=True, f=True, ni=True, type="mesh")
if not mesh:
cmds.error("Unable to find a mesh on the selected object")
# Determine spacing by looking at object's bounding box. Use its `x` axis size.
bb_min = cmds.getAttr(mesh[0] + ".boundingBoxMin")[0]
bb_max = cmds.getAttr(mesh[0] + ".boundingBoxMax")[0]
spacing = bb_max[0] - bb_min[0]
# Create a root transform to parent to.
grp = cmds.group(empty=True, name=thing[0] + '_grp#')
# Create instance, and move it in place.
for i in range (0, count):
instanceObj = cmds.instance(thing[0], name=thing[0] + 'instance' + str(i), smartTransform=True)
cmds.xform(instanceObj, ws=True, t=(i * spacing, 0, 0))
cmds.parent(instanceObj, grp)
cmds.select(grp)
cloneInRow(10)
With this I can take this crossbow:
And clone any of its objects and get nice spacing:
The only catch is rotation. If your pivot isn't centered to the mesh, then randomizing its rotation will lose its place in space (since rotating would also effects its position!) So if you got weird pivots then it won't look nice when you add back on rotations.

Python-PPTX : Data Label Positions not working for Doughnut Chart

I have a Chart Placeholder, into which I have inserted a chart of chart_type 'DOUGHNUT'. I've added data labels to it and want to change their positions. For some reason, the method given in the documentation has no effect on my chart.
Here is my code, please help if I'm doing something wrong -
from pptx import Presentation
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE, XL_LABEL_POSITION, XL_DATA_LABEL_POSITION, XL_TICK_MARK, XL_TICK_LABEL_POSITION
chart_data = ChartData()
chart_data.add_series('', tuple(input_chart_data[x] for x in input_chart_data))
graphic_frame = content_placeholder.insert_chart(XL_CHART_TYPE.DOUGHNUT, chart_data)
chart = graphic_frame.chart
chart.has_legend = False
#Adding Data-Labels with custom text
chart.plots[0].has_data_labels = True
data_labels = chart.plots[0].data_labels
i = 0
series = chart.series[0]
for point in series.points:
fill = point.format.fill
fill.solid()
fill.fore_color.rgb = RGBColor(<color_code>)
point.data_label.has_text_frame = True
#Assigning custom text for data label associated with each data-point
point.data_label.text_frame.text = str(chart_data.categories[i].label) + "\n" + str(float(chart.series[0].values[i])) + "%"
for run in point.data_label.text_frame.paragraphs[0].runs:
run.font.size = Pt(10)
i+=1
data_labels.position = XL_LABEL_POSITION.OUTSIDE_END
PowerPoint is finicky about where you place certain chart attributes and feels free to ignore them when it wants (although it does so consistently).
A quick option worth trying is to set the value individually, point-by-point in the series. So something like:
for point in series.points:
point.data_label.position = XL_LABEL_POSITION.OUTSIDE_END
The most reliable method is to start by producing the effect you want by hand, using PowerPoint itself on an example chart, then inspecting the XML PowerPoint produces in the saved file, perhaps using opc-diag. Once you've identified what XML produces the desired effect (or discovered PowerPoint won't let you do it), then you can proceed to working out how to get the XML generated by python-pptx. That might make a good second question if you're able to get that far.
I made it work by writing the below code.
def apply_data_labels(self, chart):
plot = chart.plots[0]
plot.has_data_labels = True
for series in plot.series:
values = series.values
counter = 0
for point in series.points:
data_label = point.data_label
data_label.has_text_frame = True
data_label.text_frame.text = str(values[counter])
counter = counter + 1
the cause of error is setting the label position. no matter what you set it asks to repair the PPT. will have to drill down more to see why is it so.
Also to save some more time the formatting doesn't works(font color, size)
If anybody has any leads then please help.
To add on Vibhanshu's response, I could get the formatting (font type, font color, size etc) to work using the following code:
for idx, point in enumerate(chart.series[0].points):
# set position
point.data_label.position = XL_LABEL_POSITION.OUTSIDE_END
# set text
point.data_label.has_text_frame = True
point.data_label.text_frame.text = "This is an example"
# set formatting
for paragraph_idx, paragraph in enumerate(point.data_label.text_frame.paragraphs):
paragraph.line_spacing = 0.6 # set paragraph line spacing
for run in paragraph.runs:
run.font.size = Pt(30) #set font size
run.font.name = 'Poppins Medium' #set font name
run.font.color.rgb = RGBColor.from_string("FF0000") #set font color

Find closest point on mesh in specific axis (maya)

Let's say I have one locator above a polyPlane. What I want to do is a lookup or trace from the locator in negative or positive y until it hits the polyPlane and return the position of the closest point/vertex/uv/
I imagine this have been done one million times but the only examples I have found works by locating the closest point based on all axis which in my case is close to useless.
I would appreciate any help I could get!
Edit:
Added image of the difference between the first suggested solution and what I want to achieve
What we can do is use OpenMaya (Maya's API) to loop over the faceVerts gathered in an array, check to see which is shortest distance from the locator position compared to the current facevert, if it is shorter than the last shortest distance, save it as the closestVertex variable.
import maya.OpenMaya as OpenMaya
from pymel.core import *
geo = PyNode('pSphere1')
pos = PyNode('locator1').getRotatePivot(space='world')
nodeDagPath = OpenMaya.MObject()
try:
selectionList = OpenMaya.MSelectionList()
selectionList.add(geo.name())
nodeDagPath = OpenMaya.MDagPath()
selectionList.getDagPath(0, nodeDagPath)
except:
warning('OpenMaya.MDagPath() failed on %s' % geo.name())
mfnMesh = OpenMaya.MFnMesh(nodeDagPath)
pointA = OpenMaya.MPoint(pos.x, pos.y, pos.z)
pointB = OpenMaya.MPoint()
space = OpenMaya.MSpace.kWorld
util = OpenMaya.MScriptUtil()
util.createFromInt(0)
idPointer = util.asIntPtr()
mfnMesh.getClosestPoint(pointA, pointB, space, idPointer)
idx = OpenMaya.MScriptUtil(idPointer).asInt()
faceVerts = [geo.vtx[i] for i in geo.f[idx].getVertices()]
closestVertex = None
minLength = None
for v in faceVerts:
thisLength = (pos - v.getPosition(space='world')).length()
if minLength is None or thisLength < minLength:
minLength = thisLength
closestVertex = v
select(closestVertex)
This could probably be done with python without the API, but if you've got maya, you've got access to the API :)
I hope this helps

random selection by maya-python

my question is how can i select random numbers of points of (for example in this script) lattice or vertex of an object or face or everything or totally random selection from a list in python.
please first explain random selection on this script
cm.select('ffd1Lattice.pt[:][:][:]',r=True)
and please after that explain random selection on lists and on every method.
best regards
import maya.cmds as cm
import sys
import random as rand
myList = cm.ls ( sl = True)
def softIt(*arg):
cm.polySmooth( c = True , dv = 1 , kb = False )
def randomize(*arg):
myList = cm.ls ( sl = True)
for i in myList:
cm.lattice( dv=(4, 5, 4), oc=True )
cm.select('ffd1Lattice.pt[:][:][:]',r=True)
cm.xform( r = True , t = [ rand.uniform(-1,1) , rand.uniform(-1,1) , rand.uniform(-1,1)] )
cm.headsUpMessage('this script just work with one object at time', verticalOffset=250)
cm.window( t = 'Randomaize' , s = False)
cm.columnLayout()
cm.button( l = 'do it' , c = randomize , w = 200)
cm.button( l = 'soft it' , c = softIt , w = 200)
cm.showWindow()
sys.stdout.write("this script just work with one object at time\t\"script by Amin khormaei\"")
If you aren't understanding that little snippet then you should first understand how list slicing works. These links should point you in the right direction.
The line:
cm.select('ffd1Lattice.pt[:][:][:]',r=True)
says basically 'select all the control points in the lattice'. There seems to be a bug, however, in maya 2011 (don't know about later) which will try to select points that dont exist. A 1x1x1 lattice should have 8 points numbers 0-1 in all three dimensions - but using your snippet and then calling ls on the result will report
// result: 'ffdLatticeShape.pt[0:2][0:2][0:2]' //
... at least it does on my machine -- and that should be impossible. I'd avoid using the [:] form with lattices (actually the [*] form has the same bug too. Ouch.). It works fine with regular vertices, however.
For your specific application, do you want to move all of the points by the same random amount -- which is what your snippet suggests -- or all of the points by different random amounts? Or random sets of points by a random amount? the code would be different for each alternative.

Categories