简体   繁体   English

极地立体投影中的Python点密度图

[英]Python Point density plots in polar stereographic projection

I have a point cloud of magnetization directions with azimut (declination between 0° and 360°) and inclination between 0° and 90°. 我有一个磁化方向的点云,其磁化方向具有方位角(0°和360°之间的倾斜度)和0°和90°之间的倾斜度。 I display these points in a polar azimuthal equidistant projection (using matplotlib basemap). 我以极方位角等距投影(使用matplotlib底图)显示这些点。 That means 90° inclination will point directly in the center of the plot and the declination runs clockwise. 这意味着90°的倾斜度将直接指向图的中心,并且倾斜度是顺时针方向。

My problem is that I want to also plot isolines around these point clouds, which should represent where the highest density of point/directions is located. 我的问题是我还想在这些点云周围绘制等值线,这应该代表最高密度的点/方向所在的位置。 What is the easiest way to do this? 最简单的方法是什么? Nice would be to mark the isoline which encircles 50% is my data. 最好是标记包围50%的等值线是我的数据。 If Iam not mistaken - this would be the median. 如果Iam没有记错-这将是中位数。

So far I've fiddled around with gaussian_kde and the outlier detection of sklearn ( 1 and 2 ), but the results are not as expected. 到目前为止,我一直在摆弄gaussian_kde和sklearn的异常检测( 12 ),但是结果并不理想。

Any ideas? 有任何想法吗?

Edit #1: 编辑#1:
First gaussian_kde 第一高斯

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from mpl_toolkits.basemap import Basemap

m = Basemap(projection='spaeqd',boundinglat=0,lon_0=180,resolution='l',round=True)
m.drawparallels(np.arange(-80.,1.,10.),labels=[False,True,True,False])
m.drawmeridians(np.arange(-180.,181.,30.),labels=[True,False,False,True])
#data
x, y = m(m1,-m2) #m2 is negative because I to plot in the southern hemisphere!

#set up the grid for evaluation of the KDE
yi = np.arange(0,360.1,1)
xi = np.arange(-90,1,1)
xx,yy = np.meshgrid(xi,yi)

X, Y = m(xx,yy) # to have it in my basemap projection

#setup the gaussian kde and evaluate it
#pretty much similiar to the scipy.stats docs
positions = np.vstack([X.ravel(), Y.ravel()])
values = np.vstack([x, y])
kernel = stats.gaussian_kde(values)
Z = np.reshape(kernel(positions).T, X.shape)

#plot orginal points and probaility density function
ax = plt.gca()
ax.scatter(x,y,c = 'Crimson')
TOT = ax.contour(X,Y,Z,cmap=plt.cm.Reds)
plt.show()

Then sklearn: 然后sklearn:

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from mpl_toolkits.basemap import Basemap
from sklearn import svm
from sklearn.covariance import EllipticEnvelope

m = Basemap(projection='spaeqd',boundinglat=0,lon_0=180,resolution='l',round=True)
m.drawparallels(np.arange(-80.,1.,10.),labels=[False,True,True,False])
m.drawmeridians(np.arange(-180.,181.,30.),labels=[True,False,False,True])
#data
x, y = m(m1,-m2) #m2 is negative because I to plot in the southern hemisphere!

#Similar to examples in sklearn docs
outliers_fraction = 0.5
oneclass_svm = svm.OneClassSVM(nu=0.95 * outliers_fraction + 0.05,\
               kernel="rbf", gamma=0.1,verbose=True)

#seup grid
yi = np.arange(0,360.1,1)
xi = np.arange(-90,1,1)
R,T = np.meshgrid(xi,yi)
xx, yy = m(T,R)

x, y = m(m1,-m2)

#standardize data as suggested by docs
x_std = (x-x.mean())/x.std()
y_std = (y-y.mean())/y.std()
values = np.vstack([x_std, y_std])

#fit data and calculate threshold - this should mark my median - according to value of outliers_fraction
oneclass_svm.fit(values.T)
y_pred = oneclass_svm.decision_function(values.T).ravel()
threshold = stats.scoreatpercentile(y_pred, 100 * outliers_fraction)
y_pred = y_pred > threshold

#Target vector for evaluation
TV = np.c_[xx.ravel(), yy.ravel()]
TV = (TV-TV.mean(axis=0))/TV.std(axis=0) #must be standardized as well

# evaluation - This is now shifted in the plot ad does not fit my point cloud anymore - because of the standadrization
Z = oneclass_svm.decision_function(TV)
Z = Z.reshape(xx.shape)

#plotting - very similar to the example in the docs
ax = plt.gca()
ax.contourf(xx, yy, Z, levels=np.linspace(Z.min(), threshold, 7), \
           cmap=plt.cm.Blues_r)
ax.contour(xx, yy, Z, levels=[threshold],
           linewidths=2, colors='red')
ax.contourf(xx, yy, Z, levels=[threshold, Z.max()],
           colors='orange')
ax.scatter(x, y,s=30, marker='s',c = 'RoyalBlue',label = 'Mr')
plt.show()

The EllipticEvelope works, but it is not that want I want. EllipticEvelope可以工作,但不是我想要的。

