Using Values from Lists in an equation/loop - python

I have a short list with coordinates: (0|0) (10|0) (10|10) (0|10). Im trying to use these coordinates to calculate the area of the square they build.
for loop should run 4 times and perfom the math written below.
when running i get the following error in the area = .... line:
TypeError: 'int' object is not subscriptable
list = [[0,10,10,0],[0,0,10,10]]
def gaussarea(coords):
area = 0
for coords in coords:
area = area + (coords[0][0] - coords[0][1]) * (coords[1][0]+coords[1][1])
return area
a = (gaussarea(list))

You are trying to access the index of an int, which is meaningless, since each coords is a list, not a nested list.
Assuming you get a rectangle (or square) for sure, you are good enough with
def gaussarea(coords):
area = (coords[0][1] - coords[0][0]) * (coord[1][2] - coords[1][1])
return area

the value of cords[0] is an int. Therefore cords[0][0] is trying to index into an int, hence your error. You can remove the for loop and your code should work.

Related

creating nested loop with dict data type

I'm running a loop to calculate abs(x-y) for n trials
my code:
for i in P0:
answer = (i['x']-i['y'])
A = (abs(answer))
returns the values for P0
P0 is the positions data for the first trial (P0 = T0['positions']).
Is there a way I can loop through all the positions (Pn) of all the trails (Tn) using a nested loop?
T type - list, of all the trails
Tn type - dict of the 1st trial
P type - list, of the positions (x,y) coordinates
Pn type - list
i tried:
for i in T:
Ti = T[i]
Pi = Ti['positions']
for i in Pi:
answer = (i['x']-i['y'])
A = (abs(answer))
but I get the error:
TypeError: list indices must be integers or slices, not dict.
Is there a way I can make this work as I'm not familiar with working with the dict data type
thanks
in your case i (the first one) is actually Ti you are searching for. try this:
for Ti in T:
Pi = Ti['positions']
for i in Pi:
answer = (i['x']-i['y'])
A = (abs(answer))
I am giving a detailed solution which is inefficient and funny but it will help a bit to understand how dictionary works.
abc_1 = {"ball":100, "bat":200}
abc_2 = {"green":10, "red":20}
key_1 = list(abc_1.keys())
key_2 = list(abc_2.keys())
for i in range (len(key_1)):
print(abc_1[([key_1][0][i])] - abc_2[([key_2][0][i])])
The output is:
90
180

Find Eucledian distance between landmarks of faces

I've got multiple frames and I've detected the faces in each frame using Retinaface. I would like to keep track of the faces using their landmarks.
To find the similarity between 2 landmarks, I tried to calculate the Eucledian distance :
Input :
landmark_1 = [1828, 911], [1887, 913], [1841, 942], [1832, 974], [1876, 976]
landmark_2 = [1827, 928], [1887, 926], [1848, 963], [1836, 992], [1884, 990]
After referring other links, I wrote the below function, but the values produced are very high :
def euclidean_dist(vector_x, vector_y):
vector_x, vector_y = np.array(vector_x), np.array(vector_y)
if len(vector_x) != len(vector_y):
raise Exception('Vectors must be same dimensions')
ans = sum((vector_x[dim] - vector_y[dim]) ** 2 for dim in range(len(vector_x)))
return np.sqrt(np.sum(ans**2))
Output :
euclidean_dist(landmark_1, landmark_2)
>> 1424.9424549784458
(Expecting some smaller value in this case)
I guess the code can only be used for an one dimensional vector, but I'm really stuck here. Any help would be really appreciated.
It looks like you're squaring the answer twice (ans**2). But you can also simplify the function somewhat:
def euclidean_dist(vector_x, vector_y):
vector_x, vector_y = np.array(vector_x), np.array(vector_y)
return np.sqrt(np.sum((vector_x - vector_y)**2, axis=-1))
This will automatically raise an exception when the vectors are incompatible shapes.
EDIT: If you use axis=-1 it will sum over the last axis of the array, so you can use a 2-D array of vectors, for example.
You can use linalg.nor too.
def euclidean_dist(vector_x, vector_y):
distances = np.linalg.norm(np.array(vector_x)-np.array(vector_y), axis=1)
return distances.tolist()

Nested for loop producing more number of values than expected-Python

