prakharg24 commited on
Commit
9a4bcc6
·
verified ·
1 Parent(s): aa2d80c

Update my_pages/ica.py

Browse files
Files changed (1) hide show
  1. my_pages/ica.py +63 -151
my_pages/ica.py CHANGED
@@ -1,156 +1,68 @@
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.")
 
 
 
 
1
  import streamlit as st
2
+ import matplotlib.pyplot as plt
3
+ import numpy as np
4
 
5
  def render():
6
+ st.title("ICA Triangle")
7
+
8
+ st.write("Adjust the sliders to change the position of the decision in the triangle.")
9
+
10
+ # Initialize values in session_state so they persist
11
+ if "intentional" not in st.session_state:
12
+ st.session_state.intentional = 0.33
13
+ st.session_state.conventional = 0.33
14
+ st.session_state.arbitrary = 0.34
15
+
16
+ # Sliders (manually enforce sum to 1)
17
+ intentional = st.slider("Intentional", 0.0, 1.0, st.session_state.intentional, 0.01)
18
+ remaining_for_two = 1.0 - intentional
19
+ conventional = st.slider("Conventional", 0.0, remaining_for_two, st.session_state.conventional, 0.01)
20
+ arbitrary = 1.0 - intentional - conventional
21
+
22
+ # Save back to session_state
23
+ st.session_state.intentional = intentional
24
+ st.session_state.conventional = conventional
25
+ st.session_state.arbitrary = arbitrary
26
+
27
+ st.write(f"**Arbitrary:** {arbitrary:.2f}")
28
+
29
+ # Triangle vertices (equilateral)
30
+ vertices = np.array([
31
+ [0.5, np.sqrt(3)/2], # Intentional
32
+ [0, 0], # Conventional
33
+ [1, 0] # Arbitrary
34
+ ])
35
+
36
+ # Compute point location from barycentric coordinates
37
+ point = (
38
+ intentional * vertices[0] +
39
+ conventional * vertices[1] +
40
+ arbitrary * vertices[2]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  )
42
 
43
+ # Plot
44
+ fig, ax = plt.subplots()
45
+ ax.plot(*np.append(vertices, [vertices[0]], axis=0).T, 'k-') # Triangle outline
46
+ ax.scatter(vertices[:,0], vertices[:,1], c=["blue", "green", "red"], s=100)
47
+ ax.text(*vertices[0], "Intentional", ha="center", va="bottom")
48
+ ax.text(*vertices[1], "Conventional", ha="right", va="top")
49
+ ax.text(*vertices[2], "Arbitrary", ha="left", va="top")
50
+
51
+ ax.scatter(point[0], point[1], c="orange", s=200, zorder=5)
52
+ ax.set_aspect("equal")
53
+ ax.axis("off")
54
+
55
+ st.pyplot(fig)
56
+
57
+ # Show explanation text based on closeness
58
+ closest = max(
59
+ [("Intentional", intentional), ("Conventional", conventional), ("Arbitrary", arbitrary)],
60
+ key=lambda x: x[1]
61
+ )[0]
62
+
63
+ if closest == "Arbitrary":
64
+ st.info("Example: Random seeds a truly arbitrary decision.")
65
+ elif closest == "Intentional":
66
+ st.info("Example: Ethical constraints a fully intentional choice.")
67
+ elif closest == "Conventional":
68
+ st.info("Example: Industry standard preprocessing a conventional decision.")