priyadip commited on
Commit
4f6be37
Β·
verified Β·
1 Parent(s): 21588ff

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +23 -5
  2. app.py +264 -0
  3. requirements.txt +4 -0
README.md CHANGED
@@ -1,14 +1,32 @@
1
  ---
2
- title: CHECKING
3
- emoji: πŸ¦€
4
- colorFrom: gray
5
  colorTo: purple
6
  sdk: gradio
7
  sdk_version: 6.8.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
- short_description: 'dimensionality reduction using Principal Component Analysis '
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: PCA DimReduction 3D2D
3
+ emoji: πŸ“
4
+ colorFrom: blue
5
  colorTo: purple
6
  sdk: gradio
7
  sdk_version: 6.8.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
+ short_description: PCA tool for 3D to 2D dimensionality reduction.
12
  ---
13
 
14
+ # PCA Visualizer - 3D to 2D Dimensionality Reduction
15
+
16
+ Interactive Principal Component Analysis tool with full step-by-step mathematical output.
17
+
18
+ ## Features
19
+ - Enter 6+ 3D points and instantly see all PCA steps
20
+ - Covariance matrix, eigenvalues, eigenvectors shown clearly
21
+ - 3D scatter plot of original points
22
+ - 2D projection plot
23
+ - Variance explained bar and cumulative charts
24
+
25
+ ## Usage
26
+ Enter points one per line as X Y Z, for example:
27
+ ```
28
+ 1 2 3
29
+ 4 5 6
30
+ 7 8 9
31
+ ```
32
+ Click Run PCA to compute all steps.
app.py ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import matplotlib
4
+ matplotlib.use('Agg')
5
+ import matplotlib.pyplot as plt
6
+
7
+ COLORS = ['#00d4ff','#7c3aed','#f59e0b','#10b981','#f43f5e',
8
+ '#a78bfa','#34d399','#fb923c','#60a5fa','#e879f9']
9
+
10
+ def parse_points(text):
11
+ points, errors = [], []
12
+ for i, line in enumerate([l.strip() for l in text.strip().split('\n') if l.strip()]):
13
+ try:
14
+ vals = [float(x) for x in line.replace(',', ' ').split()]
15
+ if len(vals) != 3:
16
+ errors.append(f"Line {i+1}: need 3 values, got {len(vals)}")
17
+ else:
18
+ points.append(vals)
19
+ except:
20
+ errors.append(f"Line {i+1}: invalid numbers")
21
+ return (np.array(points) if points else None), errors
22
+
23
+ def run_pca(points_text):
24
+ points, errors = parse_points(points_text)
25
+ if errors:
26
+ return "❌ Input Errors:\n" + "\n".join(errors), None, None, None
27
+ if points is None or len(points) < 6:
28
+ n = len(points) if points is not None else 0
29
+ return f"❌ Need at least 6 points (you entered {n})", None, None, None
30
+
31
+ n = len(points)
32
+ mean = np.mean(points, axis=0)
33
+ centered = points - mean
34
+ cov = np.cov(centered.T)
35
+ eigenvalues, eigenvectors = np.linalg.eigh(cov)
36
+ idx = np.argsort(eigenvalues)[::-1]
37
+ eigenvalues = eigenvalues[idx]
38
+ eigenvectors = eigenvectors[:, idx]
39
+ W = eigenvectors[:, :2]
40
+ projected = centered @ W
41
+ var_exp = eigenvalues / np.sum(eigenvalues) * 100
42
+
43
+ # ── Build output text
44
+ sep = "═" * 58
45
+ thin = "─" * 58
46
+ L = []
47
+ L.append(sep)
48
+ L.append(" PCA Β· 3D β†’ 2D DIMENSIONALITY REDUCTION")
49
+ L.append(sep)
50
+
51
+ L.append("\n β–Έ STEP 1 | INPUT POINTS")
52
+ L.append(" " + thin)
53
+ L.append(f" {'#':<6} {'X':>10} {'Y':>10} {'Z':>10}")
54
+ L.append(" " + thin)
55
+ for i, p in enumerate(points):
56
+ L.append(f" P{i+1:<5} {p[0]:>10.4f} {p[1]:>10.4f} {p[2]:>10.4f}")
57
+
58
+ L.append("\n β–Έ STEP 2 | MEAN & CENTERED POINTS")
59
+ L.append(" " + thin)
60
+ L.append(f" Mean ΞΌ = ({mean[0]:.4f}, {mean[1]:.4f}, {mean[2]:.4f})\n")
61
+ L.append(f" {'#':<6} {'X-ΞΌx':>10} {'Y-ΞΌy':>10} {'Z-ΞΌz':>10}")
62
+ L.append(" " + thin)
63
+ for i, p in enumerate(centered):
64
+ L.append(f" P{i+1:<5} {p[0]:>10.4f} {p[1]:>10.4f} {p[2]:>10.4f}")
65
+
66
+ L.append("\n β–Έ STEP 3 | COVARIANCE MATRIX (3Γ—3)")
67
+ L.append(" " + thin)
68
+ L.append(f" {'':>6} {'X':>10} {'Y':>10} {'Z':>10}")
69
+ for i, lbl in enumerate(['X','Y','Z']):
70
+ L.append(f" {lbl:<6}" + "".join(f"{cov[i,j]:>10.4f}" for j in range(3)))
71
+
72
+ L.append("\n β–Έ STEP 4 | EIGENVALUES & EIGENVECTORS")
73
+ L.append(" " + thin)
74
+ for i in range(3):
75
+ ev = eigenvectors[:, i]
76
+ L.append(f" Ξ»{i+1} = {eigenvalues[i]:>10.6f} | v{i+1} = [{ev[0]:>8.4f}, {ev[1]:>8.4f}, {ev[2]:>8.4f}]")
77
+
78
+ L.append("\n β–Έ STEP 5 | TOP 2 PRINCIPAL COMPONENTS")
79
+ L.append(" " + thin)
80
+ L.append(f" PC1 Ξ»={eigenvalues[0]:.4f} β†’ [{W[0,0]:>7.4f}, {W[1,0]:>7.4f}, {W[2,0]:>7.4f}]")
81
+ L.append(f" PC2 Ξ»={eigenvalues[1]:.4f} β†’ [{W[0,1]:>7.4f}, {W[1,1]:>7.4f}, {W[2,1]:>7.4f}]")
82
+ L.append(f"\n Variance: PC1={var_exp[0]:.2f}% PC2={var_exp[1]:.2f}% Total={var_exp[0]+var_exp[1]:.2f}%")
83
+
84
+ L.append("\n β–Έ STEP 6 | PROJECTION MATRIX W (3Γ—2)")
85
+ L.append(" " + thin)
86
+ L.append(f" {'':>4} {'PC1':>10} {'PC2':>10}")
87
+ for i, lbl in enumerate(['x','y','z']):
88
+ L.append(f" {lbl:<4} {W[i,0]:>10.4f} {W[i,1]:>10.4f}")
89
+
90
+ L.append("\n β–Έ STEP 7 | REDUCED 2D COORDINATES")
91
+ L.append(" " + thin)
92
+ L.append(f" {'#':<6} {'3D (X, Y, Z)':<32} 2D (PC1, PC2)")
93
+ L.append(" " + thin)
94
+ for i in range(n):
95
+ orig = f"({points[i,0]:.2f}, {points[i,1]:.2f}, {points[i,2]:.2f})"
96
+ red = f"({projected[i,0]:.4f}, {projected[i,1]:.4f})"
97
+ L.append(f" P{i+1:<5} {orig:<32} {red}")
98
+
99
+ L.append("\n" + sep)
100
+ output_text = "\n".join(L)
101
+
102
+ # ── Plots
103
+ fig1 = make_3d_plot(points, mean)
104
+ fig2 = make_2d_plot(projected, var_exp)
105
+ fig3 = make_var_plot(var_exp)
106
+
107
+ return output_text, fig1, fig2, fig3
108
+
109
+
110
+ def _style_ax(ax):
111
+ ax.set_facecolor('#111827')
112
+ for sp in ax.spines.values():
113
+ sp.set_color('#1e293b')
114
+ ax.tick_params(colors='#94a3b8', labelsize=8)
115
+
116
+
117
+ def make_3d_plot(points, mean):
118
+ fig = plt.figure(figsize=(6, 5), facecolor='#0a0e1a')
119
+ ax = fig.add_subplot(111, projection='3d')
120
+ ax.set_facecolor('#111827')
121
+ for pane in [ax.xaxis.pane, ax.yaxis.pane, ax.zaxis.pane]:
122
+ pane.fill = False
123
+ pane.set_edgecolor('#1e293b')
124
+ ax.tick_params(colors='#94a3b8', labelsize=7)
125
+ ax.xaxis.label.set_color('#94a3b8')
126
+ ax.yaxis.label.set_color('#94a3b8')
127
+ ax.zaxis.label.set_color('#94a3b8')
128
+ ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Z')
129
+ for i, p in enumerate(points):
130
+ c = COLORS[i % len(COLORS)]
131
+ ax.scatter(*p, color=c, s=80, edgecolors='white', linewidths=0.5, zorder=5)
132
+ ax.text(p[0], p[1], p[2], f' P{i+1}', color=c, fontsize=7.5, fontweight='bold')
133
+ ax.scatter(*mean, color='#f59e0b', s=160, marker='*', edgecolors='white', linewidths=0.8, zorder=10)
134
+ ax.set_title('Original 3D Points', color='#e2e8f0', fontsize=11, fontweight='bold', pad=10)
135
+ fig.tight_layout()
136
+ return fig
137
+
138
+
139
+ def make_2d_plot(projected, var_exp):
140
+ fig, ax = plt.subplots(figsize=(6, 5), facecolor='#0a0e1a')
141
+ _style_ax(ax)
142
+ ax.axhline(0, color='#1e293b', lw=1); ax.axvline(0, color='#1e293b', lw=1)
143
+ ax.grid(True, color='#1e293b', lw=0.5, alpha=0.7)
144
+ ax.set_xlabel(f'PC1 ({var_exp[0]:.1f}%)', color='#00d4ff', fontsize=10)
145
+ ax.set_ylabel(f'PC2 ({var_exp[1]:.1f}%)', color='#7c3aed', fontsize=10)
146
+ for i, p in enumerate(projected):
147
+ c = COLORS[i % len(COLORS)]
148
+ ax.scatter(*p, color=c, s=100, edgecolors='white', linewidths=0.6, zorder=5)
149
+ ax.annotate(f'P{i+1}', p, xytext=(7,4), textcoords='offset points',
150
+ color=c, fontsize=8.5, fontweight='bold')
151
+ ax.set_title('2D Projection (PCA)', color='#e2e8f0', fontsize=11, fontweight='bold', pad=10)
152
+ fig.tight_layout()
153
+ return fig
154
+
155
+
156
+ def make_var_plot(var_exp):
157
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4), facecolor='#0a0e1a')
158
+ labels = ['PC1','PC2','PC3']
159
+ bar_colors = ['#00d4ff','#7c3aed','#f59e0b']
160
+
161
+ _style_ax(ax1)
162
+ bars = ax1.bar(labels, var_exp, color=bar_colors, edgecolor='#0a0e1a', linewidth=1.5, width=0.5)
163
+ for bar, val in zip(bars, var_exp):
164
+ ax1.text(bar.get_x()+bar.get_width()/2, bar.get_height()+0.8,
165
+ f'{val:.1f}%', ha='center', color='#e2e8f0', fontsize=9, fontweight='bold')
166
+ ax1.set_title('Variance per PC', color='#e2e8f0', fontsize=10, fontweight='bold', pad=8)
167
+ ax1.set_ylabel('Variance (%)', color='#64748b', fontsize=9)
168
+ ax1.set_ylim(0, max(var_exp)*1.2)
169
+
170
+ _style_ax(ax2)
171
+ cum = np.cumsum(var_exp)
172
+ ax2.plot(labels, cum, 'o-', color='#10b981', lw=2.5, markersize=8,
173
+ markerfacecolor='#0a0e1a', markeredgecolor='#10b981', markeredgewidth=2.5)
174
+ ax2.fill_between(labels, cum, alpha=0.12, color='#10b981')
175
+ ax2.axhline(100, color='#f43f5e', lw=1, ls='--', alpha=0.5)
176
+ for x, y in zip(labels, cum):
177
+ ax2.text(x, y+2, f'{y:.1f}%', ha='center', color='#10b981', fontsize=9, fontweight='bold')
178
+ ax2.set_title('Cumulative Variance', color='#e2e8f0', fontsize=10, fontweight='bold', pad=8)
179
+ ax2.set_ylabel('Cumulative (%)', color='#64748b', fontsize=9)
180
+ ax2.set_ylim(0, 115)
181
+ ax2.grid(True, color='#1e293b', lw=0.5)
182
+
183
+ fig.tight_layout(pad=2)
184
+ return fig
185
+
186
+
187
+ # ── CSS
188
+ css = """
189
+ @import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Syne:wght@400;600;800&display=swap');
190
+
191
+ body, .gradio-container { background: #0a0e1a !important; color: #e2e8f0 !important; font-family: 'Syne', sans-serif !important; }
192
+ .gradio-container { max-width: 1200px !important; margin: 0 auto !important; }
193
+
194
+ .header { background: linear-gradient(135deg,#0a0e1a,#111827); border: 1px solid #1e293b;
195
+ border-top: 3px solid #00d4ff; border-radius: 12px; padding: 28px 36px; margin-bottom: 20px; }
196
+ .header h1 { font-family:'Syne',sans-serif; font-size:2rem; font-weight:800;
197
+ background:linear-gradient(90deg,#00d4ff,#7c3aed); -webkit-background-clip:text;
198
+ -webkit-text-fill-color:transparent; margin:0 0 6px 0; }
199
+ .header p { color:#64748b; font-family:'Space Mono',monospace; font-size:0.82rem; margin:0; }
200
+
201
+ .hint { background:rgba(0,212,255,0.04); border:1px solid rgba(0,212,255,0.15);
202
+ border-radius:8px; padding:12px 16px; font-family:'Space Mono',monospace;
203
+ font-size:0.76rem; color:#64748b; line-height:1.8; margin-top:10px; }
204
+ .hint strong { color:#00d4ff; }
205
+
206
+ textarea { background:#060a12 !important; border:1px solid #1e293b !important;
207
+ color:#94a3b8 !important; font-family:'Space Mono',monospace !important;
208
+ font-size:0.8rem !important; border-radius:8px !important; }
209
+ textarea:focus { border-color:#00d4ff !important; outline:none !important; }
210
+
211
+ button { font-family:'Syne',sans-serif !important; font-weight:700 !important; border-radius:8px !important; }
212
+ """
213
+
214
+ EXAMPLE = """1 2 3
215
+ 4 5 6
216
+ 7 8 9
217
+ 2 4 1
218
+ 5 1 8
219
+ 3 6 2
220
+ 9 3 7
221
+ 1 8 4"""
222
+
223
+ with gr.Blocks(css=css, title="PCA · 3D→2D") as demo:
224
+ gr.HTML("""
225
+ <div class="header">
226
+ <h1>&#x2B21; PCA Visualizer</h1>
227
+ <p>Principal Component Analysis &nbsp;Β·&nbsp; 3D &#8594; 2D Dimensionality Reduction</p>
228
+ </div>""")
229
+
230
+ with gr.Row():
231
+ with gr.Column(scale=1):
232
+ points_input = gr.Textbox(
233
+ label="3D Points (one per line: X Y Z)",
234
+ placeholder="1 2 3\n4 5 6\n...",
235
+ lines=12, value=EXAMPLE)
236
+
237
+ gr.HTML("""<div class="hint">
238
+ <strong>Format:</strong> X Y Z &nbsp;(space or comma)<br>
239
+ <strong>Minimum:</strong> 6 points required<br>
240
+ <strong>Example:</strong> &nbsp;1 2 3 &nbsp;or&nbsp; 1,2,3
241
+ </div>""")
242
+
243
+ with gr.Row():
244
+ run_btn = gr.Button("β–Ά Run PCA", variant="primary")
245
+ clear_btn = gr.Button("βœ• Clear", variant="secondary")
246
+
247
+ with gr.Column(scale=2):
248
+ with gr.Tabs():
249
+ with gr.Tab("πŸ“‹ Steps & Results"):
250
+ steps_out = gr.Textbox(label="Full PCA Computation",
251
+ interactive=False, lines=34)
252
+ with gr.Tab("πŸ”΅ 3D Input Plot"):
253
+ plot_3d = gr.Plot(label="Original 3D Points")
254
+ with gr.Tab("🟣 2D Projection"):
255
+ plot_2d = gr.Plot(label="PCA 2D Projection")
256
+ with gr.Tab("πŸ“Š Variance Analysis"):
257
+ plot_var = gr.Plot(label="Explained Variance")
258
+
259
+ run_btn.click(fn=run_pca, inputs=points_input,
260
+ outputs=[steps_out, plot_3d, plot_2d, plot_var])
261
+ clear_btn.click(fn=lambda: ("", None, None, None),
262
+ outputs=[points_input, plot_3d, plot_2d, plot_var])
263
+
264
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ numpy>=1.24.0
3
+ matplotlib>=3.7.0
4
+ Pillow>=10.0.0