Spaces:
Running
Running
File size: 4,255 Bytes
5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e 5846c4a fee9c1e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
import plotly.graph_objects as go
import numpy as np
import pandas as pd
# Paramètres de la scène (mêmes ranges que l'intégration Astro)
cx, cy = 1.5, 0.5 # centre
a, b = 1.3, 0.45 # étendue max en x/y (ellipse pour l'anisotropie)
# Paramètres de la galaxie en spirale
num_points = 3000 # plus de dots
num_arms = 3 # nombre de bras spiraux
num_turns = 2.1 # nombre de tours par bras
angle_jitter = 0.12 # écart angulaire pour évaser les bras
pos_noise = 0.015 # bruit de position global
# Génération des points sur des bras spiraux (spirale d'Archimède)
t = np.random.rand(num_points) * (2 * np.pi * num_turns) # progression le long du bras
arm_indices = np.random.randint(0, num_arms, size=num_points)
arm_offsets = arm_indices * (2 * np.pi / num_arms)
theta = t + arm_offsets + np.random.randn(num_points) * angle_jitter
# Rayon normalisé (0->centre, 1->bord). Puissance <1 pour densifier le centre
r_norm = (t / (2 * np.pi * num_turns)) ** 0.9
# Bruit radial/lateral qui augmente légèrement avec le rayon
noise_x = pos_noise * (0.8 + 0.6 * r_norm) * np.random.randn(num_points)
noise_y = pos_noise * (0.8 + 0.6 * r_norm) * np.random.randn(num_points)
# Projection elliptique
x_spiral = cx + a * r_norm * np.cos(theta) + noise_x
y_spiral = cy + b * r_norm * np.sin(theta) + noise_y
# Bulbe central (points supplémentaires très proches du centre)
bulge_points = int(0.18 * num_points)
phi_b = 2 * np.pi * np.random.rand(bulge_points)
r_b = (np.random.rand(bulge_points) ** 2.2) * 0.22 # bulbe compact
noise_x_b = (pos_noise * 0.6) * np.random.randn(bulge_points)
noise_y_b = (pos_noise * 0.6) * np.random.randn(bulge_points)
x_bulge = cx + a * r_b * np.cos(phi_b) + noise_x_b
y_bulge = cy + b * r_b * np.sin(phi_b) + noise_y_b
# Concaténation
x = np.concatenate([x_spiral, x_bulge])
y = np.concatenate([y_spiral, y_bulge])
# Intensité centrale (pour tailles/couleurs). 1 au centre, ~0 au bord
z_spiral = 1 - r_norm
z_bulge = 1 - (r_b / max(r_b.max(), 1e-6)) # bulbe très lumineux
z_raw = np.concatenate([z_spiral, z_bulge])
# Tailles: conserver l'échelle 5..10 pour cohérence
sizes = (z_raw + 1) * 5
# Filtrer les petits points proches du centre (esthétique du bulbe)
# - on calcule le rayon elliptique normalisé
# - on retire les points de petite taille situés trop près du centre
central_radius_cut = 0.18
min_size_center = 7.5
r_total = np.sqrt(((x - cx) / a) ** 2 + ((y - cy) / b) ** 2)
mask = ~((r_total <= central_radius_cut) & (sizes < min_size_center))
# Appliquer le masque
x = x[mask]
y = y[mask]
z_raw = z_raw[mask]
sizes = sizes[mask]
df = pd.DataFrame({
"x": x,
"y": y,
"z": sizes, # réutilisé pour size+color comme avant
})
def get_label(z):
if z < 0.25:
return "smol dot"
if z < 0.5:
return "ok-ish dot"
if z < 0.75:
return "a dot"
else:
return "biiig dot"
# Labels basés sur l'intensité centrale
df["label"] = pd.Series(z_raw).apply(get_label)
fig = go.Figure()
fig.add_trace(go.Scattergl(
x=df['x'],
y=df['y'],
mode='markers',
marker=dict(
size=df['z'],
color=df['z'],
colorscale=[
[0, 'rgb(78, 165, 183)'],
[0.5, 'rgb(206, 192, 250)'],
[1, 'rgb(232, 137, 171)']
],
opacity=0.9,
),
customdata=df[["label"]],
hovertemplate="Dot category: %{customdata[0]}",
hoverlabel=dict(namelength=0),
showlegend=False
))
fig.update_layout(
autosize=True,
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)',
showlegend=False,
margin=dict(l=0, r=0, t=0, b=0),
xaxis=dict(
showgrid=False,
zeroline=False,
showticklabels=False,
range=[0, 3]
),
yaxis=dict(
showgrid=False,
zeroline=False,
showticklabels=False,
scaleanchor="x",
scaleratio=1,
range=[0, 1]
)
)
# fig.show()
fig.write_html(
"../app/src/fragments/banner.html",
include_plotlyjs=False,
full_html=False,
config={
'displayModeBar': False,
'responsive': True,
'scrollZoom': False,
}
) |