prakharg24 commited on
Commit
aa2d80c
·
verified ·
1 Parent(s): 84d3b95

Update my_pages/ica.py

Browse files
Files changed (1) hide show
  1. my_pages/ica.py +138 -44
my_pages/ica.py CHANGED
@@ -1,62 +1,156 @@
1
- # pages/ica.py
2
- import streamlit as st
3
- import matplotlib.pyplot as plt
4
  import numpy as np
 
 
 
5
 
6
  def render():
7
- st.title("Intentional - Conventional - Arbitrary Triangle")
8
 
9
- # Vertices of the triangle
10
- vertices = {
11
- "Intentional": (0.0, 0.0),
 
 
12
  "Conventional": (1.0, 0.0),
13
- "Arbitrary": (0.5, np.sqrt(3)/2)
14
  }
15
 
16
- # Explanations
17
- explanations = {
18
- "Intentional": "An intentional choice is deliberate and goal-oriented.",
19
- "Conventional": "A conventional choice follows established norms.",
20
- "Arbitrary": "Random seeds a purely arbitrary choice."
 
 
 
 
 
 
 
 
 
21
  }
22
 
23
- if "clicked_vertex" not in st.session_state:
24
- st.session_state.clicked_vertex = None
 
 
 
25
 
26
- # Function to handle clicks
27
- def onclick(event):
28
- if event.xdata is None or event.ydata is None:
29
- return # Clicked outside plot
 
30
 
31
- click_point = np.array([event.xdata, event.ydata])
32
- closest_vertex = min(
33
- vertices.keys(),
34
- key=lambda v: np.linalg.norm(click_point - np.array(vertices[v]))
35
- )
36
- st.session_state.clicked_vertex = closest_vertex
37
- st.experimental_rerun()
38
 
39
- # Draw triangle
40
- fig, ax = plt.subplots()
41
- triangle_coords = np.array(list(vertices.values()) + [vertices["Intentional"]])
42
- ax.plot(triangle_coords[:, 0], triangle_coords[:, 1], 'k-', lw=2)
 
 
 
 
43
 
44
- # Label vertices
45
- for label, (x, y) in vertices.items():
46
- ax.text(x, y + 0.05, label, ha='center', fontsize=12, fontweight='bold')
47
- ax.plot(x, y, 'o', markersize=10)
48
 
49
- ax.set_aspect('equal')
50
- ax.axis('off')
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
- # Connect click event
53
- cid = fig.canvas.mpl_connect("button_press_event", onclick)
54
 
55
- st.pyplot(fig)
 
 
 
 
 
56
 
