Skip to content

Commit 8491b4c

Browse files
committed
Changes to gSheet script
1 parent e5bedc7 commit 8491b4c

File tree

2 files changed

+183
-84
lines changed

2 files changed

+183
-84
lines changed

aux_tools/google/ColumnSelector.html

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
<html>
33
<head>
44
<base target="_top">
5+
<link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap" rel="stylesheet">
6+
<style>
7+
body {
8+
font-family: 'Google Sans', sans-serif;
9+
}
10+
</style>
11+
512
<style>
613
.form-group {
714
margin: 10px 0;
@@ -14,6 +21,31 @@
1421
color: red;
1522
}
1623
</style>
24+
25+
<style>
26+
.spinner {
27+
width: 40px;
28+
height: 40px;
29+
border: 4px solid #f3f3f3;
30+
border-top: 4px solid #3498db;
31+
border-radius: 50%;
32+
animation: spin 1s linear infinite;
33+
margin: 20px auto;
34+
}
35+
36+
@keyframes spin {
37+
0% { transform: rotate(0deg); }
38+
100% { transform: rotate(360deg); }
39+
}
40+
41+
.loading-message {
42+
margin: 10px;
43+
font-style: italic;
44+
color: #666;
45+
}
46+
</style>
47+
48+
1749
</head>
1850
<body>
1951
<form onsubmit="handleSubmit(this); return false;">
@@ -37,7 +69,7 @@
3769
<? }); ?>
3870
</select>
3971
</div>
40-
72+
4173
<div class="form-group">
4274
<label>Author Column (optional)</label>
4375
<select name="authorColumn">
@@ -47,33 +79,68 @@
4779
<? }); ?>
4880
</select>
4981
</div>
82+
83+
<div class="form-group">
84+
<label>Number of Ranked Results </label>
85+
<input type="number" name="resultCount" min="1" max="500" value="10" required>
86+
</div>
5087

5188
<button type="submit">Analyze</button>
5289
</form>
53-
<!-- Add this after the form -->
90+
5491
<div id="loadingIndicator" style="display: none; text-align: center; margin-top: 20px;">
55-
<p>Analyzing ideas with SimScore...</p>
56-
<p>This may take a few moments.</p>
92+
<div class="spinner"></div>
93+
<div id="loadingMessage" class="loading-message">Initializing SimScore analysis...</div>
5794
</div>
58-
95+
5996
<script>
97+
const loadingMessages = [
98+
"Optimizing neural pathways...",
99+
"Calibrating relativity biases...",
100+
"Measuring cosine distances in vector space...",
101+
"Aligning semantic tensors...",
102+
"Computing similarity matrices...",
103+
"Discovering idea clusters...",
104+
"Calculating innovation potential...",
105+
"Synchronizing thought vectors..."
106+
];
107+
108+
function updateLoadingMessage() {
109+
const messageElement = document.getElementById('loadingMessage');
110+
let currentIndex = 0;
111+
112+
return setInterval(() => {
113+
messageElement.textContent = loadingMessages[currentIndex];
114+
currentIndex = (currentIndex + 1) % loadingMessages.length;
115+
}, 5000);
116+
}
117+
60118
function handleSubmit(form) {
61-
// Show loading indicator
62119
document.querySelector('form').style.display = 'none';
63120
document.getElementById('loadingIndicator').style.display = 'block';
64121

122+
// Start cycling through messages
123+
const messageInterval = updateLoadingMessage();
124+
65125
const data = {
66126
idColumn: form.idColumn.value,
67127
ideaColumn: form.ideaColumn.value,
68-
authorColumn: form.authorColumn.value
128+
authorColumn: form.authorColumn.value,
129+
resultCount: parseInt(form.resultCount.value) || 10
69130
};
70131

71132
google.script.run
72-
.withSuccessHandler(closeDialog)
73-
.withFailureHandler(handleError)
133+
.withSuccessHandler(() => {
134+
clearInterval(messageInterval);
135+
closeDialog();
136+
})
137+
.withFailureHandler((error) => {
138+
clearInterval(messageInterval);
139+
handleError(error);
140+
})
74141
.processSelectedColumns(data);
75142
}
76-
143+
77144
function closeDialog() {
78145
google.script.host.close();
79146
}

aux_tools/google/code.gs

Lines changed: 106 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ function getApiUrl() {
5858
}
5959

