Maya - query animation curve data - python

I have a problem to query on deeper level Maya's animation curve data.
So as input I want to have an animation curve that is not connected to any attribure, just single node.
Having this I want to create a function that either returns:
Value with given time (I know that this can be easly done by connecting this anim curve to any attibute and then grabbing value by using command like: cmds.getAttr([objName]+'.'[attrName], t=[timeValue]...but how to do it without connecting animation curve to anything?)
Time with given value - I couldnt get it using any Maya commands and this is what I need the most.. :(
This is playing with bezier curve equation basicly but I'm pretty sure that Maya API is needed here but because Im very basic with API need your help:), any clues how to solve this? Thanks!!

You can use keyframe to query an anim curve's values that isn't connected to any attribute. Here's an example that will create an anim curve with 2 keys, print the key values, then print its value at each frame:
import maya.cmds as cmds
# Create an animation curve with 2 keys.
anim_curve = cmds.createNode("animCurveTL")
cmds.setKeyframe(anim_curve, t=0, v=0)
cmds.setKeyframe(anim_curve, t=10, v=10)
# Get its key count.
key_count = cmds.keyframe(anim_curve, q=True, keyframeCount=True)
# Iterate through key count and print all key values.
for i in range(key_count):
print cmds.keyframe(anim_curve, q=True, index=(i, i))[0]
# Get the scene's frame ranges.
start = int(cmds.playbackOptions(q=True, min=True))
end = int(cmds.playbackOptions(q=True, max=True))
# Iterate through each frame and print the anim curve's value.
for f in range(start, end):
print f, cmds.keyframe(anim_curve, q=True, eval=True, time=(f, f))[0]
Getting a value at a given time is easy enough, that's what the last portion is doing.
Getting a time with a given value isn't though, and you may need to re-think your approach. First of all it's possible to have the value during sub-frames, but I'm assuming you'd want to ignore that. Also you're trying to match a float value, which is tricky in programming. As a value of 3.5 will not match a value of 3.5000001, which is likely the kind of values the curve will have since it's interpolating between the keyed values.
But if you insist on doing it then you probably need to compare the value on every frame between the curve's first/last key times. When you compare the value you might need some threshold that is deemed acceptable, or close enough, to solve precision issues. If it passes then you can append the time to a list and return it later.
Hope that points you to the right direction.

Related

Python - How to get integrated values from np.array?

I am trying to get integrated values from np.array, list of values. Not the surface under the function, but values. I have values of acceleration and want to get values of velocity.
So let's say I have an arry like:
a_x = np.array([111.2, 323.2, 123.3, 99.38, 65.23, -0.19, -34.67])
And I try to get integrated values from this array to get the values of velocity.
If I use lets say simps, quad, trapz, I get the one number (surface).
So how do you integrate np.array values and get integrated values that you can store in a list?
You can't do it by the way you want it, because you didn't understand the process behind it. If you are given acceleration, then using the following equation:
You are able only to find INDEFINITE integral, you know the acceleration, but you don't know starting conditions, thus your solution can't be empty.
As the solution to each of those questions is: "Find velocity given an acceleration", then the solution would be v(t)=integral of a(t)dt+c, where your acceleration is constant, so it doesn't rely on t and it can be written as v(t)=at+c, but still - we don't know anything about how long acceleration lasted and what is the starting condition.
But answering the question about getting values which can be stored in a list - you do it by indexing your values of np.array:
import numpy as np
a_x = np.array([111.2,323.2,123.3])
#Gets first value
print(a_x[0])
If I use lets say simps, quad, trapz, I get the one number (surface).
Because quad,simps,or trapz are methods used for given points, which return value of integral with those given points with corresponding method, for example:
numpy.trapz(y, x=None, dx=1.0, axis=- 1)
if x isn't specified (as in your case), it assumes that you want to use trapeze to estimate the field under the value y of given points with x equal distribution of x. It has to give one value.

Appending line points with same slope to Python dict

I am trying to write a function where I can spit out all the points in the same line. I am calculating that by the fact, that the slope between two pairs of points must be same for that.
I have iterated through input file to get a list of points and calculated slope. My next step would be to put them on a HashMap (or Dict in Python), with the key being the slope and update it with points and slope. If slope for those two numbers is already present, add the points to same entry and remove any duplicates.
I was able to extract input, calculate slope and put them on in a hashmap. However, putting them on hashmap is a bit challenging for me as I am trying to use Java-like syntax which I am familiar with.
Can someone help me with updating the hashmap ensuring no dups are inserted?
here is what I have done so far:
slopeMap = {}
for x in range (0, len(arr)):
for y in range (x+1, len(arr)):
slopeForPoints = (slope(arr[x][0], arr[y][0], arr[x][1], arr[y][1]))
if slopeMap.has_key(slopeForPoints) == False:
slopeMap[slopeForPoints].append()
"slopeForPoints" in slopeMap
slopeMap["slopeForPoints"] =
a.setdefault("somekey",[]).append("bob")
print slopeForPoints
I just need help with the above function. Slope and iterate function I was able to get working.
Sample slope values (Key- HashMap)
0.0
1.0
0.0
0.9
Sample point values (Value - HashMap)
0.0,0.0
1.1,1.1
3.5,4.5
2.2,2.2
As mentioned by Mad Physicist, you need to calculate the more than just the slope to identify unique lines, as parallel lines would have the same slope but not necessarily be the same line.
There are a few options for this. One such option is to make the keys of your dictionary tuples, such as (slope, intercept). Then to make sure the points are unique, you could make the values for your dictionary sets of tuples.
The idea would look something like this:
slope, intercept = slope_intercept(point1, point2) #Each point is (point_x, point_y)
#Need to write the slope_intercept function
if (slope, intercept) not in slopeMap:
slopeMap[(slope,intercept)] = set() #Could be done with a defaultDict instead
slopeMap[(slope,intercept)].add(point1))
slopeMap[(slope,intercept)].add(point2))
Note, it's more Pythonic to say
if slopeForPoints not in slopeMap:

