回答问题

在过去的几天里,我一直在尝试用 python 绘制圆形数据,通过构建一个从 0 到 2pi 的圆形直方图并拟合 Von Mises 分布。我真正想要实现的是:

  1. 具有拟合 Von-Mises 分布的方向数据。该图是使用 Matplotlib、Scipy 和 Numpy 构建的,可以在以下位置找到:http://jpktd.blogspot.com/2012/11/polar-histogram.html

在此处输入图像描述

  1. 这个情节是使用 R 制作的,但给出了我想要情节的想法。可以在这里找到:https://www.zeileis.org/news/circtree/

在此处输入图像描述

到目前为止我做了什么:

from scipy.special import i0  
import numpy as np
import matplotlib.pyploy as plt

# From my data I fitted a Von-Mises distribution, calculating Mu and Kappa. 
mu = -0.343
kappa = 10.432

# Construct random Von-Mises distribution based on Mu and Kappa values
r = np.random.vonmises(mu, kappa, 1000)

# Adjust Von-Mises curve from fitted data
x = np.linspace(-np.pi, np.pi, num=501)
y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa)) 

# Adjuste x limits and labels
plt.xlim(-np.pi, np.pi)
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], 
labels=[r'$-\pi$ (0º)', r'$-\frac{\pi}{2}$ (90º)', '0 (180º)', r'$\frac{\pi}{2}$ (270º)', r'$\pi$'])

# Plot adjusted Von-Mises function as line
plt.plot(x, y, linewidth=2, color='red', zorder=3

# Plot distribution 
plt.hist(r, density=True,  bins=20, alpha=1, edgecolor='white');
plt.title('Slaty Cleavage Strike', fontweight='bold', fontsize=14)

在此处输入图像描述

我尝试绘制圆形直方图 基于诸如python中的圆形/极坐标直方图之类的问题

# From the data above (mu, kappa, x and y):

theta = np.linspace(-np.pi, np.pi, num=50, endpoint=False)
radii = np.exp(kappa*np.cos(theta-mu))/(2*np.pi*i0(kappa)) 

# Bin width?
width = (2*np.pi) / 50

# Construct ax with polar projection
ax = plt.subplot(111, polar=True)

# Set Zero to North
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)

# Plot bars:
bars = ax.bar(x = theta, height = radii, width=width)
# Plot Line:
line = ax.plot(x, y, linewidth=1, color='red', zorder=3) 
 
# Grid settings
ax.set_rgrids(np.arange(1, 1.6, 0.5), angle=0, weight= 'black');

在此处输入图像描述

笔记:

  • 我的圆形直方图将我的数据绘制在错误的方向上,相差 180 度:比较两个直方图。 见编辑 1

  • 我相信这可能与定义在 [-pi,pi] https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats. vonmises.html见编辑 1

  • 我的数据最初在 [0,2pi] 之间变化。我转换为 [-pi,pi] 以拟合 Von Mises 并计算 Mu 和 Kappa。 见编辑 1

我真的很想将我的数据绘制为第一个图。我的数据是地质方向数据(方位角)。有人有什么想法吗? PS。对不起,很长的帖子。我希望这至少有帮助

编辑 1:

通过评论,我意识到有些人对数据是否从[0,2pi][-pi,pi]感到困惑。我意识到在我的圆形直方图中绘制的错误方向来自以下内容:

1.我的原始数据(地质数据)范围在[0,2pi]之间,即0到360度;

2.然而scipy.stats.vonmises计算[-pi, pi]中的概率密度函数;

  1. 我从我的数据中减去了 pi,以便使用 scipy.stats.vonmisesmy_data - pi;

  2. 一旦计算出MuKappa(正确),我将pi添加到Mu值中,以恢复原始方向,现在再次介于[0,2pi]之间。

  3. 现在,我的数据正确地面向东南:

在此处输入图像描述

# Add pi to fitted Mu. 
mu = - 0.343 + np.pi
kappa = 10.432

x = np.linspace(-np.pi, np.pi, num=501)
y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa)) 

theta = np.linspace(-np.pi, np.pi, num=50, endpoint=False)
radii = np.exp(kappa*np.cos(theta-mu))/(2*np.pi*i0(kappa)) 

