import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# 更新后的数据点
points = {
'blue': np.array([
[-12, 6, 0],
[-13, 3, 0],
[-15, 1, 0]
]),
'green': np.array([
[2, 0, 0],
[3, 0, 0],
[4, -2, 0]
]),
'orange': np.array([
[-2, 8, 8],
[-4, 3, 2]
]),
'pink': np.array([
[-3, 6, 5],
[-5, 2, 3],
])
}
def draw_ellipsoid(ax, center, radii, rotation, color, alpha=0.2):
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = radii[0] * np.outer(np.cos(u), np.sin(v))
y = radii[1] * np.outer(np.sin(u), np.sin(v))
z = radii[2] * np.outer(np.ones_like(u), np.cos(v))
for i in range(len(x)):
for j in range(len(x)):
[x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], rotation) + center
ax.plot_surface(x, y, z, color=color, alpha=alpha)
# 创建图形
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# 设置白色背景
ax.xaxis.pane.fill = False
ax.yaxis.pane.fill = False
ax.zaxis.pane.fill = False
ax.xaxis.pane.set_edgecolor('white')
ax.yaxis.pane.set_edgecolor('white')
ax.zaxis.pane.set_edgecolor('white')
ax.set_facecolor('white')
# 绘制散点图和椭圆
for color, coords in points.items():
# 绘制散点
ax.scatter(coords[:, 0], coords[:, 1], coords[:, 2],
c=color, s=100, alpha=1.0)
# 添加椭圆
center = np.mean(coords, axis=0)
if color == 'blue':
radii = [2, 3, 1]
rotation = np.array([[0.8, -0.2, 0], [0.2, 0.8, 0], [0, 0, 1]])
elif color == 'green':
radii = [2, 2, 1]
rotation = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
elif color in ['orange', 'pink']:
# 为橙色和粉色点共用一个更大的椭圆
if color == 'orange':
radii = [3, 4, 4]
rotation = np.array([[0.9, -0.1, 0], [0.1, 0.9, 0], [0, 0, 1]])
draw_ellipsoid(ax, center, radii, rotation, color, alpha=0.1)
# 设置坐标轴标签
ax.set_xlabel('PC1')
ax.set_ylabel('PC2')
ax.set_zlabel('PC3')
# 设置坐标轴范围
ax.set_xlim([-15, 5])
ax.set_ylim([-5, 10])
ax.set_zlim([-5, 10])
# 设置网格线
ax.grid(True, linestyle='--', alpha=0.3)
# 调整视角
ax.view_init(elev=20, azim=-45)
plt.show()
import plotly.graph_objects as go
import plotly.express as px
import numpy as np
from sklearn.manifold import TSNE
def generate_ellipsoid_mesh(center, radii, rotation, n_points=50):
u = np.linspace(0, 2 * np.pi, n_points)
v = np.linspace(0, np.pi, n_points)
x = radii[0] * np.outer(np.cos(u), np.sin(v))
y = radii[1] * np.outer(np.sin(u), np.sin(v))
z = radii[2] * np.outer(np.ones_like(u), np.cos(v))
# 应用旋转和平移
points = np.stack([x.flatten(), y.flatten(), z.flatten()])
transformed_points = np.dot(rotation, points) + center.reshape(-1, 1)
x = transformed_points[0].reshape(n_points, n_points)
y = transformed_points[1].reshape(n_points, n_points)
z = transformed_points[2].reshape(n_points, n_points)
return x, y, z
# 年龄分组函数
def age_to_group(age):
if age == 0:
return 0
elif 0 < age <= 1:
return 1
else:
return int((age-1) // 10 + 2)
# 模拟一些年龄数据 (如果你没有真实数据的话)
np.random.seed(42)
age_values = np.random.uniform(0, 100, size=1000)
# 模拟一些高维数据 (如果你没有真实的final_V的话)
final_V = np.random.randn(100, 1000) # 100维特征,1000个样本
# 将年龄转换为分组
age_groups = np.array([age_to_group(age) for age in age_values])
# 创建分组标签
group_labels = ['0', '0-1'] + [f'{i*10-9}-{i*10}' for i in range(1, 11)]
# 计算t-SNE
tsne = TSNE(n_components=3, random_state=42)
features_3d = tsne.fit_transform(final_V.T)
# 创建图形
fig = go.Figure()
# 使用plotly的颜色序列
colors = px.colors.qualitative.Set3
# 为每个年龄组添加散点和椭圆
for i, label in enumerate(group_labels):
mask = age_groups == i
if np.sum(mask) > 0: # 如果该组有数据点
group_points = features_3d[mask]
# 添加散点
fig.add_trace(go.Scatter3d(
x=group_points[:, 0],
y=group_points[:, 1],
z=group_points[:, 2],
mode='markers',
name=label,
marker=dict(
size=5,
color=colors[i % len(colors)],
opacity=0.6
),
showlegend=True
))
# 计算并添加椭圆
if len(group_points) > 1:
center = np.mean(group_points, axis=0)
cov = np.cov(group_points.T)
eigenvals, eigenvecs = np.linalg.eigh(cov)
radii = 2 * np.sqrt(eigenvals)
radii = np.maximum(radii, 0.1)
x, y, z = generate_ellipsoid_mesh(center, radii, eigenvecs)
fig.add_trace(go.Surface(
x=x, y=y, z=z,
colorscale=[[0, colors[i % len(colors)]], [1, colors[i % len(colors)]]],
showscale=False,
opacity=0.2,
name=f'{label}_surface',
showlegend=False
))
# 更新布局
fig.update_layout(
title='t-SNE 3D Visualization with Age Groups',
scene=dict(
xaxis_title='t-SNE 1',
yaxis_title='t-SNE 2',
zaxis_title='t-SNE 3',
bgcolor='white'
),
showlegend=True,
legend=dict(
yanchor="top",
y=0.99,
xanchor="left",
x=1.05
),
margin=dict(l=0, r=0, t=30, b=0)
)
# 更新场景配置
fig.update_scenes(
camera=dict(
up=dict(x=0, y=0, z=1),
center=dict(x=0, y=0, z=0),
eye=dict(x=1.5, y=1.5, z=1.5)
)
)
# 显示图形
fig.show()