Callable variable in a loop

I'm having trouble in a loop.
I have a bunch of points (a 5-D space) saved in an array
Coords=[]
Coords.append(zip(x,y,z,t,w))
Coords=np.array(Coords,float)
so that I can call all coords of 1 particle by, for example
Coords[0,0]=[0.0.0.0.1.]
Coords[0,1]=[0.1,0.,0.,0.,0.9]
Coords[0,1,0]=0.1
Now, I need to calculate some properties for every particle, so I create a dicionary, where for every key(i.e. every particle) I compute somwthing
A={}
Aa=np.arange(0.0,1.0+0.001,0.001)
for s in range(len(Coords[0])):
A[s]=[]
for a in Aa:
if Coords[0,s,2]>=a and np.sqrt(Coords[0,s,0]*Coords[0,s,4])>=a:
A[s].append(a)
Here I get the proper dictionary, so I'm calling the varaibles Coords[0,s,0] and Coords[0,s,4] properly, there is no problem.
Now, this is where I have problems.
I need to compute another property for every particle for every value in A, therefore I create a dictionary of dictionaries.
L={}
for s in range(len(Coords[0])):
L[s]={}
for a in A[s]:
L[s][a]=[]
for i in Aa:
if (Coords[0,s,0]-i)*(Coords[0,s,4]-i)-a**2==0:
L[s][a].append(i)
Now I have a problem. The variables Coords are not called properly, there are missig values.
For example, the Coords[0,2,0]=0.1 and Coords[0,2,4]=0.6 should produce two values in the list: 0.1 and 0.6 (for a=0). However, in the list only appears the value 0.1, like the variable Coords[0,2,4]=0.6 doesn't exist.
However, if I write by hand the if condition like (for a=0)
if (0.1-i)*(0.6-i)-a**2==0
then I get the proper values.
Does anyone know why this is happening? Is it because I have dictionaries inside dictionaries?
Thanks.
In your second condition:
(Coords[0,s,0]-i)*(Coords[0,s,4]-i)-a**2==0:
Try using a tolerance for your comparison, something like:
abs((Coords[0,s,0]-i)*(Coords[0,s,4]-i)-a**2) < 10**-10
There's a more detailed description here:
Rounding errors with floats in Python using Numpy