# Bin width?
width = (2*np.pi) / 50

ax = plt.subplot(111, polar=True)

# Angles increase clockwise from North
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)

bars = ax.bar(x = theta, height = radii, width=width)

line = ax.plot(x, y, linewidth=1, color='red', zorder=3) 

ax.set_rgrids(np.arange(1, 1.6, 0.5), angle=0, weight= 'black');

编辑 2

正如接受的答案的评论所建议的那样,技巧正在改变y_lim,如下所示:

在此处输入图像描述

# SE DIRECTION
mu = - 0.343 + np.pi
kappa = 10.432


x = np.linspace(-np.pi, np.pi, num=501)
y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa)) 

theta = np.linspace(-np.pi, np.pi, num=50, endpoint=False)
radii = np.exp(kappa*np.cos(theta-mu))/(2*np.pi*i0(kappa)) 

# PLOT
plt.figure(figsize=(5,5))
ax = plt.subplot(111, polar=True)

# Bin width?
width = (2*np.pi) / 50

# Angles increase clockwise from North
ax.set_theta_zero_location('N'); ax.set_theta_direction(-1);

bars = ax.bar(x=theta, height = radii, width=width, bottom=0)

# Plot Line
line = ax.plot(x, y, linewidth=2, color='firebrick', zorder=3 ) 

# 'Trick': This will display Zero as a circle. Fitted Von-Mises function will lie along zero.
ax.set_ylim(-0.5, 1.5);

ax.set_rgrids(np.arange(0, 1.6, 0.5), angle=60, weight= 'bold',
             labels=np.arange(0,1.6,0.5));

最后注:

  • 提供的直方图已经归一化,因此可以用相同比例的 vM 分布绘制它。

Answers

这是我取得的成就:

在此处输入图像描述

我不完全确定您是否希望 x 的范围为[-pi,pi][0,2pi]。如果你想要[0,2pi]范围,只需注释掉ax.set_xlimax.set_xticks行。

from scipy.special import i0
import numpy as np
import matplotlib.pyplot as plt


# From my data I fitted a Von-Mises distribution, calculating Mu and Kappa.
mu = -0.343
kappa = 10.432

# Construct random Von-Mises distribution based on Mu and Kappa values
r = np.random.vonmises(mu, kappa, 1000)

# Adjust Von-Mises curve from fitted data
x = np.linspace(-np.pi, np.pi, num=501)
y = np.exp(kappa*np.cos(x-mu))/(2*np.pi*i0(kappa))

# Adjuste x limits and labels
plt.xlim(-np.pi, np.pi)
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
labels=[r'$-\pi$ (0º)', r'$-\frac{\pi}{2}$ (90º)', '0 (180º)', r'$\frac{\pi}{2}$ (270º)', r'$\pi$'])

# Plot adjusted Von-Mises function as line
plt.plot(x, y, linewidth=2, color='red', zorder=3)

# Plot distribution
plt.hist(r, density=True,  bins=20, alpha=1, edgecolor='white')
plt.title('Slaty Cleavage Strike', fontweight='bold', fontsize=14)



# From the data above (mu, kappa, x and y):

theta = np.linspace(-np.pi, np.pi, num=50, endpoint=False)
radii = np.exp(kappa * np.cos(theta - mu)) / (2 * np.pi * i0(kappa))

# Display width
width = (2 * np.pi) / 50

# Construct ax with polar projection
ax = plt.subplot(111, polar=True)

# Set Orientation
ax.set_theta_zero_location('E')
ax.set_theta_direction(-1)
ax.set_xlim(-np.pi/1.000001, np.pi/1.000001)  # workaround for a weird issue
ax.set_xticks([-np.pi/1.000001 + i/8 * 2*np.pi/1.000001 for i in range(8)])

# Plot bars:
bars = ax.bar(x=theta, height=radii, width=width)
# Plot Line:
line = ax.plot(x, y, linewidth=1, color='red', zorder=3)

# Grid settings
ax.set_rgrids(np.arange(.5, 1.6, 0.5), angle=0, weight='black')


plt.show()
Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