Background:I have two catalogues consisting of positions of spatial objects. My aim is to find the similar ones in both catalogues with a maximum difference in angular distance of certain value. One of them is called bss and another one is called super.
Here is the full code I wrote
import numpy as np
def crossmatch(bss_cat, super_cat, max_dist):
matches=[]
no_matches=[]
def find_closest(bss_cat,super_cat):
dist_list=[]
def angular_dist(ra1, dec1, ra2, dec2):
r1 = np.radians(ra1)
d1 = np.radians(dec1)
r2 = np.radians(ra2)
d2 = np.radians(dec2)
a = np.sin(np.abs(d1-d2)/2)**2
b = np.cos(d1)*np.cos(d2)*np.sin(np.abs(r1 - r2)/2)**2
rad = 2*np.arcsin(np.sqrt(a + b))
d = np.degrees(rad)
return d
for i in range(len(bss_cat)): #The problem arises here
for j in range(len(super_cat)):
distance = angular_dist(bss_cat[i][1], bss_cat[i][2], super_cat[j][1], super_cat[j][2]) #While this is supposed to produce single floating point values, it produces numpy.ndarray consisting of three entries
dist_list.append(distance) #This list now contains numpy.ndarrays instead of numpy.float values
for k in range(len(dist_list)):
if dist_list[k] < max_dist:
element = (bss_cat[i], super_cat[j], dist_list[k])
matches.append(element)
else:
element = bss_cat[i]
no_matches.append(element)
return (matches,no_matches)
When put seperately, the function angular_dist(ra1, dec1, ra2, dec2) produces a single numpy.float value as expected. But when used inside the for loop in this crossmatch(bss_cat, super_cat, max_dist) function, it produces numpy.ndarrays instead of numpy.float. I've stated this inside the code also. I don't know where the code goes wrong. Please help

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.

Get x,y from 2d list and pass on

I'm trying to take a 2d list of locations that incl lat/ longs and get only the coordinates from the list (in column 3 and 4) to send to another function so that distances can be calculated... but I'm totally stumped.
What I have is...
EDITED from OP to show where I'm at...
x1 = -18.00 #These values don't change
y1 = 118.00
x2 = float(origList[3])
y2 = float(origList[4])
n = len(origList)
appList = []
for i in range (n-1):
appList.append(findDistance(x1, y1, x2, y2))
print appList
But now I get...File "F:\Storage\t_2\coord_find.py", line 27, in main,x2=math.fabs(origList[3])
TypeError: a float is required
So the problem is in the conversion to float???
Then all I have so far for the findDistance function (I only just started it and just want to test if arguments are being passed correctly)...
def findDistance(x1, y1, x2, y2):
cosX = math.fabs(y1 - y2)
a = 90 - x2
b = 90 - x1
Here's my updated code that is giving me this...
delx = math.fabs(y1 - y2)
TypeError: unsupported operand type(s) for -: 'float' and 'list'
I'm posting it up because I obviously didn't give a clear enough explanation and have made some changes since. AS you can see, I want to get the x2,y2 from cols 3,4.
Tried x2=float(origList[3]), y2=float(origList[4]) but that doesn't work either- I get "float()argument must be a string or a number".
Do I need to split the list somehow before trying to extract the values as floats??
import csv
import math
def fZone():
origList = [['200','12_7','Cons_pl','-20.10','120.10','C_10_T2'],['....'...]]
# origList has 30+ lines like this
x1 = -20.68 # Fixed point
x2 = 117.19 # Fixed point
n = len(origList) # list length
appList = [] # to hold returned
for i in range (n):
x2= origList[3] # I wanna get the '-20.10' col each iteration
y2= origList[4] # I wanna get the '120.10' col each iteration
appList.append(findDist(x1, y1, x2, y2))
print appList
def findDist(x1,y1,x2,y2):
delx = math.fabs(y1 - y2)
a = 90 - x2
b = 90 - x1 # formula is not finished
Your origList[0:] evaluates to origList. Try origList[0].
range(0,n-1) only goes up to n-2, and you have no need to specify the starting value of 0 since that's the default anyway. Use range(n).
You say the coordinates are in columns 3 and 4. It looks like you're somewhat new to indexing in a programming language, so I hope I don't offend with a gratuitous reminder that you might be looking for list elements 2 and 3, if you mean that these are the 3rd and 4th columns.
Also, the print should be outside the loop.
Apparently your list is containing pairs of strings, not of numbers.
In Python this conversion is never automatic so you will probably have to change the code to:
findDistance(x1, y1, float(origList[i][3]), float(origList[i][4]))
An error like
lat2= float(stnList[3])
TypeError: float() argument must be a string or a number
clearly says what was passed to float was neither a number nor a string.
Just add a print repr(stnList[3]) right before the offending statement and check out what was passed instead.
You can also the python debugger to find what the problem is, check for example this short video of a pdb session example

Categories