Ok, I think I might found a solution. 好的,我想我可能找到了解决方案。 But it should not work in every case. 但这并非在每种情况下都有效。 It should fail in my opinion when the data is multimodal distributed. 在我看来,当数据是多模式分布时,它应该会失败。

Nevertheless, here is my though process: 不过,这是我的虽则过程:

So the Probalibity Density Function (PDF) is essentially the same as a continuous histogram. 因此,概率密度函数(PDF)与连续直方图基本相同。 So I used np.percentile to calculate the upper and lower 25% percentile of both vectors. 因此,我使用np.percentile来计算两个向量的上下25%百分位数。 The I've searched for the value of the PDF at these perctiles and this should be the Isoline that i want. 我已经在这些易变的位置上搜索了PDF的值,这应该是我想要的等值线。

Of course this should also work in the polar stereographic (or any other) projection. 当然,这也应该在极地立体(或任何其他)投影中起作用。

Here is a litte example code of two gamma distributed data sets in a crossplot: 以下是交叉图中两个伽马分布式数据集的示例示例代码:

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from scipy.interpolate import LinearNDInterpolator, RegularGridInterpolator

#generate some data
x = np.random.gamma(10,0.8,1e4)
y = np.random.gamma(4,0.3,1e4)

#set up the data and grid for the 2D PDF
values = np.vstack([x,y])
pdf_x = np.linspace(x.min(),x.max(),1e2)
pdf_y = np.linspace(y.min(),y.max(),1e2)
X,Y = np.meshgrid(pdf_x,pdf_y)

kernel = stats.gaussian_kde(values)

#evaluate the PDF at every grid location
positions = np.vstack([X.ravel(), Y.ravel()])
Z = np.reshape(kernel(positions).T, X.shape)


#upper and lower quartiles of x and y data
xql = np.percentile(x,25)
xqu = np.percentile(x,75)
yql = np.percentile(y,25)
yqu = np.percentile(y,75)

#set up the interpolator - I could also use RegularGridInterpolator - should be faster
Interp = LinearNDInterpolator((X.flatten(),Y.flatten()),Z.flatten())

#1D example to illustrate what I mean 
plt.figure()
kernel2 = stats.gaussian_kde(x)
plt.hist(x,30,normed=True)
plt.plot(pdf_x,kernel2(pdf_x),'r--',linewidth=2)

#plot vertical lines at the upper and lower quartiles
plt.vlines(np.percentile(x,25),0,0.2,color='red')
plt.vlines(np.percentile(x,75),0,0.2,color='red')

#Scatterplot / Crossplot with PDF and 25 and 75% isolines
plt.figure()
plt.scatter(x,y)
#search for the isolines defining the upper and lower quartiles
#the lower quartiles isoline should encircle 75% of the data
levels = [Interp(xql,yql),Interp(xqu,yqu)]
plt.contour(X,Y,Z,levels=levels,colors='orange')

plt.show()

To finish up I will give a quick example of what it looks in a polar stereographic projection: 最后,我将简要介绍一下极地立体投影中的外观:

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from scipy.interpolate import LinearNDInterpolator
from mpl_toolkits.basemap import Basemap

#set up the coordinate projection
m = Basemap(projection='spaeqd',boundinglat=0,lon_0=180,\
            resolution='l',round=True,suppress_ticks=True)
parallelGrid = np.arange(-80.,1.,10.)
meridianGrid = np.arange(-180.0,180.1,30)
m.drawparallels(parallelGrid,labels=[False,False,False,False])
m.drawmeridians(meridianGrid,labels=[False,False,False,False],labelstyle='+/-',fmt='%i')

#Found this on stackoverflow - labels it exactly how I want it
ax = plt.gca()
ax.text(0.5,1.025,'N',transform=ax.transAxes,\
        horizontalalignment='center',verticalalignment='bottom',size=25)
for para in np.arange(30,360,30):
    x= (1.1*0.5*np.sin(np.deg2rad(para)))+0.5
    y= (1.1*0.5*np.cos(np.deg2rad(para)))+0.5
    ax.text(x,y,u'%i\N{DEGREE SIGN}'%para,transform=ax.transAxes,\
            horizontalalignment='center',verticalalignment='center')

#generate some data
x = np.random.randint(180,225,size=15)
y = np.random.randint(30,40,size=15)

#into projection
x,y = m(x,-y)
values = np.vstack([x,y])

pdf_x = np.arange(0,361,1)
pdf_y = np.arange(0,91,1)

#into projection
X,Y = np.meshgrid(pdf_x,pdf_y)
X,Y = m(X,-Y)


kernel = stats.gaussian_kde(values)
positions = np.vstack([X.ravel(), Y.ravel()])
Z = np.reshape(kernel(positions).T, X.shape)

xql = np.percentile(x,25)
xqu = np.percentile(x,75)
yql = np.percentile(y,25)
yqu = np.percentile(y,75)

Interp = LinearNDInterpolator((X.flatten(),Y.flatten()),Z.flatten())

ax = plt.gca()
ax.scatter(x,y)

levels = [Interp(xql,yql),Interp(xqu,yqu)]
ax.contour(X,Y,Z,levels=levels,colors='red')

plt.show()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM