python - 如何在 R 或 Python 中制作 3d(4 变量)三元(金字塔)图?

标签 python r matplotlib plot

我的数据是多维组合数据(所有维度总和为 1 或 100)。我已经学会了如何使用三个变量来创建二维三元图。

2d Ternary Plot

我想添加第四个维度,使我的情节看起来像这样。

Pyramid Ternary Plot

我愿意使用 python 或 R。我现在正在使用 pyr2 使用 R 在 python 中创建三元图,但这只是因为这是一个简单的解决方案。如果可以将三元数据转换为 3d 坐标,则可以使用简单的线图。 This post 展示了如何将 3d 成分数据转换为 2d 数据,以便可以使用正常的绘图方法。一种解决方案是在 3d 中做同样的事情。

这是一些示例数据:

          c1        c2        c3        c4
0   0.082337  0.097583  0.048608  0.771472
1   0.116490  0.065047  0.066202  0.752261
2   0.114884  0.135018  0.073870  0.676229
3   0.071027  0.097207  0.070959  0.760807
4   0.066284  0.079842  0.103915  0.749959
5   0.016074  0.074833  0.044532  0.864561
6   0.066277  0.077837  0.058364  0.797522
7   0.055549  0.057117  0.045633  0.841701
8   0.071129  0.077620  0.049066  0.802185
9   0.089790  0.086967  0.083101  0.740142
10  0.084430  0.094489  0.039989  0.781093

最佳答案

好吧,我自己用 wikipedia article 解决了这个问题, 一个 SO post , 和一些蛮力。对不起,代码墙,但你必须画出所有的情节轮廓和标签等等。

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d, Axes3D 
from itertools import combinations
import pandas as pd

def plot_ax():               #plot tetrahedral outline
    verts=[[0,0,0],
     [1,0,0],
     [0.5,np.sqrt(3)/2,0],
     [0.5,0.28867513, 0.81649658]]
    lines=combinations(verts,2)
    for x in lines:
        line=np.transpose(np.array(x))
        ax.plot3D(line[0],line[1],line[2],c='0')

def label_points():  #create labels of each vertices of the simplex
    a=(np.array([1,0,0,0])) # Barycentric coordinates of vertices (A or c1)
    b=(np.array([0,1,0,0])) # Barycentric coordinates of vertices (B or c2)
    c=(np.array([0,0,1,0])) # Barycentric coordinates of vertices (C or c3)
    d=(np.array([0,0,0,1])) # Barycentric coordinates of vertices (D or c3)
    labels=['a','b','c','d']
    cartesian_points=get_cartesian_array_from_barycentric([a,b,c,d])
    for point,label in zip(cartesian_points,labels):
        if 'a' in label:
            ax.text(point[0],point[1]-0.075,point[2], label, size=16)
        elif 'b' in label:
            ax.text(point[0]+0.02,point[1]-0.02,point[2], label, size=16)
        else:
            ax.text(point[0],point[1],point[2], label, size=16)

def get_cartesian_array_from_barycentric(b):      #tranform from "barycentric" composition space to cartesian coordinates
    verts=[[0,0,0],
         [1,0,0],
         [0.5,np.sqrt(3)/2,0],
         [0.5,0.28867513, 0.81649658]]

    #create transformation array vis https://en.wikipedia.org/wiki/Barycentric_coordinate_system
    t = np.transpose(np.array(verts))        
    t_array=np.array([t.dot(x) for x in b]) #apply transform to all points

    return t_array

def plot_3d_tern(df,c='1'): #use function "get_cartesian_array_from_barycentric" to plot the scatter points
#args are b=dataframe to plot and c=scatter point color
    bary_arr=df.values
    cartesian_points=get_cartesian_array_from_barycentric(bary_arr)
    ax.scatter(cartesian_points[:,0],cartesian_points[:,1],cartesian_points[:,2],c=c)





#Create Dataset 1
np.random.seed(123)
c1=np.random.normal(8,2.5,20)
c2=np.random.normal(8,2.5,20)
c3=np.random.normal(8,2.5,20)
c4=[100-x for x in c1+c2+c3]   #make sur ecomponents sum to 100

#df unecessary but that is the format of my real data
df1=pd.DataFrame(data=[c1,c2,c3,c4],index=['c1','c2','c3','c4']).T
df1=df1/100


#Create Dataset 2
np.random.seed(1234)
c1=np.random.normal(16,2.5,20)
c2=np.random.normal(16,2.5,20)
c3=np.random.normal(16,2.5,20)
c4=[100-x for x in c1+c2+c3]

df2=pd.DataFrame(data=[c1,c2,c3,c4],index=['c1','c2','c3','c4']).T
df2=df2/100


#Create Dataset 3
np.random.seed(12345)
c1=np.random.normal(25,2.5,20)
c2=np.random.normal(25,2.5,20)
c3=np.random.normal(25,2.5,20)
c4=[100-x for x in c1+c2+c3]

df3=pd.DataFrame(data=[c1,c2,c3,c4],index=['c1','c2','c3','c4']).T
df3=df3/100

fig = plt.figure()
ax = Axes3D(fig) #Create a 3D plot in most recent version of matplot

plot_ax() #call function to draw tetrahedral outline

label_points() #label the vertices

plot_3d_tern(df1,'b') #call function to plot df1

plot_3d_tern(df2,'r') #...plot df2

plot_3d_tern(df3,'g') #...

enter image description here

关于python - 如何在 R 或 Python 中制作 3d(4 变量)三元(金字塔)图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57467943/

相关文章:

python - 如何在 matplotlib 中更改 x 轴和 y 轴?

python - hexbin 和 histogram2d 的不同行为

python - Pandas 根据不同的列对 NaN 进行插值

javascript - 通过CGI将图像从html发送到python脚本

r - 查找并标记匹配的括号对

r - 有没有一种方法可以使用变量而无需定义它(在 R 中)?

python - 创建具有特定值的白色间隔的正常颜色条

python - Python 3.* 中的 Sphinx 和相关导入

python - 在 Python 中创建一个名为 'id' 的属性是不是很糟糕?

从 R 中的向量中随机挑选对 153 次