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

如何在R或Python中制作3d(4变量)三元(金字塔)绘图?,python,r,matplotlib,plot,Python,R,Matplotlib,Plot,我有多维合成数据(所有维度总和为1或100)。我已经学会了如何使用其中三个变量来创建二维三元图 我想添加一个第四维度,这样我的情节看起来像这样 我愿意使用python或R。我现在使用pyr2使用R在python中创建三元图,但这只是因为这是一个简单的解决方案。如果可以将三元数据转换为三维坐标,则可以使用简单的接线图。 显示如何将三维合成数据转换为二维数据,以便可以使用常规打印方法。一个解决方案是在3d中做同样的事情 以下是一些示例数据: c1 c2

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

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

我愿意使用python或R。我现在使用
pyr2
使用R在python中创建三元图,但这只是因为这是一个简单的解决方案。如果可以将三元数据转换为三维坐标,则可以使用简单的接线图。 显示如何将三维合成数据转换为二维数据,以便可以使用常规打印方法。一个解决方案是在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

嗯,我自己用一个,一个,还有一些蛮力解决了这个问题。很抱歉代码墙,但是您必须绘制所有的绘图轮廓和标签等等

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') #...

好吧,我自己用一个、一个和一些蛮力解决了这个问题。很抱歉代码墙,但是您必须绘制所有的绘图轮廓和标签等等

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') #...

公认的答案解释了如何在python中实现这一点,但问题也涉及到R

我已经回答了如何在R中“手动”执行此操作

否则,您可以直接使用:

df装载所需包装:质量
四点图(df)


由(v0.3.0)于2020-08-14创建的公认答案解释了如何在python中实现这一点,但问题也涉及R

我已经回答了如何在R中“手动”执行此操作

否则,您可以直接使用:

df装载所需包装:质量
四点图(df)

由(v0.3.0)于2020年8月14日创建