|
|
import plotly.graph_objects as go |
|
|
import numpy as np |
|
|
import pandas as pd |
|
|
|
|
|
|
|
|
cx, cy = 1.5, 0.5 |
|
|
a, b = 1.3, 0.45 |
|
|
|
|
|
|
|
|
num_points = 3000 |
|
|
num_arms = 3 |
|
|
num_turns = 2.1 |
|
|
angle_jitter = 0.12 |
|
|
pos_noise = 0.015 |
|
|
|
|
|
|
|
|
t = np.random.rand(num_points) * (2 * np.pi * num_turns) |
|
|
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 |
|
|
|
|
|
|
|
|
r_norm = (t / (2 * np.pi * num_turns)) ** 0.9 |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
x_spiral = cx + a * r_norm * np.cos(theta) + noise_x |
|
|
y_spiral = cy + b * r_norm * np.sin(theta) + noise_y |
|
|
|
|
|
|
|
|
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 |
|
|
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 |
|
|
|
|
|
|
|
|
x = np.concatenate([x_spiral, x_bulge]) |
|
|
y = np.concatenate([y_spiral, y_bulge]) |
|
|
|
|
|
|
|
|
z_spiral = 1 - r_norm |
|
|
z_bulge = 1 - (r_b / max(r_b.max(), 1e-6)) |
|
|
z_raw = np.concatenate([z_spiral, z_bulge]) |
|
|
|
|
|
|
|
|
sizes = (z_raw + 1) * 5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)) |
|
|
|
|
|
|
|
|
x = x[mask] |
|
|
y = y[mask] |
|
|
z_raw = z_raw[mask] |
|
|
sizes = sizes[mask] |
|
|
|
|
|
df = pd.DataFrame({ |
|
|
"x": x, |
|
|
"y": y, |
|
|
"z": sizes, |
|
|
}) |
|
|
|
|
|
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" |
|
|
|
|
|
|
|
|
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.write_html( |
|
|
"../app/src/fragments/banner.html", |
|
|
include_plotlyjs=False, |
|
|
full_html=False, |
|
|
config={ |
|
|
'displayModeBar': False, |
|
|
'responsive': True, |
|
|
'scrollZoom': False, |
|
|
} |
|
|
) |