6060
function processSelectedColumns(
61-
selections = { idColumn: "ID#", ideaColumn: "ideas", authorColumn: "author" }
61+
selections = { idColumn: "ID", ideaColumn: "Challenge need", authorColumn: "Company", resultCount: 10 }
6262
) {
6363
const sheet = SpreadsheetApp.getActiveSheet();
6464
const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
@@ -116,7 +116,7 @@ function processSelectedColumns(
116116
console.log("(Slices of) Ranked Ideas: \b", response.ranked_ideas.slice(0, 5), "\n[...]\n", response.ranked_ideas.slice(-10));
117117
console.log("Has similarity matrix? : ", Boolean(response.pairwise_similarity_matrix));
118118
console.log("Has cluster names? : ", Boolean(response.cluster_names));
119-
displayResults(response);
119+
displayResults(response, selections.resultCount);
120120
}
121121
}
122122

@@ -146,9 +146,40 @@ function callSimScoreApi(requestData) {
146146
}
147147
}
148148

149-
function displayResults(response) {
149+
function displayResults(response, numRankedResults) {
150150
const ss = SpreadsheetApp.getActiveSpreadsheet();
151151

152+
// Format ranked ideas
153+
const rankedData = response.ranked_ideas.map((item, index) => {
154+
const clusterName =
155+
response.cluster_names?.find((c) => c.id === item.cluster_id)?.name || item.cluster_id;
156+
return [
157+
"# " + (index + 1),
158+
item.idea,
159+
item.author_id || "",
160+
item.similarity_score,
161+
clusterName,
162+
item.id,
163+
];
164+
});
165+
166+
console.log("Ranked Data: ", rankedData.slice(0,5), rankedData.slice(-5))
167+
168+
const rankingsSheet = createRankedSheet(ss, rankedData, numRankedResults)
169+
170+
if (response.relationship_graph) {
171+
createBubbleChart(response, rankingsSheet, rankedData, numRankedResults);
172+
}
173+
174+
if (response.pairwise_similarity_matrix) {
175+
createMatrixSheet(ss, response)
176+
}
177+
178+
ss.setActiveSheet(ss.getSheetByName("SimScore Rankings"))
179+
}
180+
181+
function createRankedSheet(ss, rankedData, numRankedResults) {
182+
152183
// Create Rankings Sheet
153184
let rankingsSheet = ss.getSheetByName("SimScore Rankings");
154185
if (rankingsSheet) {
@@ -160,44 +191,91 @@ function displayResults(response) {
160191
// Headers for rankings
161192
const headers = [
162193
"Priority",
163-
"ID",
164194
"Idea",
165195
"Author",
166196
"Similarity Score",
167197
"Cluster",
198+
"ID",
168199
];
169200
rankingsSheet.getRange(1, 1, 1, headers.length).setValues([headers]);
170201

171-
// Format ranked ideas
172-
const rankedData = response.ranked_ideas.map((item, index) => {
173-
const clusterName =
174-
response.cluster_names?.find((c) => c.id === item.cluster_id)?.name || item.cluster_id;
175-
return [
176-
"# " + (index + 1),
177-
item.id,
178-
item.idea,
179-
item.author_id || "",
180-
item.similarity_score,
181-
clusterName,
182-
];
183-
});
184-
185-
console.log("Ranked Data: ", rankedData.slice(0,5), rankedData.slice(-5))
186-
187202
if (rankedData.length > 0) {
188203
rankingsSheet
189-
.getRange(2, 1, rankedData.length, rankedData[0].length)
190-
.setValues(rankedData);
204+
.getRange(2, 1, rankedData.slice(0, numRankedResults).length, rankedData[0].length)
205+
.setValues(rankedData.slice(0, numRankedResults));
206+
207+
// Format similarity score column (column 4) to show 2 decimal places
208+
rankingsSheet
209+
.getRange(2, 4, rankedData.slice(0, numRankedResults).length, 1)
210+
.setNumberFormat("0.00");
191211
}
212+
return rankingsSheet;
213+
}
192214

215+
function createBubbleChart(response, sheet, rankedData, numRankedResults) {
216+
// Data for the chart - in required API order
217+
const chartData = [["X", "Y", "Priority", "Similarity"]];
218+
const colorMap = {};
193219

194-
if (response.relationship_graph) {
195-
createScatterPlot(response, rankingsSheet, rankedData);
196-
}
220+
const topScores = response.ranked_ideas
221+
.slice(0, numRankedResults)
222+
.map(i => i.similarity_score);
223+
const minTopScore = Math.min(...topScores);
197224

198-
// Create Matrix Sheet if available
199-
if (response.pairwise_similarity_matrix) {
200-
let matrixSheet = ss.getSheetByName("SimScore Matrix");
225+
response.relationship_graph.nodes.forEach((node, index) => {
226+
const idea = response.ranked_ideas.find((i) => i.id === node.id);
227+
const similarity = idea ? idea.similarity_score : 1.0;
228+
const isPriority = index < numRankedResults;
229+
230+
// Add data point
231+
chartData.push([
232+
node.coordinates.x,
233+
node.coordinates.y,
234+
node.id.toString(),
235+
similarity,
236+
]);
237+
238+
const t = isPriority // don't use similarity for the top results
239+
? 1 - ((index+1) / numRankedResults) * (1-minTopScore-0.1) // This keeps t between 1.0 and 0.1 higher than minTopScore for priority items
240+
: similarity;
241+
242+
let color = "#" +
243+
Math.round(251 - (isPriority ? 251 : 185) * t).toString(16).padStart(2, "0") +
244+
Math.round(188 - (isPriority ? 188 : 55) * t).toString(16).padStart(2, "0") +
245+
Math.round(4 + (isPriority ? 250 : 240) * t).toString(16).padStart(2, "0");
246+
247+
colorMap[index] = { color };
248+
});
249+
250+
const chartRange = sheet.getRange(1, rankedData[0].length + 2, chartData.length, chartData[0].length);
251+
chartRange.setValues(chartData);
252+
sheet.hideColumns(chartRange.getColumn(), chartRange.getNumColumns());
253+
254+
const chart = sheet
255+
.newChart()
256+
.setChartType(Charts.ChartType.BUBBLE)
257+
.addRange(chartRange)
258+
.setOption("title", "Similarity to the most similar point")
259+
.setOption("subtitle", `(Top ${numRankedResults} colors enhanced)`)
260+
.setOption("height", 600)
261+
.setOption("width", 800)
262+
.setOption("series", colorMap)
263+
.setOption("tooltip", {
264+
trigger: "focus",
265+
textStyle: { fontSize: 12 },
266+
showColorCode: false,
267+
ignoreBounds: false
268+
})
269+
// Hide other columns from tooltip
270+
.setOption("hAxis", { textPosition: "none" })
271+
.setOption("vAxis", { textPosition: "none" })
272+
.setPosition(3, chartRange.getColumn() + chartRange.getNumColumns() + 1, 0, 0)
273+
.build();
274+
sheet.insertChart(chart);
275+
}
276+
277+
function createMatrixSheet(ss, response) {
278+
let matrixSheet = ss.getSheetByName("SimScore Matrix");
201279
if (matrixSheet) {
202280
matrixSheet.clear();
203281
} else {
@@ -241,50 +319,4 @@ function displayResults(response) {
241319
.build();
242320

243321
matrixSheet.setConditionalFormatRules([rule]);
244-
}
245-
}
246-
247-
function createScatterPlot(response, sheet, rankedData) {
248-
// Data for the chart - in required API order
249-
const chartData = [["X", "Y", "ID", "Similarity"]];
250-
const colorMap = {};
251-
response.relationship_graph.nodes.forEach((node, index) => {
252-
const idea = response.ranked_ideas.find((i) => i.id === node.id);
253-
const similarity = idea ? idea.similarity_score : 1.0;
254-
255-
// Add data point
256-
chartData.push([
257-
node.coordinates.x,
258-
node.coordinates.y,
259-
node.id.toString(),
260-
similarity,
261-
]);
262-
263-
// Calculate color using index instead of ID
264-
const t = similarity;
265-
let color = "#" +
266-
Math.round(251 - 185 * t).toString(16).padStart(2, "0") +
267-
Math.round(188 - 55 * t).toString(16).padStart(2, "0") +
268-
Math.round(4 + 240 * t).toString(16).padStart(2, "0")
269-
270-
colorMap[index] = { color };
271-
});
272-
273-
console.log(colorMap.slice(0, 5), colorMap.slice(-5));
274-
275-
const chartRange = sheet.getRange(1, rankedData[0].length, chartData.length, chartData[0].length);
276-
chartRange.setValues(chartData);
277-
sheet.hideColumns(chartRange.getColumn(), chartRange.getNumColumns());
278-
279-
const chart = sheet
280-
.newChart()
281-
.setChartType(Charts.ChartType.BUBBLE)
282-
.addRange(chartRange)
283-
.setOption("title", "Similarity to the most similar point")
284-
.setOption("height", 600)
285-
.setOption("width", 800)
286-
.setOption("series", colorMap)
287-
.setPosition(3, chartRange.getColumn() + chartRange.getNumColumns() + 1, 0, 0)
288-
.build();
289-
sheet.insertChart(chart);
290322
}

0 commit comments

Comments
 (0)