57
- # Show explanation if a vertex was clicked
58
- if st.session_state.clicked_vertex:
59
- st.markdown(
60
- f"### You clicked near **{st.session_state.clicked_vertex}**\n"
61
- f"{explanations[st.session_state.clicked_vertex]}"
 
 
 
 
 
 
 
 
 
 
62
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import numpy as np
2
+ import plotly.graph_objects as go
3
+ from streamlit_plotly_events import plotly_events
4
+ import streamlit as st
5
 
6
  def render():
7
+ st.title("ICA Triangle (Intentional · Conventional · Arbitrary)")
8
 
9
+ # --------------------------
10
+ # Geometry: equilateral triangle in 2D
11
+ # --------------------------
12
+ V = {
13
+ "Intentional": (0.0, 0.0),
14
  "Conventional": (1.0, 0.0),
15
+ "Arbitrary": (0.5, np.sqrt(3) / 2),
16
  }
17
 
18
+ # Explanations for each corner
19
+ corner_examples = {
20
+ "Arbitrary": (
21
+ "Arbitrary",
22
+ "Examples: random seeds, shuffling order, tie-breaking by index, default RNG states."
23
+ ),
24
+ "Conventional": (
25
+ "Conventional",
26
+ "Examples: using default hyperparams because 'that’s what everyone does', standard scalers, popular benchmarks."
27
+ ),
28
+ "Intentional": (
29
+ "Intentional",
30
+ "Examples: constraint-aware objectives, domain rules, fairness constraints, targeted regularization."
31
+ ),
32
  }
33
 
34
+ # Keep selected point in session
35
+ if "ica_click" not in st.session_state:
36
+ st.session_state.ica_click = None
37
+ if "ica_nearest" not in st.session_state:
38
+ st.session_state.ica_nearest = None
39
 
40
+ # --------------------------
41
+ # Build base figure
42
+ # --------------------------
43
+ def base_figure(selected=None):
44
+ fig = go.Figure()
45
 
46
+ # Triangle outline
47
+ tri_x = [V["Intentional"][0], V["Conventional"][0], V["Arbitrary"][0], V["Intentional"][0]]
48
+ tri_y = [V["Intentional"][1], V["Conventional"][1], V["Arbitrary"][1], V["Intentional"][1]]
49
+ fig.add_trace(go.Scatter(
50
+ x=tri_x, y=tri_y, mode="lines",
51
+ line=dict(color="black", width=2), hoverinfo="skip", showlegend=False
52
+ ))
53
 
54
+ # Vertex markers + labels
55
+ for name, (x, y) in V.items():
56
+ fig.add_trace(go.Scatter(
57
+ x=[x], y=[y], mode="markers+text",
58
+ marker=dict(size=10, color="black"),
59
+ text=[name], textposition="top center",
60
+ hoverinfo="skip", showlegend=False
61
+ ))
62
 
63
+ # A dense transparent clickable grid within triangle
64
+ grid = np.linspace(0.0, 1.0, 41)
65
+ gx, gy = np.meshgrid(grid, grid)
66
+ pts = np.vstack([gx.ravel(), gy.ravel()]).T # (N,2)
67
 
68
+ def inside_triangle(p):
69
+ # Barycentric method for triangle ABC
70
+ A = np.array(V["Intentional"])
71
+ B = np.array(V["Conventional"])
72
+ C = np.array(V["Arbitrary"])
73
+ v0 = C - A
74
+ v1 = B - A
75
+ v2 = p - A
76
+ den = v0[0]*v1[1] - v1[0]*v0[1]
77
+ if abs(den) < 1e-9:
78
+ return False
79
+ a = (v2[0]*v1[1] - v1[0]*v2[1]) / den
80
+ b = (v0[0]*v2[1] - v2[0]*v0[1]) / den
81
+ c = 1 - a - b
82
+ return (a >= 0) and (b >= 0) and (c >= 0)
83
 
84
+ in_tri = np.array([inside_triangle(p) for p in pts])
85
+ tri_pts = pts[in_tri]
86
 
87
+ # Invisible markers to capture click events anywhere inside the triangle
88
+ fig.add_trace(go.Scatter(
89
+ x=tri_pts[:, 0], y=tri_pts[:, 1], mode="markers",
90
+ marker=dict(size=24, opacity=0.0), # invisible, but clickable
91
+ hoverinfo="skip", showlegend=False, name="click-capture"
92
+ ))
93
 
94
+ # Highlight the selected point (if any)
95
+ if selected is not None:
96
+ fig.add_trace(go.Scatter(
97
+ x=[selected[0]], y=[selected[1]], mode="markers",
98
+ marker=dict(size=16, color="#1f77b4", line=dict(width=2, color="black")),
99
+ hoverinfo="skip", showlegend=False, name="selected"
100
+ ))
101
+
102
+ fig.update_layout(
103
+ margin=dict(l=10, r=10, t=20, b=10),
104
+ xaxis=dict(visible=False, range=[-0.05, 1.05], scaleanchor="y", scaleratio=1),
105
+ yaxis=dict(visible=False, range=[-0.05, 0.95]),
106
+ clickmode="event+select",
107
+ dragmode=False,
108
+ height=420,
109
  )
110
+ return fig
111
+
112
+ fig = base_figure(selected=st.session_state.ica_click)
113
+
114
+ # Render and capture click
115
+ events = plotly_events(
116
+ fig,
117
+ click_event=True,
118
+ hover_event=False,
119
+ select_event=False,
120
+ override_height=420,
121
+ override_width="100%",
122
+ key="ica_triangle"
123
+ )
124
+
125
+ # Process click
126
+ if events:
127
+ # The click snaps to the nearest invisible grid point:
128
+ x = float(events[0]["x"])
129
+ y = float(events[0]["y"])
130
+ st.session_state.ica_click = (x, y)
131
+
132
+ # Determine nearest vertex
133
+ def dist(p, q):
134
+ return np.linalg.norm(np.array(p) - np.array(q))
135
+ nearest = min(V.keys(), key=lambda k: dist((x, y), V[k]))
136
+ st.session_state.ica_nearest = nearest
137
+
138
+ # --------------------------
139
+ # Output text based on nearest vertex
140
+ # --------------------------
141
+ st.markdown("---")
142
+ if st.session_state.ica_nearest:
143
+ title, details = corner_examples[st.session_state.ica_nearest]
144
+ st.subheader(f"Closest to: {title}")
145
+ # If it's very close, emphasize "pure" examples
146
+ # (distance threshold ~ 0.12 in this normalized triangle space)
147
+ d = np.linalg.norm(np.array(st.session_state.ica_click) - np.array(V[st.session_state.ica_nearest]))
148
+ if st.session_state.ica_nearest == "Arbitrary" and d < 0.12:
149
+ st.write("**Example spotlight:** Random seeds (purely arbitrary choice).")
150
+ elif st.session_state.ica_nearest == "Conventional" and d < 0.12:
151
+ st.write("**Example spotlight:** Using library defaults just because it's common.")
152
+ elif st.session_state.ica_nearest == "Intentional" and d < 0.12:
153
+ st.write("**Example spotlight:** Encoding a fairness/robustness constraint explicitly.")
154
+ st.write(details)
155
+ else:
156
+ st.info("Click anywhere inside the triangle to indicate where your decision sits on the ICA spectrum.")