Getting data of a box plot - Matplotlib

I have to plot a boxplot of some data, which I could easily do with Matplotlib. However, I was requested to provide a table with the data presented there, like the whiskers, the medians, standard deviation, and so on.
I know that I could calculate these "by hand", but I also know, from the reference, that the boxplot method:
Returns a dictionary mapping each component of the boxplot to a list of the matplotlib.lines.Line2D instances created. That dictionary has the following keys (assuming vertical boxplots):
boxes: the main body of the boxplot showing the quartiles and the median’s confidence intervals if enabled.
medians: horizonal lines at the median of each box.
whiskers: the vertical lines extending to the most extreme, n-outlier data points.
caps: the horizontal lines at the ends of the whiskers.
fliers: points representing data that extend beyone the whiskers (outliers).
So I'm wondering how could I get these values, since they are matplotlib.lines.Line2D.
Thank you.
As you've figured out, you need to access the members of the return value of boxplot.
Namely, e.g. if your return value is stored in bp
bp['medians'][0].get_ydata()
>> array([ 2.5, 2.5])
As the boxplot is vertical, and the median line is therefore a horizontal line, you only need to focus on one of the y-values; i.e. the median is 2.5 for my sample data.
For each "key" in the dictionary, the value will be a list to handle for multiple boxes. If you have just one boxplot, the list will only have one element, hence my use of bp['medians'][0] above.
If you have multiple boxes in your boxplot, you will need to iterate over them using e.g.
for medline in bp['medians']:
linedata = medline.get_ydata()
median = linedata[0]
CT Zhu's answer doesn't work unfortunately, as the different elements behave differently. Also e.g. there's only one median, but two whiskers...therefore it's safest to manually treat each quantity as outlined above.
NB the closest you can come is the following;
res = {}
for key, value in bp.items():
res[key] = [v.get_data() for v in value]
or equivalently
res = {key : [v.get_data() for v in value] for key, value in bp.items()}

Summing values from Python Dictionary

I am using Python to sum random star spectra to increase their signal to noise ratio. One of the keywords of these spectra header contains the integration time for the spectrum. When I sum the spectra I want the keyword of the resulting spectrum to be updated with the sum of the integration times of each spectrum I used. For that, I use the following code:
for kk in range(0,NumberOfSpectra): # main cycle
TotalIntegrationTime = 0.0
for item in RandomSpectraList: # secondary cycle
SpectrumHeader = SpectraFullList[item]['head'] #1
TotalIntegrationTime += SpectrumHeader['EXPTIME']
SpectrumHeader['EXPTIME'] = TotalIntegrationTime #2
SaveHeaderFunction(SpectrumHeader, kk)
the problem I am having, is that when the main cycle loops, SpectrumHeader does not get reset when I re-assign it in #1 and shows the value it had in #2. Any ideas on why this happens and how to fix it?
NumberOfSpectra is provided by the user, RandomSpectraList is a list of random spectra by name. SpectraFullList contains the spectra and has keys 'head' and 'spec'.
Are you aware of the fact during line #2, SpectrumHeader still points to an element of SpectraFullList? They are the really the same object.
So, when executing line #2 you are essentially modifying SpectraFullList.
I guess that is not what you want and it may be the cause of your problem.
In order to solve it, insert the following line before #2:
SpectrumHeader = SpectraFullList[item]['head'].copy()

Categories

Resources