Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bingham statistics #33

Open
Antoine-Cate opened this issue Mar 6, 2020 · 2 comments
Open

Bingham statistics #33

Antoine-Cate opened this issue Mar 6, 2020 · 2 comments

Comments

@Antoine-Cate
Copy link

Only Fisher stats are available in stereonet_math.py, and these are not ideal to calculate the mean value of a series of planes or lines.
A new function (bingham_stats) that would provide the orientation of the three axes and the Bingham best fit plane would be beneficial. I need to calculate these for a project, so I hope to be able to propose a solution to this issue within the next two months.

@joferkington
Copy link
Owner

joferkington commented Mar 6, 2020

Have you had a look at various functionality in https://github.com/joferkington/mplstereonet/blob/master/mplstereonet/analysis.py ?

For orientations, the axes are identical to what you'd get by estimating the full Bingham distribution. (You actually have to use the same method to estimate the axes when fitting a Bingham distribution -- it's still eigenvectors of the covariance matrix of orientations to get the axes.) You don't get the additional shape parameters of the distribution, of course, but the fitting methods there may very well do what you need.

That having been said, I'd welcome a bingham_stats function, though it should go in analysis instead of stereonet_math, as fisher_stats should have originally.

@stims99
Copy link

stims99 commented Jul 12, 2023

Ugly piece of code but this does bingham stats:
def eigvector(w, v, list):
esort = np.argsort(w)

for c in esort:
    
    t = round(np.degrees(math.atan(v[0,c]/v[1,c]) + math.pi if v[1,c] < 0 else math.atan(v[0,c]/v[1,c])),2)
    t = t if t > 0 else t + 360
    p = round(np.degrees(math.asin(v[2,c])),2)
    
    
    if p < 0:
        dip = 90 + p
        dipdir = t
    else:
        dip = 90 - p
        dipdir = t + 180 if t < 180 else t - 180

    list.append([dip,dipdir])

def dir_cos(value):
lm = np.inner(value.Jx, value.Jy)
ln = np.inner(value.Jx, value.Jz)
mn = np.inner(value.Jy, value.Jz)
l2 = np.inner(value.Jx, value.Jx)
m2 = np.inner(value.Jy, value.Jy)
n2 = np.inner(value.Jz, value.Jz)

return np.array([l2,lm,ln, lm,m2,mn, ln, mn, n2]).reshape(3,3)

#initialize empty dictionaries
dict_mean = dict()
#dict_ori is a dictionary for each joint set
#loop through each joint set and compute bingham stats

for key, value in dict_ori.items():
value = value.reset_index(drop = True)
#directional cosine matric
dcm = sp.dir_cos(value)

#hermitian matrix to return eigenvalues
w, v = np.linalg.eigh(dcm, UPLO = 'L')
#compute the unit eigenvalues, makes converting to dip/dip azimuth easier
w_unit = np.around(w/np.sum(w),decimals =3)

#make sure eigenvectors sorted small to large (e3, e2, e1)
esort = np.argsort(w)

#initialize an empty list
ori_list = []

#calculate the eigenvector dip and dip azimuth (in degrees). rotate/flip if plotting in upper hemisphere
sp.eigvector(w, v, ori_list)

ori_list.append([w_unit.tolist(), len(value)])
ori_flat = [item for sublist in ori_list for item in sublist]

dict_mean[key] = ori_flat

ori_cols = ['e3-Dip', 'e3-Dip Az.', 'e2-Dip', 'e2-Dip Az.', 'e1-Dip', 'e1-Dip Az.', 'Eigenvalues', 'Count']

df_mean = pd.DataFrame.from_dict(dict_mean, orient = 'index', columns = ori_cols)
df_mean.sort_index()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants