euler314 commited on
Commit
3ea658b
·
verified ·
1 Parent(s): 9d2f799

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +112 -0
app.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import textwrap
3
+
4
+ import numpy as np
5
+ import pandas as pd
6
+ import streamlit as st
7
+ from sklearn.manifold import TSNE
8
+ import plotly.express as px
9
+
10
+ # -------------- Helper functions -------------------------------------------
11
+ EXAMPLE_SHAPES = {
12
+ "Cube (3-D, 8 vertices)": np.array([
13
+ [0, 0, 0], [0, 0, 1],
14
+ [0, 1, 0], [0, 1, 1],
15
+ [1, 0, 0], [1, 0, 1],
16
+ [1, 1, 0], [1, 1, 1]
17
+ ]),
18
+ "Square pyramid (3-D, 5 vertices)": np.array([
19
+ [-1, -1, 0],
20
+ [ 1, -1, 0],
21
+ [ 1, 1, 0],
22
+ [-1, 1, 0],
23
+ [ 0, 0, 1]
24
+ ])
25
+ }
26
+
27
+
28
+ def parse_text_points(text: str) -> np.ndarray:
29
+ """
30
+ Parse a multiline string of comma- or whitespace-separated numbers
31
+ into an (n_points, n_dims) array.
32
+ """
33
+ cleaned = textwrap.dedent(text.strip())
34
+ rows = [row for row in cleaned.splitlines() if row.strip()]
35
+ data = [list(map(float, row.replace(",", " ").split())) for row in rows]
36
+ return np.array(data, dtype=float)
37
+
38
+
39
+ def run_tsne(data: np.ndarray, perplexity: float, seed: int) -> np.ndarray:
40
+ tsne = TSNE(
41
+ n_components=2,
42
+ perplexity=perplexity,
43
+ random_state=seed,
44
+ init="pca"
45
+ )
46
+ return tsne.fit_transform(data)
47
+ # ---------------------------------------------------------------------------
48
+
49
+
50
+ st.title("🌀 t-SNE Explorer for n-D Point Clouds")
51
+ st.markdown(
52
+ """
53
+ Upload or paste your points, choose parameters, and see how
54
+ **t-SNE** flattens them into 2-D.
55
+ *Example shapes* are provided for quick experimentation.
56
+ """
57
+ )
58
+
59
+ # --- Sidebar controls -------------------------------------------------------
60
+ with st.sidebar:
61
+ st.header("1️⃣ Choose data source")
62
+ source = st.radio(
63
+ "Data input method",
64
+ ["Example shape", "Upload CSV/TXT", "Paste raw text"]
65
+ )
66
+
67
+ if source == "Example shape":
68
+ shape_key = st.selectbox("Pick a shape", list(EXAMPLE_SHAPES.keys()))
69
+ data_raw = EXAMPLE_SHAPES[shape_key]
70
+
71
+ elif source == "Upload CSV/TXT":
72
+ file = st.file_uploader("Upload coordinates file (*.csv / *.txt)")
73
+ if file:
74
+ text = io.StringIO(file.getvalue().decode("utf-8")).read()
75
+ data_raw = parse_text_points(text)
76
+ else:
77
+ st.stop()
78
+
79
+ else: # Paste text
80
+ placeholder = "e.g.\n0,0,0\n0,0,1\n0,1,0\n..."
81
+ text = st.text_area("Paste coordinates (one point per line)", height=200, placeholder=placeholder)
82
+ if not text.strip():
83
+ st.stop()
84
+ data_raw = parse_text_points(text)
85
+
86
+ st.divider()
87
+ st.header("2️⃣ t-SNE parameters")
88
+ perplexity = st.slider("Perplexity", 5.0, 50.0, 30.0, 1.0)
89
+ seed = st.number_input("Random seed", value=42, step=1)
90
+ run_button = st.button("Run t-SNE 🚀")
91
+
92
+ # --- Main area --------------------------------------------------------------
93
+ if run_button:
94
+ if data_raw.ndim != 2 or data_raw.shape[0] < 2:
95
+ st.error("Need at least two points; check your input.")
96
+ st.stop()
97
+
98
+ if perplexity >= data_raw.shape[0]:
99
+ st.error("Perplexity must be less than the number of points.")
100
+ st.stop()
101
+
102
+ embedding = run_tsne(data_raw, perplexity, seed)
103
+ df_plot = pd.DataFrame(embedding, columns=["x", "y"])
104
+
105
+ st.subheader("2-D embedding")
106
+ fig = px.scatter(df_plot, x="x", y="y", width=700, height=500)
107
+ fig.update_traces(marker=dict(size=10))
108
+ fig.update_layout(margin=dict(l=20, r=20, t=30, b=20))
109
+ st.plotly_chart(fig, use_container_width=True)
110
+
111
+ with st.expander("Show raw data"):
112
+ st.write(pd.DataFrame(data_raw))