play icon for videos
← Academy
SOPACT ACADEMY · GRANT INTELLIGENCE · ANALYZE

Theme a Whole Round Before Scoring

Theme a whole grant round before you score a single application — cluster the proposed work by theme, population, and geography, with counts, quotes, and the priority gaps surfaced.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> @keyframes pulseDot{0%,100%{opacity:1}50%{opacity:.35}} *{box-sizing:border-box} body{margin:0;font-family:'Hanken Grotesk',-apple-system,BlinkMacSystemFont,sans-serif;background:#EEF2F9;padding:26px;display:flex;justify-content:center} .card{width:600px;max-width:100%;background:#FFFFFF;border:1px solid #E3E9F4;border-radius:20px;box-shadow:0 26px 64px -32px rgba(15,30,70,.34),0 2px 4px rgba(15,30,70,.05);overflow:hidden} .hdr{display:flex;align-items:center;gap:11px;padding:16px 20px;border-bottom:1px solid #EEF1F7;background:#F5F8FE} .hdr .ic{display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;border:2px solid #155DFC;border-radius:50%;color:#155DFC;font-size:15px;font-weight:800;flex-shrink:0} .hdr .t{min-width:0} .hdr .t .n{font-weight:800;font-size:14.5px;color:#0F172A;letter-spacing:-.2px} .hdr .t .s{font-size:12px;color:#64748B} .hdr .pill{margin-left:auto;display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:700;color:#155DFC;background:#E6EEFF;padding:5px 10px;border-radius:20px;white-space:nowrap} .hdr .pill .d{width:6px;height:6px;border-radius:50%;background:#155DFC;animation:pulseDot 2s infinite} .tabs{display:flex;gap:0;padding:12px 16px 0;background:#F5F8FE} .tab{flex:1;display:flex;flex-direction:column;align-items:center;gap:5px;cursor:pointer;font-family:inherit;font-size:11.5px;font-weight:700;color:#64748B;background:transparent;border:none;border-bottom:2px solid transparent;padding:8px 4px 10px} .tab.on{font-weight:800;color:#155DFC;border-bottom-color:#155DFC} .tab .num{display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;border-radius:50%;font-size:11px;font-weight:800;color:#64748B;background:#EEF1F7} .tab.on .num{color:#fff;background:#155DFC} .divider{height:1px;background:#EEF1F7} .body{padding:20px} .eyebrow{font-size:10.5px;font-weight:800;letter-spacing:1.2px;text-transform:uppercase;color:#155DFC;margin-bottom:5px} .eyebrow.g{color:#15884F} .headline{font-family:'Inter',Georgia,serif;font-size:18.5px;font-weight:600;line-height:1.25;color:#0F172A;margin-bottom:12px} .lede{font-size:12.5px;line-height:1.55;color:#475569;margin:0 0 14px} .rows{display:flex;flex-direction:column;gap:8px;margin-bottom:14px} .row{display:flex;align-items:center;gap:11px;background:#F5F8FE;border:1px solid #EEF1F7;border-radius:11px;padding:11px 13px} .row .emoji{font-size:17px} .row .rt{flex:1;min-width:0} .row .rt .n{font-size:13px;font-weight:700;color:#0F172A} .row .rt .s{font-size:12px;color:#64748B} .pillsm{font-size:11px;font-weight:800;color:#155DFC;background:#E6EEFF;padding:4px 9px;border-radius:6px;flex-shrink:0} .pillsm.gray{font-weight:700;color:#64748B;background:#EEF1F7} .chainwrap{position:relative;padding-left:26px} .chainline{position:absolute;left:8px;top:8px;bottom:8px;width:2px;background:#E3E9F4} .cnode{position:relative;margin-bottom:14px} .cdot{position:absolute;left:-26px;top:4px;width:16px;height:16px;border-radius:50%;background:#fff;border:3px solid #94A3B8} .clabel{font-size:9.5px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#64748B;margin-bottom:4px} .cbox{background:#F5F8FE;border:1px solid #EEF1F7;border-radius:11px;padding:10px 12px;font-size:12px;line-height:1.5;color:#334155} .cbox.graded{display:flex;align-items:flex-start;gap:9px;border-left-width:3px;border-left-style:solid} .cnote{margin:0 0 14px 4px;font-size:11px;line-height:1.5} .cnote .plus{display:inline-flex;width:16px;height:16px;align-items:center;justify-content:center;background:#155DFC;color:#fff;border-radius:4px;font-size:10px;font-weight:800;flex-shrink:0;margin-right:6px} .csummary{display:flex;align-items:center;gap:12px;background:#0A1B3D;border-radius:13px;padding:11px 15px;margin-top:4px} .csummary .t{flex:1;font-size:11.5px;color:#CBD8F5} .csummary .t b{color:#F1F5FF} .mxwrap{border:1px solid #EEF1F7;border-radius:12px;overflow:hidden;margin-bottom:10px} .mxhead{display:grid;grid-template-columns:118px 1fr 1fr;background:#F5F8FE;border-bottom:1px solid #EEF1F7} .mxhead div{font-size:9px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#64748B;padding:7px 9px} .mxrow{display:grid;grid-template-columns:118px 1fr 1fr;border-bottom:1px solid #EEF1F7} .mxrow:last-child{border-bottom:none} .mxrow>div{padding:9px;font-size:11.5px;line-height:1.4;color:#334155;display:flex;align-items:center;flex-wrap:wrap;gap:5px} .mxrow .mxlabel{font-weight:700;color:#0F172A;background:#FAFBFE} .mxchip{font-size:9px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;padding:3px 6px;border-radius:5px;white-space:nowrap} .promptwrap{padding:0 20px 18px} .promptlbl{font-size:10px;font-weight:800;letter-spacing:1px;text-transform:uppercase;color:#94A3B8;margin-bottom:7px} .prompt{display:flex;align-items:flex-start;gap:9px;font-family:ui-monospace,'SF Mono',Menlo,monospace;font-size:11px;line-height:1.5;color:#1E293B;background:#F5F8FE;border:1px solid #EEF1F7;border-left:3px solid #155DFC;border-radius:9px;padding:11px 12px} .prompt .car{color:#155DFC;font-weight:800;flex-shrink:0} .flagrow{display:flex;align-items:flex-start;gap:10px;background:#F5F8FE;border:1px solid #EEF1F7;border-radius:11px;padding:10px 12px;border-left-width:3px;border-left-style:solid;margin-bottom:8px} .flagtag{font-size:9.5px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;padding:4px 8px;border-radius:5px;white-space:nowrap;flex-shrink:0} .flagtxt{font-size:12px;line-height:1.45;color:#334155} .lp{display:flex;align-items:center;gap:12px;background:#0A1B3D;border-radius:13px;padding:14px 16px;margin-top:6px} .lp .ic{display:inline-flex;width:34px;height:34px;align-items:center;justify-content:center;background:#14295C;border:1px solid #26407A;border-radius:9px;color:#7FA8FF;font-size:16px;flex-shrink:0} .lp .rt{flex:1;min-width:0} .lp .rt .n{font-size:13px;font-weight:800;color:#F1F5FF} .lp .rt .s{font-size:11.5px;color:#9DB2D9} .lp .open{font-size:11px;font-weight:800;color:#0A1B3D;background:#7FA8FF;padding:6px 11px;border-radius:7px;white-space:nowrap} </style> </head> <body> <div class="card"> <div class="hdr"> <span class="ic">&#128172;</span> <div class="t"> <div class="n">Grant Round · Barrier Themes</div> <div class="s">DEMO-04 · Open-Text Barriers · Sopact Sense</div> </div> <span class="pill"><span class="d"></span>Theming</span> </div> <div class="tabs" id="tabs"></div> <div class="divider"></div> <div class="body" id="body"></div> <div class="promptwrap"> <div class="promptlbl">The prompt behind this step</div> <div class="prompt"><span class="car">&gt;</span><span id="promptTxt"></span></div> </div> </div> <script> (function(){ var TABS = ["Setup", "Theme", "Fix", "Report"]; var CONTENT = [{"eyebrow": "Step 1 · Load the round", "headline": "The input is the raw comments, nothing else", "lede": "Point the Assistant at the real record — nothing inferred, nothing invented.", "prompt": "You are the Sopact Sense Assistant. Here are this round’s open-text barrier responses: [PASTE RESPONSES]. Use only what they state; mark anything you infer as [INFERRED]. Wait for my task."}, {"eyebrow": "Step 2 · Theme & reconcile", "headline": "Four themes, counts reconciled to N", "lede": "Every theme is counted and graded — <strong style=\"color:#15884F\">green</strong>, <strong style=\"color:#C9820A\">amber</strong>, <strong style=\"color:#C63E2B\">red</strong>.", "prompt": "Theme this round and reconcile the counts to N."}, {"eyebrow": "Step 3 · Handle the thin theme", "headline": "One rule keeps a single mention honest", "lede": "Take the lowest-graded item and resolve it with the one thing that's realistically obtainable.", "prompt": "Take the thinnest theme above and resolve it using only what’s realistically available. Show the before → after status and the one rule that clears it."}, {"eyebrow": "Step 4 · Missing & incomplete report", "headline": "Which themes need another round to confirm", "lede": "Every amber or red item becomes one named ask — the report leads with the decision it informs.", "prompt": "Create a 'missing & incomplete' report from this analysis in Sopact branding. List every element graded amber or red, what is missing, and the one input that would fix each. Lead with the decision this report informs."}]; var BODIES = { setup: "<div class=\"row\"><span class=\"emoji\">&#128172;</span><div class=\"rt\"><div class=\"n\">Open-text responses</div><div class=\"s\">18 applicant comments, DEMO-04</div></div><span class=\"pillsm\">Loaded</span></div><div class=\"row\"><span class=\"emoji\">&#128203;</span><div class=\"rt\"><div class=\"n\">Theme buckets</div><div class=\"s\">Transport · Childcare · Other · Language</div></div><span class=\"pillsm gray\">Coded</span></div><div class=\"row\"><span class=\"emoji\">&#128274;</span><div class=\"rt\"><div class=\"n\">Reconcile-to-N rule</div><div class=\"s\">Every count must sum back to N</div></div><span class=\"pillsm gray\">Required</span></div>", build: "<div class=\"mxwrap\"><div class=\"mxhead\"><div></div><div>Count</div><div>Representative quote</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Transport</div><div>5<span class=\"mxchip\" style=\"background:#15884F;color:#fff\">GREEN</span></div><div>“the bus doesn’t run early”</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Childcare</div><div>4<span class=\"mxchip\" style=\"background:#15884F;color:#fff\">GREEN</span></div><div>“no childcare during sessions”</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Other / unclear</div><div>1<span class=\"mxchip\" style=\"background:#C9820A;color:#fff\">AMBER</span></div><div>“a few things at once”</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Language</div><div>1<span class=\"mxchip\" style=\"background:#C63E2B;color:#fff\">RED</span></div><div>“hard to follow in English” — hold</div></div></div>", fix: "<div class=\"mxwrap\"><div class=\"mxhead\"><div></div><div>Count</div><div>Representative quote</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Transport</div><div>5<span class=\"mxchip\" style=\"background:#15884F;color:#fff\">GREEN</span></div><div>“the bus doesn’t run early”</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Childcare</div><div>4<span class=\"mxchip\" style=\"background:#15884F;color:#fff\">GREEN</span></div><div>“no childcare during sessions”</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Other / unclear</div><div>1<span class=\"mxchip\" style=\"background:#C9820A;color:#fff\">AMBER</span></div><div>“a few things at once”</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Language</div><div>1 · held<span class=\"mxchip\" style=\"background:#15884F;color:#fff\">GREEN</span></div><div>“hard to follow in English” — hold</div></div></div><div class=\"cnote\" style=\"color:#15884F;margin-left:0\"><span class=\"plus\">+</span><strong>Fix applied:</strong> Watch next round; track but don’t theme on n=1.</div>", reportFlags: "<div class=\"flagrow\" style=\"border-left-color:#C9820A\"><span class=\"flagtag\" style=\"color:#C9820A;background:#FBF0DA\">AMBER</span><div class=\"flagtxt\">Other / unclear — a single vague mention. Needs re-reading next round before it earns its own theme.</div></div><div class=\"flagrow\" style=\"border-left-color:#C63E2B\"><span class=\"flagtag\" style=\"color:#C63E2B;background:#FCE9E7\">RED</span><div class=\"flagtxt\">Language — one mention only. Held rather than themed until it recurs.</div></div>", lpTitle: "Missing & incomplete report · shareable link", lpSub: "Decision-first · Sopact branding · Grant Round · Barrier Themes", summaryBefore: "Grade: 2 green &middot; 1 amber &middot; 1 red. Single mention = hold.", summaryAfter: "Grade: 3 green &middot; 1 amber &middot; 0 red. Held, not inflated." }; var phase = 1; var tabsEl = document.getElementById('tabs'); var bodyEl = document.getElementById('body'); var promptEl = document.getElementById('promptTxt'); function renderTabs(){ tabsEl.innerHTML = ''; TABS.forEach(function(label, i){ var b = document.createElement('button'); b.type = 'button'; b.className = 'tab' + (i === phase ? ' on' : ''); b.innerHTML = '<span class="num">' + (i+1) + '</span><span>' + label + '</span>'; b.addEventListener('click', function(){ phase = i; render(); }); tabsEl.appendChild(b); }); } function renderBody(){ var c = CONTENT[phase]; var eyebrowClass = (phase===2) ? 'eyebrow g' : 'eyebrow'; var out = '<div class="' + eyebrowClass + '">' + c.eyebrow + '</div><div class="headline">' + c.headline + '</div><p class="lede">' + c.lede + '</p>'; if (phase === 0) { out += '<div class="rows">' + BODIES.setup + '</div>'; } else if (phase === 1) { out += BODIES.build; out += '<div class="csummary"><div class="t"><b>' + BODIES.summaryBefore + '</b></div></div>'; } else if (phase === 2) { out += BODIES.fix; out += '<div class="csummary"><div class="t"><b>' + BODIES.summaryAfter + '</b></div></div>'; } else { out += BODIES.reportFlags; out += '<div class="lp"><span class="ic">&#128196;</span><div class="rt"><div class="n">' + BODIES.lpTitle + '</div><div class="s">' + BODIES.lpSub + '</div></div><span class="open">Open &rarr;</span></div>'; } bodyEl.innerHTML = out; promptEl.textContent = c.prompt; } function render(){ renderTabs(); renderBody(); } render(); })(); </script> </body> </html>

In short: To analyze a batch of grant applications, theme the whole round before you score any single proposal: cluster the proposed work by theme, population, and geography, count how often each appears, quote real applicant language, and surface the priority gaps. Hold single mentions aside rather than promoting them to themes. Sopact Sense grades the clusters green, amber, or red so you can see what the round is actually asking for — and fund accordingly.

1 · Set up over your data

Start with the round's open-text responses loaded as clean data with persistent contact IDs, so every theme ties back to real applicant language. Point the assistant at the dataset and have it read your Decision Brief first — the decision, audience, outcomes, indicators, and evidence standard.

You are the Sopact Sense Assistant working over the DEMO-04 · Open-Text Barriers dataset (clean data + persistent contact IDs). Load my Decision Brief (decision, audience, outcomes, indicators, evidence standard) first, then wait for my task.

2 · Write the theming prompt

The prompt names the dimensions and demands evidence per cluster. Paste this verbatim:

Across round [ROUND], cluster proposed work by theme, population, geography; count + quote; surface priority gaps. Hold single mentions. Grade green/amber/red.

The prompt works because of five elements: the dataset it clusters over, the instruction to cluster the round by theme/population/geography, the demand to surface priority gaps, the discipline to hold single mentions rather than over-theme, and the call to grade green/amber/red so weak clusters are visible.

3 · What Sense produces

Run it against the workforce barriers demo:

Run on the Open-Text Barriers dataset (DEMO-04) already loaded in Sopact Sense.

GRADE: green | transport/childcare | recurring; amber | other | ambiguous; red | language | single mention

The green cluster is recurring transport and childcare needs — named often enough to act on. The amber cluster is an ambiguous 'other' bucket mixing several meanings. The red item is a single-mention language barrier — real, but not yet a pattern, so it's held as a watch-item.

4 · Turn a weak link green

Take the weakest cluster and fix it with the one input that resolves it. Sense shows the before → after grade.

Take the lowest-graded element above and fix it using only what the program could realistically measure. Show the before → after grade and the single indicator/edit that moves it to green.

5 · Make the report and share it

Turn the theming into a report, then a link that opens with no login.

Create a 'missing & incomplete' report from this analysis in Sopact branding [or paste your website URL / brand guideline to apply your own]. List every element graded amber or red, what is missing, and the one input that fixes each. Lead with the decision this report informs.
Create a shareable link for this report and open it in a new tab.

Tricks, tips, and troubleshooting

Theme before you score. Clustering the whole round first changes how you fund — you see which needs are widespread before any one polished proposal pulls your attention.

Hold single mentions. One applicant raising a barrier is a signal to watch, not a theme to act on. Keep single mentions in a separate list so they neither vanish nor distort the priorities.

Split the 'other' bucket. A catch-all category hides distinct needs. When 'other' grows ambiguous, ask the model to break it into named sub-themes or add a follow-up field.

Always keep the quote. Counts tell you how often; quotes tell you what people actually meant. Require a representative quote per cluster so reviewers can sanity-check the theme.

Split the 'other' cluster into named sub-themes with a count and a representative quote for each, and re-grade them.

Frequently asked questions

How do you analyze a batch of grant applications?

Cluster the whole round at once — group proposed work by theme, population, and geography, count how often each appears, and pull a representative quote per cluster. Surface the priority gaps and hold single mentions aside so you understand what the round is collectively asking for before you score individual proposals.

What is thematic analysis of grant applications?

Thematic analysis groups open-text responses into recurring patterns — themes — backed by counts and quotes. For a grant round it reveals which needs are widespread versus one-off, so funding decisions reflect the population's actual priorities rather than the most persuasive single application.

What makes a theme weak?

A theme is weak when it's a single mention dressed up as a pattern, or an ambiguous 'other' bucket that blends distinct meanings. The fix is to hold single mentions as watch-items and split catch-all buckets into named sub-themes, each with its own count and quote.

Ready to try it for yourself?

Open Sopact Sense, paste your program description, and put it to work.

Try in Sopact