File size: 3,913 Bytes
5846c4a
 
 
 
b2ac38d
 
 
 
 
 
 
 
 
 
 
 
 
fee9c1e
 
5846c4a
fee9c1e
5846c4a
b2ac38d
fee9c1e
 
b2ac38d
fee9c1e
 
 
b2ac38d
fee9c1e
 
 
b2ac38d
fee9c1e
 
b2ac38d
fee9c1e
 
 
 
 
b2ac38d
fee9c1e
 
 
b2ac38d
fee9c1e
b2ac38d
fee9c1e
 
b2ac38d
fee9c1e
 
b2ac38d
5846c4a
 
 
 
b2ac38d
5846c4a
 
 
fee9c1e
5846c4a
fee9c1e
5846c4a
fee9c1e
5846c4a
 
 
 
b2ac38d
5846c4a
 
b2ac38d
e0ad823
 
5846c4a
 
fee9c1e
5846c4a
 
 
 
 
 
 
fee9c1e
 
 
5846c4a
 
 
fee9c1e
5846c4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fee9c1e
5846c4a
fee9c1e
b9e7b9b
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
import plotly.graph_objects as go
import numpy as np
import pandas as pd

# Scene parameters (same ranges as the Astro integration)
cx, cy = 1.5, 0.5                 # center
a, b = 1.3, 0.45                  # max extent in x/y (ellipse for anisotropy)

# Spiral galaxy parameters
num_points = 3000                 # more dots
num_arms = 3                      # number of spiral arms
num_turns = 2.1                   # number of turns per arm
angle_jitter = 0.12               # angular jitter to fan out the arms
pos_noise = 0.015                 # global position noise

# Generate points along spiral arms (Archimedean spiral)
t = np.random.rand(num_points) * (2 * np.pi * num_turns)  # progression along the arm
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

# Normalized radius (0->center, 1->edge). Power <1 to densify the core
r_norm = (t / (2 * np.pi * num_turns)) ** 0.9

# Radial/lateral noise that slightly increases with radius
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)

# Elliptic projection
x_spiral = cx + a * r_norm * np.cos(theta) + noise_x
y_spiral = cy + b * r_norm * np.sin(theta) + noise_y

# Central bulge (additional points very close to the core)
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  # compact bulge
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

# Concatenation
x = np.concatenate([x_spiral, x_bulge])
y = np.concatenate([y_spiral, y_bulge])

# Central intensity (for sizes/colors). 1 at center, ~0 at edge
z_spiral = 1 - r_norm
z_bulge = 1 - (r_b / max(r_b.max(), 1e-6))  # very bright bulge
z_raw = np.concatenate([z_spiral, z_bulge])

# Sizes: keep the 5..10 scale for consistency
sizes = (z_raw + 1) * 5

# Remove intermediate filtering: keep all placed points, filter at the very end

df = pd.DataFrame({
    "x": x,
    "y": y,
    "z": sizes,  # reused for size+color as before
})

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 based on central intensity
df["label"] = pd.Series(z_raw).apply(get_label)

# Rendering order: small points first, big ones after (on top)
df = df.sort_values(by="z", ascending=True).reset_index(drop=True)

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/content/fragments/banner.html",
    include_plotlyjs=False,
    full_html=False,
    config={
        'displayModeBar': False,
        'responsive': True,
        'scrollZoom': False,
    }
)