我正在开发一个项目,需要将星星映射到虚拟球体上。星星彼此之间以及与球体中心 (0,0,0) 的间距必须均匀,并且亮度类别在球体表面具有特定的分布。球体的每个部分都应根据亮度按比例混合星星,确保整个球体被均匀覆盖。
方法与问题:
归一化:我首先将每颗恒星的位置归一化,通过将其位置向量缩放到固定半径来形成一个球体。
偶数点分布:我使用斐波那契球体采样在球体上生成了 1000 个均匀分布的点。
初始匹配:将每个点与最近的星星匹配效果很好,无需考虑星星亮度。
类别分布:当我尝试包含所需的恒星亮度分布时,挑战就出现了。这些类别需要球体表面的特定比率,但在按亮度分类时我很难保持均匀分布。
当前方法:我最新的尝试涉及随机打乱生成的点,然后根据星星的亮度类别将它们分配给星星。例如,每 1.9 分就属于亮度类别“8”的一颗星。然而,这种方法未能达到所需的均匀分布,特别是因为“8”类星星很少但数量足以满足分布要求。
import pandas as pd
import numpy as np
from sklearn.neighbors import NearestNeighbors
def classify_stars(vmag):
if vmag >= 10:
return '1'
elif 7 <= vmag < 10:
return '3'
elif 6 <= vmag < 7:
return '5'
elif 3 <= vmag < 6:
return '8'
elif 1 <= vmag < 3:
return '9'
else:
return '10'
def generate_sphere_points(samples=1000, radius=50):
points = []
dphi = np.pi * (3. - np.sqrt(5.)) # Approximation of the golden angle in radians.
for i in range(samples):
y = 1 - (i / float(samples - 1)) * 2 # y goes from 1 to -1
radius = np.sqrt(1 - y * y) # radius at y
theta = dphi * i # golden angle increment
x = np.cos(theta) * radius
z = np.sin(theta) * radius
points.append((x * 50, y * 50, z * 50))
return np.array(points)
df = pd.read_csv('hygdata_v3.csv', usecols=['hip', 'x', 'y', 'z', 'mag'])
df.dropna(subset=['hip', 'x', 'y', 'z', 'mag'], inplace=True)
df['hip'] = df['hip'].astype(int)
df['norm'] = np.sqrt(df['x']**2 + df['y']**2 + df['z']**2)
df['x'] = 50 * df['x'] / df['norm']
df['y'] = 50 * df['y'] / df['norm']
df['z'] = 50 * df['z'] / df['norm']
df.drop(columns='norm', inplace=True)
df['class'] = df['mag'].apply(classify_stars)
points = generate_sphere_points(samples=1000)
desired_distribution = {'1': 0.27, '3': 0.27, '5': 0.27, '8': 0.19, '9': 0, '10': 0}
total_points = len(points)
# Calculate points per category based on desired distribution
category_points = {k: int(v * total_points) for k, v in desired_distribution.items()}
# Randomly shuffle points to avoid spatial clustering in assignment
np.random.shuffle(points)
sampled_df = pd.DataFrame()
offset = 0
for category, count in category_points.items():
if count > 0:
category_stars = df[df['class'] == category]
nbrs = NearestNeighbors(n_neighbors=1).fit(category_stars[['x', 'y', 'z']])
if offset + count > len(points):
count = len(points) - offset # Adjust count if it exceeds the number of points
_, indices = nbrs.kneighbors(points[offset:offset + count])
unique_indices = np.unique(indices.flatten())
assigned_stars = category_stars.iloc[unique_indices[:count]]
sampled_df = pd.concat([sampled_df, assigned_stars], ignore_index=True)
offset += count
# Output the hip values of stars with category 8 to see if they are evenly distributed
sampled_df = sampled_df.drop_duplicates(subset='hip')
category_8_stars = sampled_df[sampled_df['class'] == '8']
hip_values_category_8 = category_8_stars['hip'].astype(str).tolist()
print(hip_values_category_8)
数据集可以在这里下载:https://raw.githubusercontent.com/EnguerranVidal/HYG-STAR-MAP/main/hygdatav3.csv
就像我说的,它并没有像我想象的那样工作。 经过整整两天的尝试解决这个谜题后,我来到这里寻求专家的建议。
知道如何解决这个问题吗?
泊松盘采样适用于球体并生成良好的点分布。
如果您将星星按照亮度递减/受欢迎程度增加的顺序排列,那么您可以减小光盘大小,以便在每个尺度上获得令人满意的分布。